@lionchat/mcp-server 1.19.2 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,9 +19,11 @@ Comprovado em produção (24/07): a sessão que dizia "não há função de list
19
19
  kanban_items, funnels, flows, flow_tools, campaigns, macros, automation_rules, agents, teams,
20
20
  inboxes, labels, canned_responses, reports, sla, csat, captain_assistants, captain_documents,
21
21
  scheduled_messages, custom_attributes, webhooks, eclinica_integrations, tasks, notifications,
22
- lead_forms (Formulários públicos de captação).
23
- - **Fora do MCP por decisão do dono (19/08): assinatura, plano, fatura, forma de pagamento, cartão,
24
- saldo e recarga.** Não existem ferramentas dessas áreas e não devem ser criadas. Se o usuário
22
+ lead_forms (Formulários públicos de captação), signature_documents / signature_envelopes
23
+ (assinatura ELETRÔNICA de contratos — modelos e contratos enviados).
24
+ - **Fora do MCP por decisão do dono (19/08): assinatura DO PLANO (cobrança), plano, fatura, forma de
25
+ pagamento, cartão, saldo e recarga.** (A assinatura ELETRÔNICA de contratos é outra coisa e TEM
26
+ ferramentas: `lionchat_signature_*`.) Não existem ferramentas dessas áreas e não devem ser criadas. Se o usuário
25
27
  pedir, diga que isso se resolve no painel, na área de assinatura da conta — não tente por
26
28
  ferramenta nem por chamada direta.
27
29
  - Só depois de pesquisar e não encontrar é que se pode dizer que a função não existe.
@@ -223,6 +225,17 @@ lionchat_conversations_messages_list (conversation_id: 123)
223
225
  3. lionchat_inboxes_public_conversations_create (vincula contato à inbox)
224
226
  ```
225
227
 
228
+ **Telefone com ou sem o nono dígito (desde 05/09/2026):** a busca do passo 1 acha o contato
229
+ mesmo que ele esteja salvo na OUTRA forma do celular brasileiro (com o 9 quando você busca sem, e
230
+ vice-versa). Não precisa buscar duas vezes. Se mesmo assim `lionchat_contacts_create` devolver 422
231
+ com `attributes: ["phone_number"]`, o contato já existe — busque de novo e ATUALIZE em vez de criar.
232
+ Nunca tente "resolver" trocando a forma do número no create: a criação recusa as duas formas de
233
+ propósito (a recusa protege contra ficha em dobro).
234
+ **Atenção:** como a busca e o `contacts_filter` agora enxergam as duas formas, uma pessoa que tenha
235
+ ficha duplicada pode voltar como **2 resultados**. Nunca pegue o primeiro às cegas para
236
+ `contacts_update` — confira nome/e-mail ou pergunte ao usuário qual é a ficha certa. A lupa geral
237
+ (`lionchat_search_list`) NÃO tem essa tolerância: para telefone, use `lionchat_contacts_search`.
238
+
226
239
  ### Criar funil (kanban) novo com etapas
227
240
 
228
241
  **FUNIL = KANBAN = pipeline = board — são a MESMA coisa no LionChat.** Quando o usuário pedir "cria um kanban", "monta um pipeline" ou "cria um funil", a ferramenta é `lionchat_funnels_create` (não existe endpoint separado de "criar kanban").
@@ -372,13 +385,14 @@ Antes de escolher a ferramenta, cheque se a intenção bate com a coluna da dire
372
385
  |---|---|---|
373
386
  | Listar / ver não lidas | `lionchat_conversations_list` (`conversation_type: 'unread'`) ou `lionchat_conversations_meta` | NÃO use `lionchat_conversations_unread` — é AÇÃO DE ESCRITA (marca como não-lida) |
374
387
  | Achar a conversa **de uma pessoa/empresa** (nome, telefone, e-mail, CPF/CNPJ, nº da conversa) | `lionchat_search_list` (`/search/conversations`) ou `lionchat_contacts_search` | RÁPIDO. **NÃO use `lionchat_conversations_search`**: apesar do nome, ele é o legado que procura dentro das mensagens e leva **15 a 22 s** (medido em produção 11/08). O sufixo `_list` aqui é histórico — `lionchat_search_list*` **são buscas**, não listagens; a regra "não baixe tudo com `*_list`" vale para `lionchat_<recurso>_list` |
375
- | Achar **onde foi dito** algo (palavra dentro da conversa) | `lionchat_search_list_2` (`/search/messages`) | RÁPIDO: índice trigram próprio e teto de tempo em duas fases (2 s / 14 s). É a substituta certa do `lionchat_conversations_search` |
388
+ | Achar **onde foi dito** algo (palavra dentro da conversa) | `lionchat_search_list_2` (`/search/messages`) | RÁPIDO: índice trigram próprio e teto de tempo em duas fases (2 s / 2 s desde 04/09 — antes a 2ª fase herdava 14 s e o pior caso da seção era 16 s). Estourou as duas, o payload volta com `message_search_interrupted: true` e a lista VAZIA — isso NÃO quer dizer que não existe, quer dizer que não deu tempo: tente de novo. É a substituta certa do `lionchat_conversations_search` |
376
389
  | Não sei se o termo é nome de alguém ou algo dito no papo | `lionchat_search_search` (`/search`) | Cobre os dois numa chamada. Opção mais segura quando a intenção é ambígua |
377
390
  | (qualquer busca) termo com menos de 3 caracteres | — | Volta **vazio de propósito** em todas as buscas. Vazio ≠ "não existe": quer dizer que a busca não rodou. Refaça com 3+ caracteres. Só-dígitos é isento nas rotas `/search/*`, mas **não** no `lionchat_conversations_search` legado |
378
391
  | Só a contagem / números | `lionchat_conversations_meta` / `lionchat_reports_summary` | Não liste o conteúdo completo |
379
392
  | Criar contato | `lionchat_contacts_create` base (path `/contacts`) | NÃO use as variantes `_1` … `_9` |
380
393
  | Pausar a IA agora (botão de pânico) | `lionchat_captain_assistants_update` (`paused: true`, top-level) | — |
381
394
  | Criar/editar **formulário público de captação** (página de captura própria) | `lionchat_lead_forms_create` / `_update` | Leia `lionchat://docs/formularios-publicos` ANTES — o desenho vai em `form_data` e só entra no ar depois do `publish` (que valida o desenho e pode voltar 422 com a lista de pendências). Caixa de WhatsApp vinculada (`inbox_id`) é obrigatória pra publicar. Escrita é só de administrador |
395
+ | **Mandar um contrato pra assinar** / ver quem assinou / reenviar / cancelar / criar ou editar o modelo escrito | `lionchat_signature_envelopes_create` / `_list` / `_show` / `_resend` / `_cancel`; `lionchat_signature_documents_list` / `_create` / `_update`; `lionchat_signature_envelopes_sign_as_sender` (o remetente assina pelo painel) | Leia `lionchat://docs/assinatura-eletronica` ANTES. Modelo `text` a API cria e edita (texto com `{{contact.*}}`); PDF/Word só pela tela. Campo do modelo sem valor na ficha bloqueia o envio (422 `variaveis_sem_valor` com a lista); `422 escolher_caixa` = repita com `inbox_id`. Cada contrato consome 1 vaga do limite mensal. Modelo Word: `422 fila_cheia` = muita gente convertendo agora, repita em instantes; `422 conversor_indisponivel` = o serviço de conversão está fora (não é o arquivo) — avise o operador. Remetente assina pelo painel com `_sign_as_sender` (PNG em base64). Importar Word, pré-visualizar e baixar PDF: só pela tela (o conector não envia arquivo nem recebe PDF) |
382
396
  | **Testar um formulário** antes de publicar | `lionchat_lead_forms_test_run` | Roda o RASCUNHO no motor real e desfaz tudo no fim — zero rastro. Mande `answers: [{node_id, value}]` (até 60) pra reproduzir um caminho; a resposta traz o bloco atual + o log do percurso |
383
397
  | Conferir se um site **aceita ser exibido dentro do formulário** (bloco Página externa) | `lionchat_lead_forms_check_embed` | Body `{url}`; devolve `{status: allowed\|blocked\|unknown, reason}`. Grave o veredito em `embed_allowed` do bloco. Admin-only |
384
398
  | Ver **tudo que uma pessoa preencheu** (nosso formulário, anúncio do Meta, Webhook Universal, fluxo) | `lionchat_contacts_form_entries_list` / `_show` | Por CONTATO, sem paginação (teto 250 por origem, `meta.truncated`). O detalhe de Meta/webhook mostra SÓ os campos vinculados e gravados — nunca o payload cru. `show` exige `source` + `id` da mesma linha |
@@ -0,0 +1,75 @@
1
+ # Assinatura eletrônica de contratos
2
+
3
+ **Não confundir com "assinatura" de PLANO/cobrança** (fatura, cartão, saldo) — essa área fica fora do MCP.
4
+ Aqui é a **assinatura eletrônica de documentos**: o cliente assina um contrato pelo WhatsApp (ou e-mail),
5
+ com código de uso único, e o LionChat guarda a prova (IP, aparelho, localização, hash, PDF selado).
6
+ Feature `document_signing` (ligada por conta; 403 `feature_disabled` quando desligada).
7
+
8
+ ## As três camadas
9
+
10
+ | Camada | O que é | Ferramentas |
11
+ |---|---|---|
12
+ | **Modelo** (`signature_documents`) | O contrato padrão, escrito uma vez com `{{variáveis}}` da ficha. `kind`: `text` (escrito no editor — o único que a API cria), `file` (PDF pronto, igual pra todos) ou `word` (.docx que sai idêntico com os campos mapeados) — os dois últimos só pela tela (upload). | `lionchat_signature_documents_list/show/create/update/destroy/field_catalog` |
13
+ | **Contrato** (`signature_envelopes`) | Cada ENVIO a uma pessoa: PDF próprio com os dados dela, prazo, linha do tempo. | `lionchat_signature_envelopes_list/show/create/resend/cancel/limits` |
14
+ | **Participante** | Quem assina dentro de um contrato: `signer` (titular, pode ser mais de um), `witness` (testemunha, opcional), `sender` (o remetente, quando o modelo tem "eu também assino" — assina NO PAINEL, sem link). Cada um tem link e código próprios. | dentro do contrato (`participants[]`) |
15
+
16
+ ## Estados do contrato (`status`) e os baldes de filtro
17
+
18
+ | Balde (`status` na listagem) | Estados | Significado |
19
+ |---|---|---|
20
+ | `aguardando` | `draft`, `sent` | criado sem entrega (draft) ou enviado e ainda não aberto |
21
+ | `visualizado` | `viewed`, `partially_signed` | abriu o link / parte das pessoas já assinou |
22
+ | `assinado` | `signed_pending_seal`, `signed` | todos assinaram; selando / documento final pronto |
23
+ | `encerrado` | `refused`, `cancelled`, `expired` | recusado / cancelado pela equipe / prazo venceu |
24
+ | `falta_eu` | — | contratos abertos em que o usuário do token é o remetente e ainda não assinou |
25
+
26
+ Participante: `pending` → `viewed` → `verified` (confirmou o código) → `signed` | `refused`.
27
+
28
+ ## Linha do tempo (`events[].kind`)
29
+ `created` · `delivered` (link entregue a uma pessoa) · `sent` · `opened` (cada abertura) · `code_requested` ·
30
+ `code_verified` · `signed` (com `ip`, `device`, `location`; `panel: true` = assinou no painel) · `all_signed` ·
31
+ `sealed` (documento final gerado, `sealed_sha256`) · `refused` · `cancelled` · `expired` · `delivery_failed`
32
+ (motivo em `delivery.failed[]`) · `reminded` · `resent`. Tudo append-only — é o relatório de evidências.
33
+
34
+ ## Como mandar um contrato (receita)
35
+ 1. `lionchat_signature_documents_list` → escolha o modelo (ou crie um `text` com `signature_documents_create`;
36
+ variáveis em `signature_documents_field_catalog`).
37
+ 2. Confira a ficha: toda `{{variável}}` do modelo precisa ter valor no contato (nome, CPF, endereço…) —
38
+ senão o envio volta `422 variaveis_sem_valor` com a lista do que falta.
39
+ 3. `lionchat_signature_envelopes_create` com `signature_document_id`, `contact_id` e `participants`
40
+ (`[{name, role: 'signer', phone, delivery_channel: 'whatsapp', contact_id}]`; testemunha = mais um item
41
+ com `role: 'witness'` e o telefone dela).
42
+ 4. `422 escolher_caixa` → a pessoa conversa em mais de uma caixa de WhatsApp: repita com `inbox_id`.
43
+ 5. Acompanhe com `signature_envelopes_show` (linha do tempo) ou `signature_envelopes_list`
44
+ (`contact_id`, `status`, `q`). Não chegou? `resend`. Errou? `cancel` (admin). Falta a SUA assinatura
45
+ (modelo com "eu também assino")? `signature_envelopes_sign_as_sender` — ver regra abaixo.
46
+
47
+ ## Regras que valem sempre
48
+ - **Quem pode**: administrador ou cargo personalizado com "Gerenciar Assinaturas" (`signature_manage`) — vale para
49
+ criar/editar modelo, prévia, enviar, reenviar, baixar e "eu também assino" (403 sem a chave). A LISTA de modelos e a
50
+ leitura de um modelo continuam abertas a qualquer membro. Cancelar contrato e apagar modelo: só administrador.
51
+ - **Trava sagrada**: campo do modelo sem valor na ficha bloqueia o envio. Preencher a ficha primeiro.
52
+ - **Validade** (`roles_layout.validity_days`, padrão 7) conta do ENVIO; `{{document.deadline}}` imprime a data no
53
+ texto; passou = `expired` (cron de hora em hora). **Lembrete** (`reminder_days`, padrão 2, 0 = off): quem não
54
+ assinou recebe o link de novo a cada N dias.
55
+ - **Conversor de Word** é um serviço separado (docx-converter). Fora do ar = `422 conversor_indisponivel` na prévia e no envio de modelo Word — é o serviço, não o arquivo; repetir em instantes. Modelos `text` e `file` não passam por ele.
56
+ - **Fila única de conversão do Word**: uma conversão por vez em toda a instalação (todas as contas); pela tela espera-se até 10 s, automação/macro/fluxo/formulário até 2 s.
57
+ Passou disso o envio/prévia volta `422 fila_cheia` — é só repetir em instantes (o modelo está bom).
58
+ - **Limite mensal** (`signature_envelopes_limits`): cada contrato criado consome 1 vaga; cancelar não devolve.
59
+ - **PDFs** (original, assinado, evidências) e o **QR de conferência** só existem pela tela/download autenticado —
60
+ não há ferramenta que devolva os bytes. O `sealed_sha256` é o hash do documento final.
61
+ - **Só pela tela, de propósito** (existem na API, mas NÃO como ferramenta): importar um Word (`import_docx`),
62
+ pré-visualizar modelo ou rascunho (`preview`, `preview_draft`) e baixar PDF (`download`). O conector não envia
63
+ arquivo nem recebe PDF — não prometa "vou gerar a prévia" ou "vou baixar o assinado"; oriente a tela.
64
+ - **Assinar no painel** ("eu também assino", 08/09): `lionchat_signature_envelopes_sign_as_sender` assina como o
65
+ REMETENTE (a pessoa do token) — nunca no lugar do cliente. Manda `signature_image` (PNG em base64 com prefixo
66
+ `data:image/png;base64,...`), opcional `location {latitude, longitude, accuracy}` (vai pra prova) e
67
+ `remember_drawing`. 422: `nao_e_sua` (não é o remetente deste contrato), `ja_assinado`, `sem_desenho`. Era a
68
+ última que faltava? o contrato fecha e o PDF final é gerado em seguida. Os que esperam você: `status=falta_eu`.
69
+ - **Envio por outros caminhos**: ação `send_signature_document` no FlowBuilder, na Macro e na Automação;
70
+ bloco `generate_contract` no Formulário público (gera pelas respostas e manda o link). Gatilhos do Flow
71
+ `signature_*` (8 acontecimentos) trazem `{{contrato.*}}` — ver `lionchat_flows_schema_reference`.
72
+
73
+ ## Onde o cliente vê
74
+ Menu **Assinaturas** (modelos e contratos, filtros, "Falta você assinar"), aba **Contratos** na ficha do contato,
75
+ pílulas na conversa a cada acontecimento e avisos no sininho para quem enviou.
@@ -160,11 +160,11 @@ Travas que valem conhecer (não dá pra desligar):
160
160
  ## Limite do prompt e cache OpenAI (2026-05-22)
161
161
 
162
162
  - `config.instructions` (system prompt do agente) aceita até **20.000 caracteres** (antes 10k). Acima de 15k, o frontend mostra aviso "lost in the middle" — prefira colocar instruções críticas no início ou final.
163
- - **Cache automático** ativo em todos os 16 modelos oferecidos na plataforma. Desconto 50-75% no input cachado, sem configuração. Reuso do prompt do agente em múltiplas conversas maximiza a economia.
163
+ - **Cache automático** ativo em todos os 19 modelos oferecidos na plataforma. Desconto 50-75% no input cachado, sem configuração. Reuso do prompt do agente em múltiplas conversas maximiza a economia.
164
164
 
165
165
  ### Lista real de modelos (`config.model`)
166
166
 
167
- Estes são os 16 valores que o seletor de modelo do painel oferece (`ModelSelector.vue`). Só recomende
167
+ Estes são os 19 valores que o seletor de modelo do painel oferece (`ModelSelector.vue`). Só recomende
168
168
  valores desta lista:
169
169
 
170
170
  | Faixa | Modelos |
@@ -172,18 +172,21 @@ valores desta lista:
172
172
  | Econômicos / rápidos | `gpt-4.1-nano`, `gpt-4o-mini`, `gpt-4.1-mini`, `gpt-5.4-nano`, `gpt-5.4-mini` |
173
173
  | Intermediários | `gpt-4o`, `gpt-4.1`, `gpt-5-mini`, `gpt-5.4` |
174
174
  | Raciocínio | `o3-mini`, `o4-mini` |
175
- | Premium | `gpt-5`, `gpt-5.2`, `gpt-5.5`, `o1`, `o3` |
175
+ | Premium | `gpt-5`, `gpt-5.2`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-terra`, `gpt-5.6-sol`, `o1`, `o3` |
176
176
 
177
177
  **`GPT-5.2 Pro` não existe.** O valor válido é `gpt-5.2`, sem "Pro".
178
178
 
179
- > **PERIGO — família `gpt-5.6` (`gpt-5.6-luna`, `gpt-5.6-terra`, `gpt-5.6-sol`): REMOVIDA em 29/07/2026.**
180
- > Esses modelos **recusam function tools** em `/v1/chat/completions` (erro 400 real: "Function tools with
181
- > reasoning_effort are not supported"). Como o AI Agente usa ferramentas em **toda** resposta, 100% das
182
- > chamadas falhavam e a IA ficava **MUDA** — sem erro na tela, sem resposta. Ficou 2 semanas invisível.
183
- > **Nunca sugira, nunca grave** um `gpt-5.6` — nem se o cliente pedir "o mais novo/mais forte".
179
+ > **Família `gpt-5.6` (`gpt-5.6-luna`, `gpt-5.6-terra`, `gpt-5.6-sol`) — LIBERADA em 09/2026.**
180
+ > Foi removida em 29/07/2026 porque recusa function tools no canal antigo da OpenAI e deixava a IA MUDA.
181
+ > Desde 09/2026 o servidor fala com esses três pela porta `/v1/responses` (só para eles — nenhum outro
182
+ > modelo muda de canal). Podem ser gravados em `config.model` do assistente, no Copilot e no bloco de IA do
183
+ > Flow. **Recusam temperatura personalizada: `config.temperature` é ignorada** (só o padrão). O `sol` custa
184
+ > ~5x o `luna` — recomende o `luna` salvo pedido explícito. **NUNCA no bloco de IA do Formulário de Lead**
185
+ > (teto de 15 s; o servidor exclui e cai no fallback).
184
186
  >
185
- > O campo `config.model` **não tem lista branca no servidor**: ele é `store_accessor` do `config` e
186
- > aceita qualquer texto sem validar. Modelo inválido salva com 200 e só quebra na hora de responder.
187
+ > Desde 09/2026 o campo `config.model` **tem lista branca no servidor** (`LlmConstants::SELECTABLE_MODELS`):
188
+ > trocar para um modelo fora da lista devolve **422** (`model is not included in the list`). Registro
189
+ > antigo com modelo fora da lista continua salvando os outros campos; só a troca é recusada.
187
190
  > Desde 29/07 o erro vira uma **nota privada em português** na conversa (`llm_request_rejected`) — é o
188
191
  > primeiro lugar a olhar quando "a IA parou de responder logo depois de mexerem nas configurações".
189
192
 
@@ -387,6 +390,40 @@ integração conectada na conta (senão é pulado em silêncio — confira as li
387
390
  (o que iniciou o fluxo ou o mais recente da conversa); sem card, o registro NÃO aparece nas telas de
388
391
  eventos do Funil (só no histórico do fluxo). Formato completo no `flowbuilder-design-guide`.
389
392
 
393
+ ### Meta CAPI — lead que chegou por ANÚNCIO DE WHATSAPP (2026-09-10)
394
+
395
+ Quem chegou pelo botão de WhatsApp de um anúncio (a conversa carrega `ctwa_clid` e a caixa é a
396
+ oficial, com WABA) sai pra Meta como evento de MENSAGEM (`action_source: business_messaging`) — e a
397
+ Meta só aceita isso num **dataset vinculado à WABA**, nunca no pixel do site (recusa 2804132). Até
398
+ 10/09 100% desses eventos caíam no plano B (saíam como site) sem ninguém ver. Regras pro MCP:
399
+
400
+ - **Vincular a caixa primeiro:** `lionchat_inboxes_capi_dataset_link` (POST `/inboxes/{id}/capi_dataset`).
401
+ Idempotente, vale para todos os números da mesma WABA, usa a chave da PRÓPRIA caixa (a do pixel não
402
+ serve). O id fica em `provider_config.capi_dataset_id` (visível em `lionchat_inboxes_show` para admin).
403
+ Sem o vínculo os eventos de anúncio saem como site com `fallback_reason: lionchat:dataset_nao_configurado`.
404
+ - **Nome do evento em mensagem = SÓ 14:** `LeadSubmitted`, `QualifiedLead`, `ViewContent`, `AddToCart`, `InitiateCheckout`, `Purchase`, `OrderCreated`, `OrderShipped`, `OrderDelivered`, `OrderCanceled`, `OrderReturned`, `CartAbandoned`, `RatingProvided`, `ReviewProvided`.
405
+ O evento de SITE continua com o nome que o cliente quiser. A escolha de WhatsApp mora em
406
+ `messaging_name` (etapa e `won` do `meta_events_config`, tool `lionchat_funnels_meta_events_config`),
407
+ em `messaging_event_names.meta` (bloco `send_conversion` do fluxo) e em `messaging_event_name`
408
+ (disparo manual `lionchat_kanban_items_meta_capi_fire`). Tri-estado: chave AUSENTE = automático
409
+ (Lead/Contact → LeadSubmitted, Purchase → Purchase, InitiateCheckout → InitiateCheckout; sem sugestão
410
+ o lead de anúncio sai como site com motivo), `''` = não enviar como WhatsApp, um dos 14 = escolha.
411
+ Nome fora dos 14 é descartado no funil e dá 422 no disparo manual. `lost` (Perdido) é sempre site —
412
+ não existe evento de "perdido" em mensagens. O nome interno do cliente vai em `custom_data.internal_event`.
413
+ - **Diagnóstico "por que a venda não contou como conversão de WhatsApp?":**
414
+ `lionchat_funnels_meta_capi_events_list` com `degraded=true` e ler `fallback_reason` + `action_source`.
415
+ Motivos nossos: `lionchat:dataset_nao_configurado` (falta o vínculo), `lionchat:caixa_token_recusado`
416
+ (a Meta recusou a chave da caixa — reconectar a caixa), `lionchat:caixa_nao_encontrada`,
417
+ `lionchat:caixa_sem_token`, `lionchat:dataset_id_invalido`, `lionchat:desligado_pelo_cliente`,
418
+ `lionchat:nome_sem_equivalente_whatsapp`; da Meta: `"<subcode>: <mensagem>"` (ex.: 2804087 = clique
419
+ do anúncio inválido/expirado).
420
+ - Recusa ao vincular (422 com `subcode`, ex.: 2804116 / "whatsapp_business_manage_events"): a chave da
421
+ caixa não tem a permissão — reconectar a caixa pelo Cadastro Incorporado da Meta; nunca pedir o token
422
+ do pixel para isso. Um 401/403 da caixa NUNCA desliga o pixel da conta (site, formulário e agenda
423
+ continuam) — o evento de anúncio apenas sai como site com o motivo.
424
+ - NUNCA prometer que eventos antigos voltam: o plano B marca como enviado (não há retry) e a Meta só
425
+ aceita evento com até 7 dias.
426
+
390
427
  ### Meta Lead — token de anúncios de OUTRO app (2026-09-01)
391
428
 
392
429
  `lionchat_meta_lead_validate_token` pode voltar `app_verified: false` com `expires_at` nulo: é token
@@ -690,7 +727,7 @@ automática. Ver a seção de variáveis de conta acima.
690
727
 
691
728
  - **Tipo de atributo `time` (Hora 24h):** ao criar custom attribute com `attribute_display_type: "time"` (ou o numérico `9`), o valor canônico é `"HH:MM"` 24h e o fuso mora na definição (`attribute_timezone`, IANA, default `America/Sao_Paulo`). Uso principal: alimentar o campo Horário do node `wait` (modo date, `waitTimeMode: "variable"`).
692
729
  - **Tipo de atributo `datetime` (Data e Hora, novo 2026-07-18):** `attribute_display_type: "datetime"` (ou numérico `10`), com `attribute_timezone` (default `America/Sao_Paulo`). Guarda data+hora juntas em ISO com offset (`"2026-07-18T14:55:00-03:00"`); exibe `"DD/MM/AAAA - HH:MM"`. Um porteiro no backend aceita e converte vários formatos de entrada (ISO/UTC/BR/AM-PM/unix). **ATENÇÃO ao montar flows:** o tipo `datetime` NÃO é selecionável no Gatilho de Data nem nos campos Data/Horário do node `wait` — esses continuam exigindo `date`(5) pra data e `time`(9) pra hora, SEPARADOS. O `datetime` é, por ora, tipo de armazenamento/exibição (sidebar + mensagens humanas), não fonte de entrada de fluxo. Em condição, atributo `datetime` é tratado como string (compara o ISO cru).
693
- - **Timeout de flow `ai_tool` com node `api`:** sobe sozinho de 20s pro teto de 45s quando ainda está no padrão — não precisa configurar nada; só evite setar `execution_timeout_ms` custom se quiser manter o auto-ajuste.
730
+ - **Timeout de flow `ai_tool` com node `api`:** sobe sozinho de 20s pro teto de 45s quando ainda está no padrão e, desde 10/09/2026, DESCE de volta pro teto quando o último node `api` é apagado (antes o valor gravado ficava acima do teto e o flow não salvava mais — o 422 vinha como "configuração incompleta" sem nenhum bloco vermelho). Não precisa configurar nada; só evite setar `execution_timeout_ms` custom se quiser manter o auto-ajuste. Valor acima do teto enviado por API/MCP continua recusado.
694
731
  - **Teste do node `api`:** o resultado do último teste fica salvo no servidor (pin, TTL 30 dias) — sobrevive a trocar de navegador/máquina. Isso é recurso do editor humano; não há tool MCP pra isso.
695
732
 
696
733
  ## Status codes a respeitar
@@ -704,6 +704,7 @@ Todos os formatos abaixo foram conferidos linha a linha em `app/services/action_
704
704
  | `assign_agent` | `[70]` — o agente precisa ser membro da caixa. `["nil"]` desatribui |
705
705
  | `assign_team` | `[3]`. `["nil"]` desatribui |
706
706
  | `assign_captain_assistant` | `[17]` ou `[{"assistant_id": 17, "proactive": true}]` — `proactive` false = a IA assume mas nao fala na hora |
707
+ | `deactivate_captain` | `[]` — desliga o AI Agente da conversa (novo 10/09/2026; a macro também tem) |
707
708
  | `send_email_to_team` | `[{"team_ids": [1], "message": "texto"}]` |
708
709
  | `send_webhook_event` | `["https://..."]` |
709
710
  | `send_attachment` | `[blob_ids]` — so funciona se a regra ja tiver arquivo anexado; nao da pra montar so por API |
@@ -713,7 +714,7 @@ Todos os formatos abaixo foram conferidos linha a linha em `app/services/action_
713
714
  | `mute_conversation` | `[]` |
714
715
  | `snooze_conversation` | `[]` |
715
716
  | `resolve_conversation` / `open_conversation` / `pending_conversation` | `[]` |
716
- | `update_contact_attribute` / `update_conversation_attribute` | `[{"attribute_key": "chave", "value": "texto ou {{contact.phone_number}}"}]` |
717
+ | `update_contact_attribute` / `update_conversation_attribute` | `[{"attribute_key": "chave", "value": "texto ou {{contact.phone_number}}"}]` — chave PROTEGIDA é recusada na execução e fica só no log (10/09/2026): prefixos `waha_whatsapp_`, `whatsapp_`, `origin_`, `ctwa_`, `meta_lead_`, `lt_` e atributos de sistema como `utm_*`/`gclid`. Vale pra macro e automação |
717
718
  | `create_kanban_item` | `[{"funnel_id": 31, "funnel_stage": "prospeccao", "allow_duplicates": false}]` |
718
719
  | `move_kanban_item_to_stage` | `[{"funnel_id": 31, "funnel_stage": "qualificacao"}]` |
719
720
  | `assign_agent_to_kanban_item` | `[{"funnel_id": 31, "agent_id": 70, "mode": "add"}]` — `mode` aceita `add` (padrao) ou `remove_all` |
@@ -196,12 +196,23 @@ Funnel
196
196
  ├── stages (jsonb: hash com slug_etapa => { name, color, position, description, checklist_templates })
197
197
  ├── settings (jsonb: { agents: [], goals: [], automations: [{trigger_type, action, action_config, enabled}] })
198
198
  ├── global_custom_attributes (jsonb array)
199
- ├── meta_events_config (jsonb: won/lost/stages → Meta Pixel/CAPI events)
199
+ ├── meta_events_config (jsonb: won/lost/stages → Meta Pixel/CAPI events; cada bloco: enabled, name,
200
+ │ is_standard, value_strategy, value_fixed, currency, messaging_name — este último é o evento de
201
+ │ ANÚNCIO DE WHATSAPP, tri-estado: ausente = automático, '' = não enviar, um dos 14 nomes da Meta;
202
+ │ só em stages e won, nunca em lost)
200
203
  ├── archived (bool)
201
204
  ├── active (bool)
202
205
  ├── position (int, ordem entre funis)
203
206
  └── created_at
204
207
 
208
+ MetaCapiEvent (meta_capi_events — cada envio de conversão pro Meta)
209
+ ├── event_name (nome INTERNO, o que o cliente escolheu), event_id (idempotência), status (pending/sent/failed/duplicate)
210
+ ├── trigger_type, kanban_item_id, contact_id, conversation_id, funnel_id, meta_pixel_integration_id
211
+ ├── inbox_id (2026-09-10: a caixa oficial de onde saiu a WABA — o envio de anúncio de WhatsApp usa o dataset e a chave DESSA caixa)
212
+ ├── fallback_reason (2026-09-10: preenchido quando um evento de anúncio de WhatsApp saiu como SITE — plano B; NULL = não degradou)
213
+ ├── payload_sent (jsonb: data[0].action_source = website | business_messaging; data[0].event_name = o nome que FOI pra Meta)
214
+ └── response_body (jsonb: resposta da Meta; `fallback_from` = a recusa original quando houve plano B)
215
+
205
216
  KanbanItem
206
217
  ├── id (PK)
207
218
  ├── account_id (FK)
@@ -341,6 +352,17 @@ Macro
341
352
  └── visibility (personal/global)
342
353
  ```
343
354
 
355
+ **Macro — ações e freios (10/09/2026).** `actions` aceita 40 nomes: todos os das automações (mesmos
356
+ `action_params`, ver a tabela em conversation-flows.md) mais os que só a macro tem — `mark_unread` (`[]`),
357
+ `add_contact_label`/`remove_contact_label` (`[titulos]`, etiqueta do CONTATO), `distribute_agents`
358
+ (`[agent_ids]`, rodízio de verdade), `update_card_attribute` (`[{funnel_id, attribute_key, value}]`),
359
+ `add_card_checklist` (`[{funnel_id, checklist_template_ids}]`), `add_card_offer` (`[{funnel_id, offer_ids}]`)
360
+ e `send_conversion` (`[{destinations, event_names, value}]` — só administrador ou cargo com
361
+ `marketing_integrations_manage` consegue SALVAR a macro; executar segue livre; teto de 50 conversões por
362
+ execução). Atributo protegido em `update_*_attribute` é recusado na execução (só no log). Executar
363
+ (`lionchat_macros_execute`): até 100 conversas por chamada, a mesma conversa em 5 s é pulada em silêncio,
364
+ 30 execuções por minuto por usuário (429). A mensagem de `send_canned_response` sai assinada por quem executou.
365
+
344
366
  ## Agenda / Tarefas / Booking
345
367
 
346
368
  ```
@@ -436,6 +458,11 @@ daquele tipo no calendário; vazio = cor do agente. A tarefa devolve `booking_co
436
458
  `cliente_alteracao_pagamento`, `odontograma_finalizado`, `inclusao_procedimento`
437
459
  (capturados ao vivo, não documentados pelo e-Clínica).
438
460
 
461
+ O recurso `eclinica_integration` da conta passou a ser ligado e desligado pelo PRÓPRIO cadastro da
462
+ integração (10/09/2026, `auto_managed`): sumiu do Super Admin e não há passo manual — os blocos de
463
+ relatório e as tools da e-Clínica valem assim que a integração existe. Contas que já tinham integração
464
+ receberam o recurso no deploy (migração).
465
+
439
466
  Os 3 últimos são do perfil ODONTOLÓGICO: `agendamento_aguardando` = a recepção marcou a
440
467
  chegada do paciente na clínica (grava a hora da chegada e `eclinica_status_agendamento = aguardando`);
441
468
  `odontograma_aprovado` = plano de tratamento aprovado (grava o cabeçalho do odontograma);
@@ -468,6 +495,8 @@ Atributos de sistema no CONTATO (prefixo `eclinica_`, protegidos, usáveis como
468
495
  | `eclinica_data_consulta` | date | Data da consulta, ISO |
469
496
  | `eclinica_hora_consulta` | **time** | Hora da consulta 24h `"HH:MM"` (novo 2026-07-06) |
470
497
  | `eclinica_hora_final` | **time** | Hora final da consulta (novo 2026-07-27) |
498
+ | `eclinica_link_confirmacao` | **link** | Link ecli.co para o paciente confirmar/cancelar a ÚLTIMA consulta (novo 2026-09-08; só existe quando a unidade aprendeu o padrão na aba Unidades). No LEMBRETE use a variável `{{link_confirmacao}}` do fluxo (ou `{{agendamento.link_confirmacao}}` na automação): é da consulta certa — a ficha aponta para a última, e quem tem duas marcadas receberia o link errado |
499
+ | `eclinica_paciente_nome` | text | Nome do PACIENTE como está no cadastro da e-Clínica (novo 2026-09-09). O nome do contato pode ser o do WhatsApp (mãe que agenda o filho pelo celular dela) — por isso NUNCA use `{{contact.name}}` nas mensagens da clínica. Nos fluxos por evento: `{{ contact.custom_attribute.eclinica_paciente_nome \| default: contact.name \| primeiro_nome }}`; no LEMBRETE use a variável `{{ paciente_nome \| default: contact.name \| primeiro_nome }}` (por consulta) ou `{{agendamento.paciente_nome}}` na automação. `primeiro_nome` = primeira palavra com inicial maiúscula. |
471
500
  | `eclinica_status_agendamento` | text | `agendado` / `aguardando` (paciente chegou) / `no_show` / `atendido` / `desmarcado`. Vem do TIPO do evento, nunca da letra da situação. **Estado terminal do MESMO agendamento não volta pra `agendado`** (2026-08-20): a e-Clínica manda `agendamento_alterado` a cada edição da consulta, inclusive depois da chegada/atendimento, e isso NÃO reabre o status. Consulta com `eclinica_idagenda` DIFERENTE nasce `agendado` |
472
501
  | `eclinica_situacao` | text | Situação do agendamento no painel, **POR EXTENSO** (2026-08-21, legenda oficial da e-Clínica): AGUARDANDO, NA CADEIRA, PASSAR FINANCEIRO, AGENDAR RETORNO, ATENDIDO, CONFIRMADO, CONFIRMADO PELO LINK, CONFIRMADO PELA API, FALTA, DESMARCADO, CANCELADO PELO LINK, CANCELADO PELA API. Antes guardava a letra crua (`A`, `C`…). Código nunca visto aparece como veio |
473
502
  | `eclinica_compromisso` | text | Tipo da consulta — TEXTO LIVRE da recepção (ex: Consulta, Retorno) |
@@ -590,6 +619,11 @@ MetaLeadIntegration (Facebook Lead Ads)
590
619
  ├── facebook_page_id (FK polimórfico)
591
620
  ├── status (active/token_expired/paused)
592
621
  └── meta_lead_forms (has_many)
622
+ → cada lead vira CONTATO com os atributos meta_lead_* (form_id/form_name, campaign_id/name,
623
+ adset_id/name, ad_id/name, creative_id/name, platform, account_id/name; definidos por conta como
624
+ atributo de contato). Filtráveis em contacts_filter como atributo personalizado; desde 10/09/2026
625
+ também no filtro da tela de contatos e no painel "Atributos de Campanha" da conversa
626
+ (meta_lead_form_name aparece como "Origem - Formulário")
593
627
 
594
628
  LeadForm (Formulário público de captação — feature flag lead_forms, por conta)
595
629
  ├── account_id (FK)
@@ -724,3 +758,20 @@ Os limites que a API devolve (`resource_limits.*` da conta, `email_usage.limit`,
724
758
  duas contas no MESMO plano podem ter limites diferentes — não é defeito. Limite `0` significa
725
759
  ILIMITADO em toda a plataforma. A contratação/remoção de adicionais é feita SÓ pela tela de
726
760
  Cobrança do painel (não há ferramenta MCP para isso, por decisão do dono).
761
+
762
+ ## Assinatura eletrônica de contratos (04/09)
763
+
764
+ ```
765
+ SignatureDocument (modelo) 1 ──── N SignatureEnvelope (contrato de UMA pessoa) 1 ──── N SignatureParticipant
766
+ name, kind (text|file|word) title, status, sent_at, expires_at, name, role (signer|witness|sender),
767
+ body ({{variáveis}}), tags, contact_id, conversation_id, status, phone/email, delivery_channel,
768
+ roles_layout {signers, witnesses, original_sha256, sealed_sha256, conversation_id (a conversa DELE),
769
+ sender_signs, require_id_photo, created_by (quem mandou) public_url, signed_at, viewed_at
770
+ validity_days, reminder_days} │
771
+ progress (contagem por balde) └── N SignatureEvent (append-only: kind, occurred_at, ip, user_agent, detail)
772
+ ```
773
+ - Contrato aponta pro contato (`contact_id`, nulifica se a ficha for apagada — a prova sobrevive) e pra conversa
774
+ do titular; cada participante tem a PRÓPRIA conversa (testemunha na dela).
775
+ - `roles_layout` é jsonb aberto e MESCLADO no update; `progress` é calculado (aguardando/visualizado/assinado/encerrado).
776
+ - Feature por conta: `document_signing`. Limite mensal em `usage_limits.signature_requests_per_month` (0 = ilimitado).
777
+ - Detalhe completo: resource `lionchat://docs/assinatura-eletronica`.
@@ -79,7 +79,7 @@ Mesmo shape de condição. 15/página.
79
79
  |---|---|
80
80
  | `id` (id interno do contato) | equal_to, not_equal_to |
81
81
  | `name`, `email`, `identifier`, `city`, `company`, `profession` | equal_to, not_equal_to, contains, does_not_contain |
82
- | `phone_number` | + starts_with (busca por DDD/prefixo) — **corrigido na atualização de 26/07/2026**; em instalação anterior devolve SEMPRE lista vazia (virava igualdade exata). Vazio com prefixo que existe = instalação antiga |
82
+ | `phone_number` | + starts_with (busca por DDD/prefixo) — **corrigido na atualização de 26/07/2026**; em instalação anterior devolve SEMPRE lista vazia (virava igualdade exata). Vazio com prefixo que existe = instalação antiga. **`equal_to`/`not_equal_to` casam as DUAS formas do celular BR (com e sem o 9º dígito) desde 05/09/2026** — mande `+5541999887766` ou `+554199887766`, os dois acham a mesma ficha; `not_equal_to` exclui as duas. Termo que não é celular BR completo (fixo, estrangeiro, trecho) segue exato |
83
83
  | `cpf`, `cnpj`, `rg` (cadastral) | equal_to, not_equal_to, contains, does_not_contain, is_present, is_not_present |
84
84
  | `country_code` | equal_to, not_equal_to |
85
85
  | `labels` | equal_to, not_equal_to, is_present, is_not_present |
@@ -529,7 +529,7 @@ o botão "Usar variável" ao lado do campo alterna lista fixa ↔ variável.
529
529
  | `add_card_offer` | `{ offer_id, use_custom_value?, custom_value?, funnel_id?, card_source? }` | Adiciona uma OFERTA (produto/serviço) ao card. `offer_id` de `offers_list`. `use_custom_value: true` + `custom_value` grava um valor personalizado na oferta; senão usa o valor cadastrado. O total do card recalcula sozinho (soma das ofertas). Respeita `card_source` (funnel só localiza o card) |
530
530
  | `send_webhook` | `{ url, headers?, body? }` | Dispara webhook externo |
531
531
  | `start_flow` | `{ flow_id }` | Inicia outro fluxo. **NÃO encerra o fluxo de origem** (desde 31/08): se houver bloco ligado depois dele, o fluxo SEGUE normalmente. Sendo o último do desenho, o fluxo termina ali como sempre. |
532
- | `send_conversion` (novo 2026-09-01; `event_names` 2026-09-02) | `{ destinations: ['meta'\|'ga4'\|'google_ads'], event_names: { meta?, google_ads?, ga4? }, event_name (reserva), value? }` | Manda o evento de conversão pro Meta (CAPI), Google Ads e/ou GA4 — o mesmo caminho do Funil, de dentro do fluxo. Aba Sistema (só flow `conversation`). Ver bloco próprio abaixo |
532
+ | `send_conversion` (novo 2026-09-01; `event_names` 2026-09-02; `messaging_event_names` 2026-09-10) | `{ destinations: ['meta'\|'ga4'\|'google_ads'], event_names: { meta?, google_ads?, ga4? }, messaging_event_names: { meta? }, event_name (reserva), value? }` | Manda o evento de conversão pro Meta (CAPI), Google Ads e/ou GA4 — o mesmo caminho do Funil, de dentro do fluxo. Aba Sistema (só flow `conversation`). Ver bloco próprio abaixo |
533
533
  | `deactivate_flow` ou `disable_flow` | `{}` | Encerra fluxo atual |
534
534
  | `update_attribute` | `{ attr_source: 'contact'\|'conversation'\|'card', attr_key, attr_value }` | Seta custom_attribute (ver abaixo) |
535
535
  | `assign_captain` (ou `assign_captain_assistant`) | `{ assistant_id }` | Atribui IA Captain |
@@ -542,7 +542,7 @@ o botão "Usar variável" ao lado do campo alterna lista fixa ↔ variável.
542
542
  **`send_conversion` — Enviar conversão (2026-09-01):**
543
543
 
544
544
  ```json
545
- { "key": "send_conversion", "config": { "destinations": ["meta", "google_ads"], "event_names": { "meta": "Lead", "google_ads": "Contact" }, "event_name": "Lead", "value": "1500,50" } }
545
+ { "key": "send_conversion", "config": { "destinations": ["meta", "google_ads"], "event_names": { "meta": "Lead", "google_ads": "Contact" }, "messaging_event_names": { "meta": "QualifiedLead" }, "event_name": "Lead", "value": "1500,50" } }
546
546
  ```
547
547
 
548
548
  - `destinations`: array com `meta`, `ga4` e/ou `google_ads` — **OBRIGATÓRIO e não vazio** (vazio = a ação
@@ -555,6 +555,15 @@ o botão "Usar variável" ao lado do campo alterna lista fixa ↔ variável.
555
555
  Chave presente e em branco = aquele destino é PULADO ("sem nome de evento"); chave ausente cai em `event_name`.
556
556
  Google Ads só envia evento que tenha ação mapeada na integração; a tela lista Meta (padrão + personalizados
557
557
  da conta) e Google Ads (mapeados), GA4 é livre. Grave sempre `event_names` E `event_name` (= primeiro nome).
558
+ - `messaging_event_names` (**desde 2026-09-10**, só a chave `meta`): o evento de **ANÚNCIO DE WHATSAPP**. Quem chegou
559
+ por anúncio de WhatsApp (clique para o WhatsApp, caixa oficial vinculada à Meta) sai como `business_messaging`, e
560
+ nesse caso a Meta só aceita 14 nomes: `LeadSubmitted`, `QualifiedLead`, `ViewContent`, `AddToCart`,
561
+ `InitiateCheckout`, `Purchase`, `OrderCreated`, `OrderShipped`, `OrderDelivered`, `OrderCanceled`, `OrderReturned`,
562
+ `CartAbandoned`, `RatingProvided`, `ReviewProvided`. Tri-estado: chave **ausente** = automático (sugestão pelo
563
+ evento de site: Lead/Contact → LeadSubmitted, Purchase → Purchase, InitiateCheckout → InitiateCheckout; sem sugestão
564
+ o lead de anúncio sai como site com `fallback_reason`); `""` = não enviar como WhatsApp (sai como site); um dos
565
+ 14 = escolha. Nome fora da lista é ignorado (vira automático). Não afeta GA4/Google Ads. O nome interno do
566
+ cliente (`event_names.meta`) vai em `custom_data.internal_event`.
558
567
  - `event_name`: reserva/compatibilidade (fluxos de antes de 02/09), só letras/números/sublinhado (até 40; ex.: `Lead`, `Schedule`,
559
568
  `Purchase`); aceita variável `{{ }}`. No **Google Ads** o nome precisa estar mapeado no
560
569
  `conversion_action_map` da integração, senão é pulado.
@@ -672,13 +681,15 @@ aiModel nos modos novos (proteção de nós antigos que carregam aiModel de defa
672
681
  padrão da conta).
673
682
  Exemplo: `{"aiMode":"sentiment","aiAssistantId":"12","aiModel":"gpt-4.1-mini","aiModelExplicit":true}`.
674
683
 
675
- **A whitelist (`FlowBuilder::RawLlmService::SUPPORTED_MODELS`) é uma lista FECHADA de 16 nomes, SEM
684
+ **A whitelist (`FlowBuilder::RawLlmService::SUPPORTED_MODELS`) é uma lista FECHADA de 19 nomes, SEM
676
685
  curinga** — não existe "a família gpt-5 inteira":
677
686
  `gpt-4o-mini`, `gpt-4o`, `gpt-4.1-nano`, `gpt-4.1-mini`, `gpt-4.1`, `gpt-5-mini`, `gpt-5`,
678
- `gpt-5.2`, `gpt-5.4-nano`, `gpt-5.4-mini`, `gpt-5.4`, `gpt-5.5`, `o1`, `o3`, `o3-mini`, `o4-mini`.
679
- A família **`gpt-5.6` (luna/terra/sol) foi REMOVIDA em 2026-07-29**: ela recusa function tools
680
- (erro 400 na OpenAI), o que deixava o Agente de IA **mudo em 100% das chamadas** — saiu também daqui
681
- pra não ser oferecida numa tela e faltar na outra. Também não existem `o1-mini`, `gpt-4.5-preview`,
687
+ `gpt-5.2`, `gpt-5.4-nano`, `gpt-5.4-mini`, `gpt-5.4`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-terra`,
688
+ `gpt-5.6-sol`, `o1`, `o3`, `o3-mini`, `o4-mini`.
689
+ A família **`gpt-5.6` (luna/terra/sol) voltou em 09/2026** (tinha sido removida em 2026-07-29 porque
690
+ recusa function tools no canal antigo): o servidor fala com esses três pela porta `/v1/responses`.
691
+ Eles ignoram a temperatura do bloco (só o padrão) e **NÃO valem no bloco de IA do Formulário de Lead**
692
+ (teto de 15 s — o servidor exclui e usa o fallback). Também não existem `o1-mini`, `gpt-4.5-preview`,
682
693
  `gpt-5.2-pro` nem `gpt-5.5-pro` (a OpenAI recusa).
683
694
 
684
695
  **OBRIGATÓRIO via API — `aiAssistantId`:** os modos `generate`/`intent`/`sentiment`/`extract`
@@ -1020,6 +1031,7 @@ O campo `flow_type` (definido na criação, IMUTÁVEL depois) decide a natureza
1020
1031
  | Campos extra | — | `tool_name` (snake_case, `[a-z][a-z0-9_]`, max 50) + `tool_description` (max 500) OBRIGATÓRIOS |
1021
1032
  | Retorno | manda mensagens | retorna dado estruturado ao LLM via node `end` |
1022
1033
  | Nodes permitidos | todos | `start`, `end`, `api`, `condition`, `set_variable`, `ai`, `note`, `randomizer`, `action`, `send_message` |
1034
+ | Aviso de espera (10/09/2026) | — | enquanto a ferramenta roda, o cliente recebe "Só um momento, estou verificando isso pra você...". Cada ferramenta escolhe o seu no node `start`: `data.toolWaitMessageEnabled` (`false` desliga; AUSENTE = ligado — só um `false` de verdade desliga, `""` ou lixo mantém ligado) e `data.toolWaitMessageText` (texto próprio, até 1000 caracteres; vazio = frase padrão). Vive no `flow_data` e viaja no snapshot de versão; ferramenta já existente não muda de comportamento |
1023
1035
 
1024
1036
  Se o cliente pediu "uma ferramenta que a IA usa pra consultar X / calcular Y", é `ai_tool`. Se pediu "quando chega mensagem, faça Z", é `conversation`. Na dúvida, `conversation`.
1025
1037
 
@@ -1128,15 +1140,35 @@ Dois atalhos: `{{trigger}}` devolve o contexto INTEIRO em JSON e `{{trigger.data
1128
1140
  sem os metadados — úteis pra jogar tudo dentro de um node `ai` ou `api`. Bloco (Hash/Array) inteiro
1129
1141
  sai em JSON; valor simples sai cru.
1130
1142
 
1131
- **O que o histórico mostra e NÃO é variável (22/08/2026).** O passo Início do histórico de execução
1132
- passou a exibir, em todo gatilho, o contato (nome, telefone, e-mail), a conversa (número, canal, caixa)
1133
- e os fatos do que disparou: etiqueta, responsável/equipe (ou "removido"), card (título, funil, etapa
1134
- anterior → etapa), política de SLA, grupo, nome do formulário e do marco, anúncio/formulário/campanha
1135
- do Meta Lead (+ as respostas, em bloco próprio), produto/oferta/meio de pagamento do gateway, evento/
1136
- unidade/data/hora/compromisso da e-Clínica, tecla do TopSend, e os dados do agendamento. Esses fatos
1137
- ficam numa área só-de-log (`_trigger_facts`) — **não existem como `{{trigger.*}}`** e não entram em
1138
- `{{trigger.data}}`. Se o cliente precisar de um deles no fluxo, use a variável de origem quando
1139
- existir (`{{booking.*}}`, `{{form_*}}`, `{{contact.*}}`, atributos do contato gravados pela integração).
1143
+ **Os fatos do que disparou VIRARAM variáveis (08/09/2026).** Desde 22/08 o passo Início do histórico
1144
+ mostra, em todo gatilho, o contato, a conversa e os fatos do que disparou. Desde 08/09 esses fatos
1145
+ também RESOLVEM como `{{trigger.<bloco>.<campo>}}` (contexto do gatilho vence o fato na mesma chave).
1146
+ Eles continuam FORA de `{{trigger.data}}` e de `{{trigger}}` — fluxo já em produção não muda de conteúdo.
1147
+
1148
+ Oferecidos no autocompletar (só quando o bloco Início tem o gatilho que os preenche):
1149
+
1150
+ | Gatilhos do Início | Variáveis |
1151
+ |---|---|
1152
+ | `card_created`, `card_moved`, `card_won`, `card_lost`, `card_attribute_changed` | `{{trigger.kanban.title}}`, `{{trigger.kanban.funnel_name}}`, `{{trigger.kanban.stage_name}}`, `{{trigger.kanban.stage}}` (código da etapa) |
1153
+ | `card_moved` | `{{trigger.kanban.previous_stage_name}}`, `{{trigger.kanban.previous_stage}}` |
1154
+ | `card_won`, `card_lost` | `{{trigger.kanban.status}}` (`won`/`lost`) |
1155
+ | `label_added`, `label_removed` | `{{trigger.label.name}}` |
1156
+ | `assignee_changed` | `{{trigger.assignee.name}}` (vazio = responsável removido) |
1157
+ | `team_changed` | `{{trigger.team.name}}` (vazio = equipe removida) |
1158
+ | `sla_missed` | `{{trigger.sla.policy_name}}`, `{{trigger.sla.type}}` (`frt`/`nrt`/`rt`) |
1159
+ | `group_participant_joined`, `group_participant_left` | `{{trigger.group.name}}`, `{{trigger.group.id}}` |
1160
+
1161
+ Resolvem mas NÃO aparecem no seletor (produtor único — só o gatilho daquela integração preenche):
1162
+ `{{trigger.attribute.name}}`/`current_value` (atributo do contato entrou no valor), `{{trigger.form.name}}`/
1163
+ `milestone`, `{{trigger.payment.gateway|event|product|offer|method|status|amount}}`,
1164
+ `{{trigger.eclinica.event|unit|date|time|compromisso|idagenda}}`, `{{trigger.lead.form|page|ad|adset|campaign|platform}}`
1165
+ (nome do anúncio, não dado de pessoa), `{{trigger.dtmf.key|campaign}}`, `{{trigger.reminder.date|time|compromisso|unit|days_before}}`,
1166
+ além de `{{trigger.kanban.id}}`/`funnel_id` (use `{{trigger.kanban_item_id}}`/`{{trigger.funnel_id}}`),
1167
+ `{{trigger.assignee.id}}`, `{{trigger.team.id}}`, `{{trigger.kanban.previous_status}}` e
1168
+ `{{trigger.group.participants_count}}`. As RESPOSTAS do lead do Meta não viram variável (só aparecem no
1169
+ histórico). Sessões anteriores a 22/08 não têm fatos gravados: essas variáveis saem vazias nelas.
1170
+ O bloco do card chama-se `kanban` — nunca `card`. Se o cliente precisar de um dado que não está aqui,
1171
+ use a variável de origem quando existir (`{{booking.*}}`, `{{form_*}}`, `{{contact.*}}`).
1140
1172
 
1141
1173
  **NÃO duplique o que já tem variável própria.** `{{contact.name}}`, `{{conversation.status}}`,
1142
1174
  `{{inbox.name}}` e os atributos `ctwa_*` continuam existindo e são a forma canônica. O `{{trigger.*}}`
@@ -23,7 +23,7 @@ caixa de WhatsApp vinculada e (opcionalmente) dispara um fluxo do FlowBuilder no
23
23
  responde 404** — ninguém consegue preencher. As tools de dashboard (listar, criar, editar,
24
24
  publicar, ver respostas, simular) **funcionam mesmo assim**. Dá pra montar tudo antes de ligar a
25
25
  flag; não adianta divulgar o link antes.
26
- - **Escrita é só de administrador.** `create`, `update`, `destroy`, `publish`, `duplicate` e
26
+ - **Escrita é de administrador ou de cargo personalizado com "Gerenciar Formulários" (`lead_form_manage`).** `create`, `update`, `destroy`, `publish`, `duplicate` e
27
27
  `check_embed` passam por `check_admin_authorization?`; usuário não-admin recebe **401**. Leitura
28
28
  (`list`, `show`, `stats`, `responses`) e o **simulador** (`test_run`) são liberados a qualquer
29
29
  agente da conta.
@@ -194,6 +194,7 @@ whitelist do `metadata` segue sem ela) — a decisão é do servidor.
194
194
  | `end` | `title, description, redirect_url, button_label, image, video_url` | — | sim |
195
195
  | `api_request` | `label, method, url, headers, body, timeout` | `success`, `error` | não (mostra bloco de espera) |
196
196
  | `ai` | `label, mode, prompt, categories, include_answers, model` | modo `generate`: `success`, `error` / modo `classify`: um `cat_<id>` por categoria + `other` | não (mostra bloco de espera) |
197
+ | `generate_contract` | `label, document_id, send_link` | `success`, `error` | não (mostra bloco de espera) |
197
198
 
198
199
  **Chave fora da lista não é lida pelo motor** e o editor a **remove no próximo salvamento pela
199
200
  tela**. Escrever um campo inventado pela API não gera erro nenhum — ele simplesmente não faz nada e
@@ -318,6 +319,16 @@ respostas já dadas como contexto. `model` é validado contra a lista suportada;
318
319
  da conta. A IA usa a **chave da própria conta** — conta sem chave faz o bloco sair pela saída de
319
320
  erro.
320
321
 
322
+ **`generate_contract`** (04/09 — bloco "Gerar contrato", feature `document_signing`): gera o CONTRATO de
323
+ assinatura eletrônica daquela pessoa a partir de um modelo (`document_id` = id de
324
+ `lionchat_signature_documents_list`) com os dados da FICHA — mapeie as perguntas com `map_to` para os
325
+ campos que o modelo usa (nome, CPF, endereço…); campo sem valor = saída `error` com o motivo
326
+ (`variaveis_sem_valor: contact.cpf`). `send_link` (padrão `true`) manda o link de assinatura no WhatsApp da
327
+ pessoa (conversa da caixa vinculada); `false` deixa o contrato pronto e você manda `{{contrato.<node_id>.link}}`
328
+ pelo bloco `send_message`. Roda DEPOIS do vínculo do contato, como efeito (bloco de espera), dentro dos
329
+ orçamentos do formulário (200 contratos/formulário/dia, 2.000/conta/dia). Consome 1 vaga do limite mensal
330
+ de contratos. Saídas: `success` (contrato criado) e `error`.
331
+
321
332
  ### Variáveis
322
333
 
323
334
  | Variável | O que traz | Onde vale |
@@ -326,6 +337,7 @@ erro.
326
337
  | `{{contact.name}}` `{{contact.phone}}` `{{contact.email}}` | O que a pessoa respondeu (a ficha é reserva) | idem |
327
338
  | `{{api.<node_id>.<caminho>}}` | Um pedaço da resposta de uma consulta | idem |
328
339
  | `{{ia.<node_id>}}` | O texto que a IA gerou naquele bloco | idem |
340
+ | `{{contrato.<node_id>.link}}` `.titulo` `.prazo` `.id` `.status` | O contrato gerado pelo bloco Gerar contrato (endereço de assinatura, título, data-limite) | mensagem, prompt, valores |
329
341
  | `{{var.<nome>}}` | Variável criada pelo bloco Definir variável | idem |
330
342
  | `{{conta.<variável>}}` | Variável da conta (cofre) | cabeçalho e CORPO de `api_request` (com segredo); em `set_variable` e no valor das Ações só as NÃO-secretas |
331
343
 
@@ -497,6 +497,21 @@ Ao disparar uma conversão pro Meta (Conversions API), o valor agora carrega uma
497
497
  tanto no disparo individual da conversão quanto na configuração do funil (valor padrão herdado pelos
498
498
  cards daquele funil).
499
499
 
500
+ ## Meta CAPI — evento de anúncio de WhatsApp, dataset da WABA e plano B (2026-09-10)
501
+
502
+ - **Evento de anúncio de WhatsApp** (`action_source: business_messaging`): conversão de quem chegou
503
+ pelo botão de WhatsApp de um anúncio (conversa com `ctwa_clid` numa caixa oficial). A Meta só
504
+ aceita 14 nomes nele (`LeadSubmitted`, `QualifiedLead`, `ViewContent`, `AddToCart`, `InitiateCheckout`, `Purchase`, `OrderCreated`, `OrderShipped`, `OrderDelivered`, `OrderCanceled`, `OrderReturned`, `CartAbandoned`, `RatingProvided`, `ReviewProvided`) e só num dataset vinculado à WABA.
505
+ - **Dataset da WABA** (`provider_config.capi_dataset_id` da caixa oficial): destino desses eventos,
506
+ criado/recuperado pelo botão "Vincular à Meta" (`lionchat_inboxes_capi_dataset_link`) com a chave da
507
+ própria caixa. Um por conta do WhatsApp Business; vale para todos os números dela.
508
+ - **`messaging_name` / `messaging_event_names.meta` / `messaging_event_name`**: a escolha do evento de
509
+ WhatsApp (funil / fluxo / disparo manual). Tri-estado: ausente = automático, `''` = não enviar como
510
+ WhatsApp, um dos 14 = escolha.
511
+ - **Plano B** (`fallback_reason` no `meta_capi_events`): o evento de anúncio saiu como SITE. O motivo
512
+ fica gravado (`lionchat:*` nosso ou `"<subcode>: <mensagem>"` da Meta); na tela é o selo âmbar
513
+ "site (plano B)" e o filtro "Só plano B" (`degraded=true` na API).
514
+
500
515
  ## Idiomas da plataforma (2026-06)
501
516
 
502
517
  A plataforma opera com 6 idiomas: `en`, `es`, `fr`, `it`, `pt`, `pt_BR` (default das contas
@@ -566,7 +581,7 @@ com data futura ou `has_imported_history` fecharia a janela de 24h daquela conve
566
581
  |---|---|---|
567
582
  | `medium` | caixa (`inboxes_list`/`_show`) | sub-tipo do canal. Numa caixa de Página do Facebook diz se ela é Messenger ou **só Instagram** — é o que separa os dois |
568
583
  | `content` | mensagem | já vem no formato de exibição (mensagem apagada mostra o aviso, não o texto cru) |
569
- | `last_incoming_message_at` | conversa | data da última mensagem VIVA do cliente (unix). Use para saber se a janela de 24h está aberta — não confie na data da conversa, que pode vir de histórico importado |
584
+ | `last_incoming_message_at` | conversa | data da última mensagem VIVA do cliente (unix). Use para saber se a janela de 24h está aberta — não confie na data da conversa, que pode vir de histórico importado. Mensagem que a Meta entregou ATRASADA (reentrega depois de uma queda) conta pela hora de ENVIO da Meta, não pela chegada (08/09): o campo, `can_reply` e a tela seguem a mesma régua que a Meta usa pra recusar |
570
585
 
571
586
  ## Formulário público: código para incorporar no site (02/09/2026)
572
587
 
@@ -584,3 +599,22 @@ A gravação permanente só nasce cerca de 24h depois da ligação. O card agora
584
599
  conversa). Quem atendeu voltou a aparecer nas recebidas. Se o cliente diz que o botão de ouvir não
585
600
  funciona numa ligação de hoje, o mais provável é que o arquivo permanente ainda não exista — a
586
601
  reconferência resolve sozinha dentro de 36h.
602
+
603
+ ## Assinatura eletrônica de contratos (04/09)
604
+
605
+ ### `status` do contrato (`signature_envelopes`)
606
+ | Valor | Balde de filtro | Significado |
607
+ |---|---|---|
608
+ | `draft` | aguardando | criado sem nenhuma entrega (falhou) — use `resend` |
609
+ | `sent` | aguardando | link entregue, ninguém abriu ainda |
610
+ | `viewed` | visualizado | alguém abriu o link |
611
+ | `partially_signed` | visualizado | parte das pessoas assinou |
612
+ | `signed_pending_seal` | assinado | todos assinaram; o documento final está sendo gerado |
613
+ | `signed` | assinado | documento final pronto (`sealed_sha256`) |
614
+ | `refused` / `cancelled` / `expired` | encerrado | recusado / cancelado pela equipe / prazo venceu |
615
+
616
+ ### `role` do participante: `signer` (titular), `witness` (testemunha), `sender` (remetente — assina no painel).
617
+ ### `status` do participante: `pending` → `viewed` → `verified` → `signed` | `refused`.
618
+ ### Erros do envio (`signature_envelopes_create`): `variaveis_sem_valor` (+ `missing[]`), `escolher_caixa` (+ `inboxes[]`),
619
+ `entrega_falhou`, `sem_caixa_whatsapp`, `telefone_invalido`, `limite_do_mes`, `cpf_invalido`, `funcionalidade_desligada`,
620
+ `fila_cheia` (fila única de conversão do Word cheia — repetir em instantes), `conversor_indisponivel` (o serviço de conversão de Word não respondeu — repetir em instantes).