@lionchat/mcp-server 1.10.0 → 1.10.2
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.
- package/dist/docs/instructions.md +23 -0
- package/dist/docs/resources/best-practices.md +35 -0
- package/dist/docs/resources/conversation-flows.md +220 -1
- package/dist/docs/resources/data-model.md +4 -3
- package/dist/docs/resources/filtros-e-relatorios.md +32 -1
- package/dist/docs/resources/flowbuilder-design-guide.md +67 -1
- package/dist/docs/resources/glossary.md +17 -0
- package/dist/docs/resources/reports-guide.md +19 -0
- package/dist/docs/resources/troubleshooting.md +36 -0
- package/endpoints.json +4 -4
- package/package.json +1 -1
|
@@ -90,6 +90,25 @@ daquela caixa, mas fica FORA da distribuição automática (round-robin nunca at
|
|
|
90
90
|
caixas das quais participa — exceção é estar atribuído a um card, que libera só aquela conversa (ver
|
|
91
91
|
`lionchat://docs/kanban-deep-dive`).
|
|
92
92
|
|
|
93
|
+
### Supervisor de time (TeamMember.auto_assignable) — novo 2026-07-30
|
|
94
|
+
|
|
95
|
+
O TIME passou a ter os MESMOS dois papéis da caixa. Supervisor de time é membro pra TUDO — menção ao
|
|
96
|
+
time, e-mail de automação, acesso ao funil do Kanban, relatório, contagem e atribuição MANUAL — mas
|
|
97
|
+
fica FORA da distribuição automática do time (nem conversa, nem rodízio de card do funil).
|
|
98
|
+
|
|
99
|
+
- Flag: `team_members.auto_assignable` (`false` = supervisor, `true` = agente). A coluna nasce `true`:
|
|
100
|
+
todo vínculo anterior a 30/07 é Agente.
|
|
101
|
+
- Tools: `lionchat_team_members_create` / `_update`. **O contrato é DIFERENTE do da caixa, de
|
|
102
|
+
propósito:** aqui `user_ids[]` é a lista COMPLETA de membros e `supervisor_ids[]` é um SUBCONJUNTO
|
|
103
|
+
dela. Chave `supervisor_ids` **ausente = não mexe em papel nenhum** (só entra/sai membro) — assim um
|
|
104
|
+
cliente antigo que só manda `user_ids` não zera em silêncio os supervisores marcados na tela.
|
|
105
|
+
- `lionchat_team_members_list` traz `is_supervisor` por agente.
|
|
106
|
+
|
|
107
|
+
**As duas marcas são INDEPENDENTES (decisão do dono 30/07):** a da caixa protege da distribuição da
|
|
108
|
+
CAIXA; a do time protege da distribuição do TIME. Supervisor de caixa que é agente de um time
|
|
109
|
+
CONTINUA recebendo conversa por aquele time — é intencional, não é defeito. Nunca diga ao cliente que
|
|
110
|
+
marcar supervisor num lugar protege no outro.
|
|
111
|
+
|
|
93
112
|
## 3. Convenções da API
|
|
94
113
|
|
|
95
114
|
### Datas
|
|
@@ -302,6 +321,7 @@ e pular evita que ela receba tudo em dobro. Quem está sendo atendido pela equip
|
|
|
302
321
|
| Rate limit leitura | 1200/min por token |
|
|
303
322
|
| Rate limit escrita | 600/min por token |
|
|
304
323
|
| Loop detection | bloqueia chamada idêntica >10x em 10s |
|
|
324
|
+
| Variável de Conta — tamanho do valor | 32 KB por variável (novo 01/08/2026; passou disso = HTTP 422 na conta). Vale só pra variável DECLARADA na tela; chave interna do sistema não é barrada. É por variável, não pela soma — conta com dezenas de tokens legítimos não é punida |
|
|
305
325
|
|
|
306
326
|
Exceção ao teto de 300: em ação em massa de **contatos** com `select_all: true` (agir sobre todos os
|
|
307
327
|
contatos do filtro) não há teto de IDs — o servidor refaz o filtro e processa em lotes no fundo. O
|
|
@@ -352,6 +372,9 @@ Antes de escolher a ferramenta, cheque se a intenção bate com a coluna da dire
|
|
|
352
372
|
| **Importar histórico** de caixa WhatsApp Cloud (QR) | `lionchat_inboxes_whatsapp_history_start` / `_status` / `_cancel` | Admin-only + flag `qr_history_import`; só caixa oficial. Acompanhe `state` no `_status` |
|
|
353
373
|
| Ver / limpar **falhas de envio** de uma caixa | `lionchat_inboxes_failed_messages_summary` primeiro; depois `_bulk_retry` (reenviar) ou `_bulk_cancel` (descartar) | Admin-only. Reenvio em massa e cancelamento em massa são ações irreversíveis: mostre as contagens do summary e confirme (seção 7a/7b). Numa mensagem só: `lionchat_conversations_messages_create_1` (reenviar) / `lionchat_conversations_messages_cancel_retry` (cancelar) |
|
|
354
374
|
| **Definir supervisor** de caixa | `lionchat_inbox_members_create` / `_update` com `supervisor_ids[]` | Supervisor vê TUDO da caixa mas fica fora do rodízio (ver abaixo) |
|
|
375
|
+
| **Definir supervisor** de time | `lionchat_team_members_create` / `_update` com `supervisor_ids[]` | Contrato diferente do da caixa: `user_ids[]` é a lista COMPLETA e `supervisor_ids[]` um subconjunto dela. Omitir `supervisor_ids` não mexe em papel nenhum (seção 2) |
|
|
376
|
+
| **Mudar a fila do time** (teto por atendente, janela, online/offline) | `lionchat_teams_update` (`assignment_mode`, `fair_distribution_limit`, `fair_distribution_window`) | Time tem PREFERÊNCIA sobre a caixa na distribuição. Leia a config atual antes de mudar (ver `lionchat://docs/conversation-flows`) |
|
|
377
|
+
| **Migrar conversas** de uma caixa WhatsApp pra outra (ex.: QR Code → Oficial) | `lionchat_inboxes_inbox_migration_list` (prévia) → `_execute` → acompanhar status | Admin-only e IRREVERSÍVEL: sempre mostre os números da prévia e confirme (seção 7a). Grupos não vão pro canal oficial — ficam na caixa de origem |
|
|
355
378
|
| Qualquer coisa de Ligação WP (Wavoip) | **NÃO HÁ TOOL** — removidas em 2026-07-16 por decisão do dono | Ligação WP é contratada e configurada **manualmente pelo cliente no painel**. O MCP não conecta, não desconecta, não entrega token de discagem nem muda config. Oriente o usuário a fazer pelo painel (Configurações da caixa → Ligação WP). |
|
|
356
379
|
| Restringir agendas que a IA oferece | `lionchat_captain_assistants_update` (`config.booking_event_type_ids: [Int]`) | binding de agenda por cenário NÃO é settable via API |
|
|
357
380
|
| Configurar o Copiloto (modelo/temperatura/prompt base) | `lionchat_copilot_settings_update` | admin-only; copiloto tem motor próprio (padrão temp 0.3) |
|
|
@@ -247,6 +247,24 @@ pula o follow-up). Tipos:
|
|
|
247
247
|
(não empurra pra frente — evita disparo em massa na abertura); a cadência segue nos passos seguintes.
|
|
248
248
|
`start == end` = janela inválida (ignorada). Ideal pra não incomodar cliente de madrugada.
|
|
249
249
|
|
|
250
|
+
## Follow-up fora da janela de 24h usa TEMPLATE (novo 2026-07-30)
|
|
251
|
+
|
|
252
|
+
Em caixa **WhatsApp oficial**, passadas 24h da última mensagem do cliente, a Meta recusa qualquer texto
|
|
253
|
+
escrito pela IA. Até 30/07 o follow-up nem perguntava: escrevia, o canal recusava e sobrava um balão
|
|
254
|
+
vermelho com o erro enganoso "Template not found or invalid template name" (392 balões assim num único
|
|
255
|
+
dia numa conta). Agora o gerador de follow-up recebe os modelos aprovados da caixa ANTES de escrever e
|
|
256
|
+
escolhe um deles quando a janela está fechada.
|
|
257
|
+
|
|
258
|
+
O que isso significa na prática, pra explicar ao cliente:
|
|
259
|
+
- **Conta em caixa oficial que quer follow-up depois de 24h PRECISA ter template aprovado na Meta.**
|
|
260
|
+
Sem nenhum template, não há como falar fora da janela — não é limitação da plataforma, é regra da Meta.
|
|
261
|
+
- **Mandar template não reabre a janela.** Só a resposta do cliente reabre. Um follow-up por template
|
|
262
|
+
pode ser respondido — e é a resposta dele que libera texto livre de novo.
|
|
263
|
+
- **Trava anti-repetição:** modelo já enviado naquele ciclo de follow-up sai da lista. Numa conta com um
|
|
264
|
+
único template (normalmente o mesmo da campanha), sem essa trava o cliente receberia minutos depois o
|
|
265
|
+
mesmo texto que acabou de ler.
|
|
266
|
+
- Dentro da janela nada muda: o follow-up continua sendo texto livre, escrito pela IA.
|
|
267
|
+
|
|
250
268
|
## Desligar a IA quando um humano assume (2026-07)
|
|
251
269
|
|
|
252
270
|
`config.feature_pause_on_human_reply` (bool, padrão false). Ligado, a IA **se desliga sozinha** na
|
|
@@ -379,6 +397,17 @@ o `exclusion` (e o `audience_mode`) vão TOP-LEVEL; ao CRIAR/EDITAR a campanha e
|
|
|
379
397
|
`{assignee_id, priority, labels}`: `contact_labels: []` (aplica etiqueta ao CONTATO que recebeu) e
|
|
380
398
|
`attribute_changes: [{scope:'contact'|'conversation', key, value}]` (grava/sobrescreve atributo de quem recebeu).
|
|
381
399
|
|
|
400
|
+
**Público por PLANILHA (novo 2026-07-31):** o painel passou a aceitar CSV/XLS como público do disparo,
|
|
401
|
+
nas três abas de campanha. **Não existe tipo novo de público** — a importação marca os contatos da
|
|
402
|
+
planilha com uma **etiqueta de contato** e/ou um **atributo de contato**, e a campanha usa os tipos que
|
|
403
|
+
já existiam (`ContactLabel` / `ContactAttribute`).
|
|
404
|
+
|
|
405
|
+
Ou seja: **dá pra reproduzir pela API.** Importe os contatos aplicando uma marca própria da lista (ex.:
|
|
406
|
+
etiqueta `lista-black-friday`) e monte o `audience` com `{"type": "ContactLabel", "id": <id>}`. Se o
|
|
407
|
+
cliente pedir "disparar pra essa planilha", esse é o caminho. A marcação em lote é feita em silêncio
|
|
408
|
+
(sem callback nem evento), então importar uma lista grande **não acorda automação nem fluxo** — foi
|
|
409
|
+
desenhada assim de propósito, pra não repetir a tempestade de eventos de 29/07.
|
|
410
|
+
|
|
382
411
|
SEMPRE rode `campaigns_estimate_audience` com o MESMO audience + audience_mode + exclusion antes de
|
|
383
412
|
criar a campanha e mostre a contagem ao usuário — estimativa e disparo usam o mesmo motor (não divergem).
|
|
384
413
|
|
|
@@ -399,6 +428,12 @@ Pra dados fixos que se repetem (slogans, endereços, horários):
|
|
|
399
428
|
- Resolve em: mensagens, respostas prontas, campanhas e automações. NÃO resolve nas instruções do AI Agente (base/cenário) — ali só `contact.*` e `conversation.*`.
|
|
400
429
|
- `secret` nunca aparece em template (sai vazio); só resolve em nós API Request do FlowBuilder.
|
|
401
430
|
- Atualiza UMA vez, propaga pra todo lugar.
|
|
431
|
+
- **Teto de 32 KB por variável (novo 01/08/2026).** Valor maior que isso é recusado com HTTP 422. É por
|
|
432
|
+
VARIÁVEL, não pela soma — conta com dezenas de tokens legítimos (uma delas tem 23 tokens de
|
|
433
|
+
integração) não é punida. A maior variável legítima medida na plataforma tem 348 bytes, então o teto
|
|
434
|
+
dá ~90x de folga: cabe qualquer token, URL, endereço ou texto de configuração; **não** cabe base de
|
|
435
|
+
dados, JSON gigante nem script. Se o cliente quiser guardar algo desse tamanho, o lugar é um arquivo
|
|
436
|
+
ou uma integração, não uma Variável de Conta.
|
|
402
437
|
|
|
403
438
|
Nunca hard-code esses dados em respostas geradas.
|
|
404
439
|
|
|
@@ -131,6 +131,42 @@ Regra prática:
|
|
|
131
131
|
Quem entra no rodízio: só `inbox_members` com `auto_assignable: true` (supervisor de caixa fica de
|
|
132
132
|
fora) e, se "distribuir para agentes offline" estiver desligado, só quem está online.
|
|
133
133
|
|
|
134
|
+
### A fila do TIME tem preferência sobre a da caixa (novo 2026-07-31)
|
|
135
|
+
|
|
136
|
+
Existe um TERCEIRO nível de distribuição, e ele vem ANTES dos dois de cima. A regra, por conversa:
|
|
137
|
+
|
|
138
|
+
> **conversa está num time que distribui → manda o TIME (quem entra e qual o teto).
|
|
139
|
+
> Senão → cai pra caixa/política, exatamente como antes.**
|
|
140
|
+
|
|
141
|
+
Decisão do dono: **time tem preferência, caixa é reserva.** O time decide QUEM e QUANTO; a
|
|
142
|
+
caixa/política continua decidindo a ORDEM da fila, as exclusões e a capacidade por atendente.
|
|
143
|
+
|
|
144
|
+
Campos do time (tools `lionchat_teams_create` / `_update`):
|
|
145
|
+
|
|
146
|
+
| Campo | O que faz | Padrão |
|
|
147
|
+
|---|---|---|
|
|
148
|
+
| `allow_auto_assign` | liga/desliga a distribuição do time | `true` |
|
|
149
|
+
| `assignment_mode` | `online_only` (só quem está online) ou `include_offline` (todo mundo do time) | `online_only` |
|
|
150
|
+
| `fair_distribution_limit` | teto de conversas por atendente na janela | `10` |
|
|
151
|
+
| `fair_distribution_window` | tamanho da janela, **em segundos** | `600` |
|
|
152
|
+
|
|
153
|
+
Quem entra no bolo do time: membros com `auto_assignable: true` (supervisor de time fica de fora)
|
|
154
|
+
**que também sejam membros da caixa** — quem não é da caixa nunca entra, senão a conversa cairia com
|
|
155
|
+
alguém que nem enxerga aquela caixa.
|
|
156
|
+
|
|
157
|
+
Antes de 31/07 o time sorteava UMA vez, no instante em que a conversa caía nele; não achando ninguém
|
|
158
|
+
disponível, desistia PARA SEMPRE e a conversa ficava aberta sem dono. Agora a mesma varredura que já
|
|
159
|
+
existia para a caixa reprocessa a fila do time. Se o cliente reclamar de "conversas com time e sem
|
|
160
|
+
dono" de antes dessa data, a causa é essa — e já está corrigida.
|
|
161
|
+
|
|
162
|
+
**LEIA o valor do time antes de responder** — a resposta de `lionchat_teams_list` / `_show` traz os
|
|
163
|
+
quatro campos. Como em toda configuração, nunca recite o padrão de fábrica como se fosse o que o
|
|
164
|
+
cliente configurou: cite o número que a API devolveu.
|
|
165
|
+
|
|
166
|
+
> Nota de compatibilidade: `fair_distribution_limit` e `fair_distribution_window` só passaram a sair
|
|
167
|
+
> na resposta em **03/08/2026**. Se vierem ausentes, a instalação é anterior a essa data — nesse caso
|
|
168
|
+
> não afirme o valor, mande conferir em Configurações → Times → editar o time.
|
|
169
|
+
|
|
134
170
|
**LEIA o valor da conta antes de responder — NUNCA recite um número de cabeça.** Os valores reais
|
|
135
171
|
vêm na resposta da API:
|
|
136
172
|
- `has_assignment_policy` (resposta da caixa) diz QUAL dos dois caminhos vale ali. `true` = política
|
|
@@ -266,6 +302,41 @@ Conversation
|
|
|
266
302
|
2. Tem SLA policy ativando state change?
|
|
267
303
|
3. Veio de external API call?
|
|
268
304
|
|
|
305
|
+
## Pesquisa de satisfação (CSAT) — vale em TODO canal (corrigido 2026-07-31)
|
|
306
|
+
|
|
307
|
+
A pesquisa de satisfação é enviada **dentro da própria conversa** (modo `in_chat`) em **todos os
|
|
308
|
+
canais** — WhatsApp, Telegram, Instagram, SMS, site. O backend sempre funcionou assim; era a TELA que
|
|
309
|
+
só mostrava a configuração quando a caixa era WhatsApp, então de 01/04 a 31/07 quem usava outro canal
|
|
310
|
+
via a aba quase vazia e herdava um texto padrão que não conseguia editar. Hoje a configuração aparece
|
|
311
|
+
igual pra todos.
|
|
312
|
+
|
|
313
|
+
Duas coisas pra não errar ao explicar:
|
|
314
|
+
- **A regra de etiqueta (`survey_rules`) agora é respeitada de verdade.** Ela aparecia na tela e era
|
|
315
|
+
IGNORADA no envio — a pesquisa saía pra todo mundo. Se o cliente configurou "só enviar quando a
|
|
316
|
+
conversa tem a etiqueta X" antes de 31/07 e reclamou que ia pra todos, a causa era essa e já está
|
|
317
|
+
corrigida.
|
|
318
|
+
- **Caixa que nunca teve a aba salva** pode continuar sem `csat_mode` gravado e cair no caminho antigo.
|
|
319
|
+
Se duas caixas iguais se comportarem diferente, mande abrir a aba de Pesquisa de Satisfação e salvar
|
|
320
|
+
uma vez.
|
|
321
|
+
|
|
322
|
+
## Migrar conversas entre caixas de WhatsApp (2026-08-01)
|
|
323
|
+
|
|
324
|
+
Serve pra quem está saindo do WhatsApp por QR Code e indo pro Oficial (ou trocando de número): leva as
|
|
325
|
+
conversas e os contatos da caixa antiga pra nova. Tools: `lionchat_inboxes_inbox_migration_list`
|
|
326
|
+
(prévia), `_execute` (executa) e o acompanhamento de status. **Admin-only e irreversível** — mostre os
|
|
327
|
+
números da prévia e confirme antes.
|
|
328
|
+
|
|
329
|
+
O que a prévia devolve (e o que ela conta): a contagem é de **CONVERSAS**, dividida em migráveis,
|
|
330
|
+
conflitantes e não-migráveis; contato sem conversa é ignorado, e os baldes fecham com o total.
|
|
331
|
+
|
|
332
|
+
**Regras que mudam o resultado — diga ao cliente ANTES de executar:**
|
|
333
|
+
- **Grupos não vão pro canal Oficial.** A Meta não tem grupos: conversa de grupo (`@g.us`), lista de
|
|
334
|
+
transmissão e canal ficam na caixa de ORIGEM e aparecem contados como pulados. Não é falha.
|
|
335
|
+
- QR Code → Oficial passou a funcionar de verdade em 01/08. Antes a migração falhava — em uma conta
|
|
336
|
+
gravou "0 migradas" por causa de um grupo, e na prática teria falhado em 100% dos contatos, porque o
|
|
337
|
+
formato de identificador do QR Code não estava sendo convertido. Se o cliente tentou migrar antes
|
|
338
|
+
dessa data e não deu certo, mande tentar de novo.
|
|
339
|
+
|
|
269
340
|
## Receitas de ação (qual tool usar pra cada coisa)
|
|
270
341
|
|
|
271
342
|
### ENVIAR MENSAGEM (`conversations_messages_create`)
|
|
@@ -420,6 +491,154 @@ POST /api/v1/accounts/{account_id}/automation_rules
|
|
|
420
491
|
"event_name": "conversation_updated",
|
|
421
492
|
"action_types": ["label_added"],
|
|
422
493
|
"conditions": [{"attribute_key": "labels", "filter_operator": "contains", "values": ["vip"]}],
|
|
423
|
-
"actions": [{"action_name": "send_email_to_team", "action_params": {"team_ids": [1], "message": "VIP!"}}]
|
|
494
|
+
"actions": [{"action_name": "send_email_to_team", "action_params": [{"team_ids": [1], "message": "VIP!"}]}]
|
|
495
|
+
}
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## Condicoes de automacao — e a REGRA DO CONECTOR
|
|
501
|
+
|
|
502
|
+
```json
|
|
503
|
+
"conditions": [
|
|
504
|
+
{"attribute_key": "status", "filter_operator": "equal_to", "values": ["resolved"], "query_operator": "AND"},
|
|
505
|
+
{"attribute_key": "labels", "filter_operator": "equal_to", "values": ["vip"], "query_operator": null}
|
|
506
|
+
]
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### O conector (`query_operator`) — leia isto antes de gravar
|
|
510
|
+
|
|
511
|
+
O conector **liga a condicao com a SEGUINTE**. Logo:
|
|
512
|
+
|
|
513
|
+
- A **ULTIMA** condicao **TEM** que ter `query_operator: null`.
|
|
514
|
+
- Condicao **UNICA** = `query_operator: null` (nao ha proxima pra ligar).
|
|
515
|
+
- Valores aceitos nas demais: `"AND"` ou `"OR"`.
|
|
516
|
+
|
|
517
|
+
> **A API valida o VALOR do conector, mas NAO a POSICAO.** Conector na ultima condicao **salva com
|
|
518
|
+
> sucesso**, aparece certo na tela — e a regra nunca dispara.
|
|
519
|
+
>
|
|
520
|
+
> Incidente real: **8 regras criadas pelo conector de IA entre 26 e 30/07/2026, em 3 contas
|
|
521
|
+
> diferentes, todas com conector na ultima condicao. Todas nasceram mortas.** A pergunta ao banco
|
|
522
|
+
> saia pela metade (`... IN ($1) and`), o erro era engolido e a regra respondia "nada casou". A conta
|
|
523
|
+
> 62 ficou com as **6** regras de etiquetagem automatica paradas. Medido em producao em 03/08:
|
|
524
|
+
> **732 erros por hora**.
|
|
525
|
+
>
|
|
526
|
+
> O motor foi corrigido em 03/08 (a limpeza acontece ao montar a consulta), entao regra torta nao
|
|
527
|
+
> quebra mais. **Mas continue gravando certo:** a tela de edicao le o dado cru e formato errado
|
|
528
|
+
> aparece estranho ali — mesmo efeito do campo de template que sumia da tela.
|
|
529
|
+
|
|
530
|
+
### Campos da condicao
|
|
531
|
+
|
|
532
|
+
| Campo | Obrigatorio | O que e |
|
|
533
|
+
|---|---|---|
|
|
534
|
+
| `attribute_key` | SIM | Campo padrao (ver abaixo) ou a chave de um atributo personalizado que **exista na conta** |
|
|
535
|
+
| `filter_operator` | SIM | Como comparar |
|
|
536
|
+
| `values` | SIM (menos em `is_present`/`is_not_present`) | Array, sempre |
|
|
537
|
+
| `query_operator` | SIM em todas | `"AND"`/`"OR"`; **`null` na ultima** |
|
|
538
|
+
| `custom_attribute_type` | so p/ atributo personalizado | `conversation_attribute` ou `contact_attribute` |
|
|
539
|
+
|
|
540
|
+
### Operadores de filtro
|
|
541
|
+
|
|
542
|
+
`equal_to`, `not_equal_to`, `contains`, `does_not_contain`, `is_present`, `is_not_present`,
|
|
543
|
+
`is_greater_than`, `is_less_than`, `starts_with`, `days_before`, `days_ago`, `last_days`, `today`,
|
|
544
|
+
`yesterday`.
|
|
545
|
+
|
|
546
|
+
**Cada campo aceita so um subconjunto.** Operador que o campo nao aceita faz a regra inteira falhar
|
|
547
|
+
na validacao. Na duvida, leia uma regra que ja funciona com `lionchat_automation_rules_show` e copie.
|
|
548
|
+
|
|
549
|
+
### Chave que a conta nao conhece
|
|
550
|
+
|
|
551
|
+
Se `attribute_key` nao for um campo padrao **nem** um atributo personalizado existente na conta, a
|
|
552
|
+
regra **inteira** falha na validacao e nunca dispara — erro
|
|
553
|
+
`Automation conditions <chave> not supported`. Aconteceu de verdade na conta 62 (`tipo_interesse`).
|
|
554
|
+
Antes de usar atributo personalizado numa condicao, confirme que ele existe com
|
|
555
|
+
`lionchat_custom_attributes_list`.
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
## Acoes de automacao — formato do `action_params`
|
|
560
|
+
|
|
561
|
+
> **REGRA DE OURO:** `action_params` e SEMPRE um **array**, mesmo quando so tem um item.
|
|
562
|
+
> O backend le `params[0]`. Passar um objeto solto (`{...}` em vez de `[{...}]`) quebra a acao.
|
|
563
|
+
|
|
564
|
+
> **PERIGO — falha silenciosa:** o `action_params` e um campo livre (JSONB). A API **aceita e grava
|
|
565
|
+
> qualquer formato**, sem validar. Se as chaves estiverem erradas, a regra e salva com sucesso, o
|
|
566
|
+
> painel mostra a acao na tela, e na hora de disparar ela **nao faz nada e nao registra erro nenhum**
|
|
567
|
+
> — sem log, sem mensagem falhada, sem aviso. Por isso: **nunca invente nome de chave**. Se a acao
|
|
568
|
+
> nao estiver documentada abaixo, leia uma regra existente com `lionchat_automation_rules_show` e
|
|
569
|
+
> copie o formato exato dela.
|
|
570
|
+
>
|
|
571
|
+
> Incidente real (conta 39, 02-03/08/2026): uma IA gravou `template_name`/`template_id` em vez de
|
|
572
|
+
> `name`/`id`. A regra ficou 14 horas sem enviar nada, 9 leads pagos entraram e ninguem foi avisado.
|
|
573
|
+
|
|
574
|
+
### `send_whatsapp_template` — ATENCAO ESPECIAL
|
|
575
|
+
|
|
576
|
+
Envia um modelo aprovado da Meta. **So funciona em caixa WhatsApp API Oficial (Cloud).**
|
|
577
|
+
|
|
578
|
+
```json
|
|
579
|
+
{
|
|
580
|
+
"action_name": "send_whatsapp_template",
|
|
581
|
+
"action_params": [{
|
|
582
|
+
"name": "confirmacao_pedido",
|
|
583
|
+
"id": "1071396275361941",
|
|
584
|
+
"language": "pt_BR",
|
|
585
|
+
"category": "UTILITY",
|
|
586
|
+
"processed_params": {"body": {"1": "{{contact.first_name}}"}}
|
|
587
|
+
}]
|
|
424
588
|
}
|
|
425
589
|
```
|
|
590
|
+
|
|
591
|
+
| Chave | Obrigatoria | O que e |
|
|
592
|
+
|---|---|---|
|
|
593
|
+
| `name` | **SIM** | Nome EXATO do modelo aprovado na Meta. E por ele que o envio acontece |
|
|
594
|
+
| `id` | nao | ID do modelo na Meta. Serve so de reserva se `name` faltar |
|
|
595
|
+
| `language` | nao (padrao `pt_BR`) | Precisa bater com o idioma do modelo aprovado |
|
|
596
|
+
| `category` | nao | `UTILITY`, `MARKETING` ou `AUTHENTICATION` |
|
|
597
|
+
| `processed_params` | nao | Valores das variaveis: `{"body": {"1": "...", "2": "..."}}`. Aceita Liquid (`{{contact.first_name}}`) |
|
|
598
|
+
|
|
599
|
+
**NUNCA use `template_name`, `template_id`, `template_category` nem `template_language` aqui.**
|
|
600
|
+
Esse e o formato dos **nos do FlowBuilder**, que e outra coisa. Na automacao, essas chaves sao
|
|
601
|
+
ignoradas e a acao vira um nada silencioso.
|
|
602
|
+
|
|
603
|
+
Antes de gravar, confirme que o modelo existe e esta aprovado com
|
|
604
|
+
`lionchat_inboxes_whatsapp_templates_list` — o envio so acha o modelo se `name` + `language`
|
|
605
|
+
casarem e o status for `approved`.
|
|
606
|
+
|
|
607
|
+
### Demais acoes
|
|
608
|
+
|
|
609
|
+
Todos os formatos abaixo foram conferidos linha a linha em `app/services/action_service.rb` e
|
|
610
|
+
`app/services/automation_rules/action_service.rb`.
|
|
611
|
+
|
|
612
|
+
| `action_name` | `action_params` |
|
|
613
|
+
|---|---|
|
|
614
|
+
| `send_message` | `["texto da mensagem"]` |
|
|
615
|
+
| `add_private_note` | `["nota interna"]` |
|
|
616
|
+
| `send_canned_response` | `[12]` — id da resposta pronta |
|
|
617
|
+
| `add_label` / `remove_label` | `["etiqueta1", "etiqueta2"]` |
|
|
618
|
+
| `assign_agent` | `[70]` — o agente precisa ser membro da caixa. `["nil"]` desatribui |
|
|
619
|
+
| `assign_team` | `[3]`. `["nil"]` desatribui |
|
|
620
|
+
| `assign_captain_assistant` | `[17]` ou `[{"assistant_id": 17, "proactive": true}]` — `proactive` false = a IA assume mas nao fala na hora |
|
|
621
|
+
| `send_email_to_team` | `[{"team_ids": [1], "message": "texto"}]` |
|
|
622
|
+
| `send_webhook_event` | `["https://..."]` |
|
|
623
|
+
| `send_attachment` | `[blob_ids]` — so funciona se a regra ja tiver arquivo anexado; nao da pra montar so por API |
|
|
624
|
+
| `change_status` | `["resolved"]`, `["open"]`, `["pending"]` ou `["snoozed"]` |
|
|
625
|
+
| `change_priority` | `["urgent"]`, `["high"]`, `["medium"]`, `["low"]`. `["nil"]` limpa |
|
|
626
|
+
| `send_email_transcript` | `["a@b.com,c@d.com"]` — UMA string, varios e-mails separados por virgula |
|
|
627
|
+
| `mute_conversation` | `[]` |
|
|
628
|
+
| `snooze_conversation` | `[]` |
|
|
629
|
+
| `resolve_conversation` / `open_conversation` / `pending_conversation` | `[]` |
|
|
630
|
+
| `update_contact_attribute` / `update_conversation_attribute` | `[{"attribute_key": "chave", "value": "texto ou {{contact.phone_number}}"}]` |
|
|
631
|
+
| `create_kanban_item` | `[{"funnel_id": 31, "funnel_stage": "prospeccao", "allow_duplicates": false}]` |
|
|
632
|
+
| `move_kanban_item_to_stage` | `[{"funnel_id": 31, "funnel_stage": "qualificacao"}]` |
|
|
633
|
+
| `assign_agent_to_kanban_item` | `[{"funnel_id": 31, "agent_id": 70, "mode": "add"}]` — `mode` aceita `add` (padrao) ou `remove_all` |
|
|
634
|
+
| `add_note_to_kanban_item` | `[{"funnel_id": 31, "text": "texto da nota"}]` — a chave e **`text`**, nao `note` |
|
|
635
|
+
| `set_kanban_item_status` | `[{"funnel_id": 31, "status": "won"}]` — `won`, `lost` ou `open`. Status fora disso e ignorado |
|
|
636
|
+
| `start_kanban_item_timer` / `stop_kanban_item_timer` | `[{"funnel_id": 31}]` |
|
|
637
|
+
|
|
638
|
+
**Acoes de Kanban:** todas precisam que a conversa ja tenha um card no funil informado. Sem card,
|
|
639
|
+
a acao e pulada (fica so no log do servidor). Use `create_kanban_item` antes, na mesma regra.
|
|
640
|
+
|
|
641
|
+
Lista autoritativa de nomes validos: `AutomationRule#actions_attributes` no backend. Nome de acao
|
|
642
|
+
fora dessa lista e recusado com 422 ao salvar — isso a API valida. O que ela **nao** valida e o
|
|
643
|
+
conteudo do `action_params`. `apply_kanban_checklist_template` existe no motor mas **nao** e uma
|
|
644
|
+
acao de automacao valida (e so do FlowBuilder) — usar aqui devolve 422.
|
|
@@ -396,11 +396,12 @@ Booking (agendamento confirmado)
|
|
|
396
396
|
|
|
397
397
|
## e-Clínicas (Efficient) — integração de clínicas
|
|
398
398
|
|
|
399
|
-
|
|
399
|
+
13 eventos de webhook, cada um mapeável a automação OU flow na tela Integrações > e-Clínica:
|
|
400
400
|
`cliente_novo`, `agendamento_novo`, `falta`, `pagamento` (os 4 da doc oficial) +
|
|
401
401
|
`agendamento_atendido`, `agendamento_alterado`, `agendamento_desmarcado`,
|
|
402
|
-
`agendamento_transferido`, `cliente_baixa_pagamento`
|
|
403
|
-
|
|
402
|
+
`agendamento_transferido`, `cliente_baixa_pagamento`, `cliente_alteracao`,
|
|
403
|
+
`cliente_inclusao_pagamento`, `controle_laboratorio_novo`, `controle_laboratorio_alterado`
|
|
404
|
+
(capturados ao vivo, não documentados pelo e-Clínica).
|
|
404
405
|
|
|
405
406
|
Atributos de sistema no CONTATO (prefixo `eclinica_`, protegidos, usáveis como variável):
|
|
406
407
|
|
|
@@ -29,13 +29,44 @@ E/OU é encadeado condição a condição (sem parênteses).
|
|
|
29
29
|
| `display_id` | equal_to, not_equal_to, contains, does_not_contain (o `contains`, busca por trecho do número, passou a funcionar de verdade em 2026-07-25 — antes dava erro de banco) |
|
|
30
30
|
| `referer`, `mail_subject` | equal_to, not_equal_to, contains, does_not_contain |
|
|
31
31
|
| `browser_language`, `conversation_language` | equal_to, not_equal_to |
|
|
32
|
-
| `created_at`, `last_activity_at` (valor = data) | is_greater_than, is_less_than, days_before |
|
|
32
|
+
| `created_at`, `last_activity_at` (valor = data) | is_greater_than, is_less_than, days_before + relativos `today`, `yesterday`, `last_days`, `days_ago` (novo 01/08 — ver abaixo) |
|
|
33
33
|
| `card_funnel_stage` (conversa POR CARD do Kanban — valor `funnel:<id>` ou `stage:<id>:<chave_etapa>`) | equal_to, not_equal_to |
|
|
34
34
|
| **qualquer outra chave** = atributo personalizado | conforme o tipo do atributo (ver tabela em api-conventions) |
|
|
35
35
|
|
|
36
36
|
Atributo personalizado: informe `custom_attribute_type` na condição — `'conversation_attribute'`
|
|
37
37
|
(atributo da conversa) ou `'contact_attribute'`. Sem ele o escopo pode sair errado.
|
|
38
38
|
|
|
39
|
+
### Data relativa — "Hoje", "Ontem", "últimos X dias" (novo 2026-08-01)
|
|
40
|
+
|
|
41
|
+
Não calcule data no seu lado pra perguntar "quantas conversas entraram hoje". Existem operadores
|
|
42
|
+
próprios, e eles resolvem tudo em **dias INTEIROS no fuso da CONTA** (`Account#timezone`, padrão
|
|
43
|
+
`America/Sao_Paulo`). Valem em `created_at` e `last_activity_at`, tanto em
|
|
44
|
+
`lionchat_conversations_filter` quanto em `lionchat_contacts_filter`.
|
|
45
|
+
|
|
46
|
+
| Operador | Valor | Janela |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `today` | **nenhum** | hoje, 00:00 → 23:59 |
|
|
49
|
+
| `yesterday` | **nenhum** | ontem, 00:00 → 23:59 |
|
|
50
|
+
| `last_days` | `values: [N]` | últimos N dias **incluindo hoje** (N=7 → de 6 dias atrás 00:00 até hoje 23:59) |
|
|
51
|
+
| `days_ago` | `values: [N]` | o dia EXATO de N dias atrás (um dia só, não um intervalo) |
|
|
52
|
+
| `days_before` | `values: [N]` | tudo **mais antigo** que N dias atrás (o comportamento que já existia) |
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{ "attribute_key": "created_at", "filter_operator": "today", "values": [], "query_operator": null }
|
|
56
|
+
{ "attribute_key": "created_at", "filter_operator": "last_days", "values": [7], "query_operator": null }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Regras que derrubam a chamada se ignoradas:**
|
|
60
|
+
- `today` e `yesterday` NÃO levam valor — o servidor nem espera o campo.
|
|
61
|
+
- Nos outros três, N tem que ser inteiro entre **1 e 998**. Zero, negativo, texto ou vazio = HTTP 422
|
|
62
|
+
(`InvalidValue`). Não existe `last_days: 0` pra dizer "hoje" — pra hoje use `today`.
|
|
63
|
+
- `is_greater_than` / `is_less_than` continuam sendo o caminho da data FIXA (`values: ["2026-08-01"]`).
|
|
64
|
+
Use-os quando o cliente citou um dia específico; use os relativos quando ele disse "hoje", "ontem"
|
|
65
|
+
ou "últimos X dias".
|
|
66
|
+
|
|
67
|
+
Por que mudou: até 01/08 a borda do dia era montada em UTC, o que errava **3 horas** no Brasil —
|
|
68
|
+
conversa criada às 22h aparecia no dia seguinte. Agora a borda é a do fuso da conta.
|
|
69
|
+
|
|
39
70
|
## 2. Contatos — `lionchat_contacts_filter`
|
|
40
71
|
|
|
41
72
|
Mesmo shape de condição. 15/página.
|
|
@@ -186,6 +186,13 @@ Webhooks embutidos NÃO aparecem na listagem de integrações standalone; exclui
|
|
|
186
186
|
- `title` = texto **EXATO** do botão quick-reply aprovado na Meta (o WhatsApp devolve o TÍTULO no clique; o match é por ele). `value` = slug do título (deduplicado se dois títulos colidem).
|
|
187
187
|
- Handles: `button_<value>` por botão + `no_response` (sempre — texto livre em vez de clique) + `no_reply_timeout` (só com `buttons_timeout > 0`; `buttons_timeout_unit` `minutes|hours|days`; `0` = sem timeout).
|
|
188
188
|
- Modo síncrono (`ai_tool`) e `dry_run` NÃO pausam/roteiam — o template só é enviado (botões decorativos). Só faz sentido em caixa WhatsApp com template de botões aprovado.
|
|
189
|
+
- **O item guarda uma FOTO do template** (corpo + botões) tirada quando foi configurado. Se o modelo for
|
|
190
|
+
alterado na Meta depois disso, a foto envelhece: até 2026-07-30 a atualização automática ao reabrir o
|
|
191
|
+
bloco comparava só o CORPO, então mudança APENAS de botão passava batido — a tela mostrava os botões
|
|
192
|
+
novos (ela lê o modelo vivo) e o flow continuava roteando pelos ANTIGOS. Caso real: um botão renomeado
|
|
193
|
+
fazia todo mundo cair em "outra resposta". Hoje corpo E botões são comparados. **Se você mudou os
|
|
194
|
+
botões de um template na Meta, avise que é preciso reabrir o bloco e RELIGAR a saída renomeada** — a
|
|
195
|
+
aresta do botão antigo é removida junto.
|
|
189
196
|
|
|
190
197
|
> ⚠️ **SAÍDAS CONDICIONAIS — NUNCA ligue edge nelas sem ativar a condição.** Estas saídas SÓ existem
|
|
191
198
|
> quando a config abaixo está presente. Ligar edge nelas sem isso cria uma **aresta fantasma** (linha
|
|
@@ -269,6 +276,13 @@ No editor visual esses destinos só aparecem quando a validação bate (computed
|
|
|
269
276
|
|
|
270
277
|
**REGRA:** depois de wait_response com `options` OU `varied_options`, NUNCA coloque node `condition` pra ramificar — ligue os edges direto nos handles `option_X` (em `varied_options`, `X` é o `id` do grupo).
|
|
271
278
|
|
|
279
|
+
**Node que NÃO salva também avança (corrigido 2026-08-01):** até essa data, o avanço do `wait_response`
|
|
280
|
+
dependia de ter uma variável configurada — com `saveTo: ""` o node RECEBIA a resposta e reentrava em si
|
|
281
|
+
mesmo, e quem respondia no prazo acabava saindo pelo caminho de `timeout`. Sintoma que o cliente
|
|
282
|
+
relatava: "mando a mensagem e o fluxo trava em aguardando resposta". Hoje o node avança sempre; salvar
|
|
283
|
+
o valor é opcional de novo, como o schema sempre prometeu. Se um flow antigo tiver ganhado uma variável
|
|
284
|
+
só pra destravar, ela pode sair.
|
|
285
|
+
|
|
272
286
|
### 2.4 `condition`
|
|
273
287
|
|
|
274
288
|
```json
|
|
@@ -325,7 +339,8 @@ No editor visual esses destinos só aparecem quando a validação bate (computed
|
|
|
325
339
|
| `equal_any` / `not_equal_any` / `contains_any` / `not_contains_any` | multi-valor (usa `values` array). `contains_any` = contém ALGUMA; `not_contains_any` = não contém NENHUMA (útil pra "seguir só quando a msg não tem nenhuma das palavras-chave de outros flows") |
|
|
326
340
|
| `business_hours` / `outside_business_hours` | horário comercial (par: dentro/fora). `business_hours` aceita `start_hour`/`end_hour` (0-23), `days` (array 0=Dom..6=Sab, ausente=todos) e **`timezone`** (IANA, ex.: `America/Sao_Paulo` — default se ausente). **REGRA:** a saída `outside_business_hours` HERDA `start_hour`/`end_hour`/`days`/`timezone` da `business_hours` ANTERIOR no array — pode deixá-los ausentes na "fora" (o backend preenche). O horário é avaliado no `timezone` (não em UTC) |
|
|
327
341
|
| `can_reply` / `can_reply_closed` | janela 24h aberta/fechada |
|
|
328
|
-
| `conversation_has_agent` / `conversation_no_agent` / `conversation_not_agent` | agente atribuído |
|
|
342
|
+
| `conversation_has_agent` / `conversation_no_agent` / `conversation_not_agent` | agente atribuído (HUMANO) |
|
|
343
|
+
| `conversation_has_ai_agent` / `conversation_no_ai_agent` / `conversation_not_ai_agent` | agente de IA atribuído (novo 2026-08-01) — ver abaixo |
|
|
329
344
|
| `contact_has_label` / `contact_no_label` / `conversation_has_label` / `conversation_no_label` | labels |
|
|
330
345
|
| `kanban_exists` / `kanban_in_stage` / `kanban_won` / `kanban_lost` | card no funil. `funnel_id` é CHAVE SEPARADA da condição (número, ex.: `"funnel_id": 37`). A etapa vai em `value` (slug puro da etapa, ex.: `"avaliacao_aceita"`) ou em `stage` — NÃO no formato `"37:etapa"`. Ex.: `{ "operator": "kanban_in_stage", "funnel_id": 37, "value": "avaliacao_aceita" }` |
|
|
331
346
|
| `card_attr_equals` / `card_attr_contains` | atributo do card (`attrSource: 'card'` + `attr_key`; aceita `card_source: 'trigger'` p/ ler o card que iniciou o flow) |
|
|
@@ -342,6 +357,22 @@ No editor visual esses destinos só aparecem quando a validação bate (computed
|
|
|
342
357
|
|
|
343
358
|
`greater_than`/`less_than` valem em atributo número (valor numérico) E temporais `date`/`time`/`datetime` (o backend detecta o formato do valor: instante > dia > minutos > número). `number_range` SÓ em número. Nunca use maior/menor em texto/lista.
|
|
344
359
|
|
|
360
|
+
**Agente de IA — `conversation_has_ai_agent` e irmãos (novo 2026-08-01):** o flow sempre soube LIGAR e
|
|
361
|
+
DESLIGAR a IA (ações `assign_captain` / `deactivate_captain`), mas não sabia PERGUNTAR se ela estava
|
|
362
|
+
ligada. Agora sabe. É o espelho exato do trio do agente humano:
|
|
363
|
+
|
|
364
|
+
| Forma | Verdadeiro quando |
|
|
365
|
+
|---|---|
|
|
366
|
+
| `{ "operator": "conversation_has_ai_agent" }` (sem valor) | tem QUALQUER IA atribuída |
|
|
367
|
+
| `{ "operator": "conversation_has_ai_agent", "values": [12, 15] }` | a IA atribuída é uma dessas |
|
|
368
|
+
| `{ "operator": "conversation_has_ai_agent", "value": 12 }` | a IA atribuída é exatamente essa |
|
|
369
|
+
| `{ "operator": "conversation_no_ai_agent" }` | não tem IA nenhuma |
|
|
370
|
+
| `{ "operator": "conversation_not_ai_agent", "values": [12] }` | tem IA, mas não é nenhuma dessas |
|
|
371
|
+
|
|
372
|
+
**Semântica (decisão do dono 01/08): reflete ATRIBUIÇÃO, não "vai responder agora".** Assistente
|
|
373
|
+
pausado no botão de pânico global continua contando como atribuído. Se o cliente perguntar "a IA está
|
|
374
|
+
respondendo?", essa condição NÃO responde isso — ela responde "a IA está ligada nesta conversa?".
|
|
375
|
+
|
|
345
376
|
**SLA — operador `sla_check` (2026-06):** verifica se a conversa está dentro/fora do prazo de SLA. A regra NÃO usa `field`, só `value` (código fixo):
|
|
346
377
|
|
|
347
378
|
| `value` | Verdadeiro quando |
|
|
@@ -813,6 +844,41 @@ continua servindo pra GRAVAR no contato). Teto: payload acima de 256KB não vira
|
|
|
813
844
|
disparado por OUTRO gatilho (mensagem, card, data): `{{webhook.*}}` resolve vazio. O autocomplete
|
|
814
845
|
do editor mostra o grupo WEBHOOK com os campos do último payload recebido.
|
|
815
846
|
|
|
847
|
+
**Variáveis do gatilho `{{trigger.*}}` (novo 2026-08-01):** todo flow — não importa o gatilho — passa
|
|
848
|
+
a saber O QUE o disparou. Antes só existia o tipo, e um flow com VÁRIOS gatilhos não tinha como se
|
|
849
|
+
ramificar por qual deles disparou. Agora dá: `{{trigger.type}}` num node `condition`.
|
|
850
|
+
|
|
851
|
+
Sempre presente:
|
|
852
|
+
|
|
853
|
+
| Variável | Conteúdo |
|
|
854
|
+
|---|---|
|
|
855
|
+
| `{{trigger.type}}` | chave do evento (`message_created`, `conversation_created`, `label_added`, `kanban_item_stage_changed`, `webhook_received`, `date_trigger`, `flow_campaign`, `manual`, `pagetrack_visited`…) |
|
|
856
|
+
| `{{trigger.name}}` | rótulo legível do MESMO evento ("Mensagem recebida", "Card mudou de etapa") — use este pra ESCREVER pro cliente, e o `type` pra COMPARAR em condição |
|
|
857
|
+
| `{{trigger.activated_at}}` | quando disparou (ISO 8601) |
|
|
858
|
+
| `{{trigger.kanban_item_id}}` / `{{trigger.funnel_id}}` | só quando veio do Kanban |
|
|
859
|
+
|
|
860
|
+
Presentes conforme o evento (ausente = resolve vazio, sem erro):
|
|
861
|
+
|
|
862
|
+
| Bloco | Campos |
|
|
863
|
+
|---|---|
|
|
864
|
+
| `{{trigger.message.*}}` | `id`, `content` (texto da mensagem, cortado em 2.000 caracteres), `type`, `created_at` |
|
|
865
|
+
| `{{trigger.conversation.*}}` | `id` (o display_id), `status`, `channel` (nome amigável: `Waha`, `Whatsapp`, `Instagram`), `inbox_id`, `inbox_name`, `created_at` |
|
|
866
|
+
| `{{trigger.contact.*}}` | `id`, `name`, `phone` |
|
|
867
|
+
| `{{trigger.ad.*}}` (anúncio/CTWA) | `id`, `name`, `creative_id`, `creative_name`, `adset_id`, `adset_name`, `campaign_id`, `campaign_name`, `source`, `headline`, `description`, `cta`, `url` |
|
|
868
|
+
| `{{trigger.attribute.*}}` | `name`, `previous_value`, `current_value`, `changed_at` — o valor ANTES e DEPOIS do atributo que disparou (só nos gatilhos de mudança de atributo) |
|
|
869
|
+
|
|
870
|
+
Dois atalhos: `{{trigger}}` devolve o contexto INTEIRO em JSON e `{{trigger.data}}` devolve o mesmo
|
|
871
|
+
sem os metadados — úteis pra jogar tudo dentro de um node `ai` ou `api`. Bloco (Hash/Array) inteiro
|
|
872
|
+
sai em JSON; valor simples sai cru.
|
|
873
|
+
|
|
874
|
+
**NÃO duplique o que já tem variável própria.** `{{contact.name}}`, `{{conversation.status}}`,
|
|
875
|
+
`{{inbox.name}}` e os atributos `ctwa_*` continuam existindo e são a forma canônica. O `{{trigger.*}}`
|
|
876
|
+
serve pra perguntar "o que veio COM o gatilho", não pra ser um segundo nome do mesmo dado.
|
|
877
|
+
|
|
878
|
+
**Variáveis do agente de IA `{{ai_agent.*}}` (novo 2026-08-01):** `{{ai_agent.name}}` e
|
|
879
|
+
`{{ai_agent.id}}` trazem o AI Agente atribuído à conversa (vazio se não houver). Prefixo `ai_agent` de
|
|
880
|
+
propósito — `agent` sozinho é o atendente HUMANO, e confundir os dois seria pior que não ter.
|
|
881
|
+
|
|
816
882
|
---
|
|
817
883
|
|
|
818
884
|
## 2-D. Exit conditions (saída automática do flow)
|
|
@@ -168,6 +168,23 @@ do rodízio).
|
|
|
168
168
|
aceitam `supervisor_ids[]` além de `user_ids[]` — os IDs em `supervisor_ids` viram supervisores;
|
|
169
169
|
os de `user_ids` viram membros comuns. A resposta traz `is_supervisor` (boolean) por agente.
|
|
170
170
|
|
|
171
|
+
### Supervisor de TIME (novo 2026-07-30) — é outra marca, independente da de caixa
|
|
172
|
+
|
|
173
|
+
O time ganhou os mesmos dois papéis. Supervisor de time continua membro pra tudo (menção, e-mail de
|
|
174
|
+
automação, acesso a funil do Kanban, relatório, contagem, atribuição MANUAL) e fica fora da
|
|
175
|
+
distribuição automática do time — tanto de conversa quanto do rodízio de card do funil.
|
|
176
|
+
|
|
177
|
+
**Onde fica armazenado:** flag `team_members.auto_assignable` (espelho da de caixa).
|
|
178
|
+
|
|
179
|
+
**Como definir/ler via tools:** `lionchat_team_members_create` / `_update` com `supervisor_ids[]`.
|
|
180
|
+
**Diferença importante do contrato da caixa:** aqui `user_ids[]` é sempre a lista COMPLETA de membros
|
|
181
|
+
e `supervisor_ids[]` é um SUBCONJUNTO dela; omitir `supervisor_ids` não mexe em papel nenhum.
|
|
182
|
+
`lionchat_team_members_list` traz `is_supervisor`.
|
|
183
|
+
|
|
184
|
+
**As duas marcas NÃO se comunicam:** a da caixa protege da distribuição da caixa, a do time da
|
|
185
|
+
distribuição do time. Supervisor de caixa que é agente num time continua recebendo por aquele time —
|
|
186
|
+
comportamento intencional.
|
|
187
|
+
|
|
171
188
|
## KanbanItem (Card do CRM)
|
|
172
189
|
|
|
173
190
|
### Estrutura
|
|
@@ -489,6 +489,25 @@ viraram conversa). É um relatório de LEITURA puro — não cria nem altera nad
|
|
|
489
489
|
**Perguntas que esse relatório responde:** "qual plataforma trouxe mais leads?", "qual campanha/
|
|
490
490
|
conjunto converteu melhor?", "quantos leads únicos vieram esse mês e quantos fecharam?".
|
|
491
491
|
|
|
492
|
+
### Atributos de anúncio (`ctwa_*`) — dois novos e nomes alinhados (2026-08-01)
|
|
493
|
+
|
|
494
|
+
Conversa que veio de anúncio "Clique para WhatsApp" carrega atributos `ctwa_*` (`ctwa_campaign_name`,
|
|
495
|
+
`ctwa_adset_name`, `ctwa_ad_name`, `ctwa_creative_name`, `ctwa_source_url`…). Eles são atributos de
|
|
496
|
+
conversa normais: dá pra filtrar (`lionchat_conversations_filter`), usar em público de campanha e ler
|
|
497
|
+
em flow (`{{trigger.ad.*}}`).
|
|
498
|
+
|
|
499
|
+
Dois deles apareciam no painel **sem cadastro nenhum** e por isso não dava pra filtrar por eles em
|
|
500
|
+
lugar algum. Foram criados em 01/08 e agora funcionam como os demais:
|
|
501
|
+
|
|
502
|
+
| Chave | Rótulo | Tipo |
|
|
503
|
+
|---|---|---|
|
|
504
|
+
| `ctwa_conversion_source` | Plataforma de Origem do Anúncio | texto |
|
|
505
|
+
| `ctwa_conversion_delay_seconds` | Tempo até a Conversão (s) | número |
|
|
506
|
+
|
|
507
|
+
Na mesma data os rótulos de exibição dos `ctwa_*` foram alinhados com os do painel. **As CHAVES não
|
|
508
|
+
mudaram** — flow, automação, campanha e filtro guardam a chave, nunca o rótulo, então nada que já
|
|
509
|
+
existia quebrou. Se o cliente disser que "o nome do campo mudou", é só o rótulo na tela.
|
|
510
|
+
|
|
492
511
|
## Quando o usuário pede algo MUITO específico que não existe num endpoint
|
|
493
512
|
|
|
494
513
|
Se a pergunta requer cálculos custom (ex: "conversas por agente que duraram mais de X minutos"):
|
|
@@ -283,6 +283,42 @@ Cancelar vale pra TODOS os grupos (inclusive `permanent`, `window_expired`, `cam
|
|
|
283
283
|
que nunca seriam reenviados) — é assim que se limpa o painel. Ações irreversíveis: confirme com o
|
|
284
284
|
usuário e mostre as contagens do summary antes.
|
|
285
285
|
|
|
286
|
+
### "Erro 131026 / Message undeliverable" — NUNCA chute a causa (30/07)
|
|
287
|
+
A Meta devolve o MESMO código 131026 pra duas coisas diferentes: **o número não tem WhatsApp** e **a
|
|
288
|
+
pessoa não está recebendo** (bloqueou, aparelho fora, não aceita mensagem de empresa). A Meta não diz
|
|
289
|
+
qual das duas — então a plataforma carimba um fato NOSSO em
|
|
290
|
+
`content_attributes.undeliverable_history`:
|
|
291
|
+
|
|
292
|
+
| Carimbo | O que significa | O que dizer ao cliente |
|
|
293
|
+
|---|---|---|
|
|
294
|
+
| `never_delivered` | nunca entregamos nada pra esse contato | provavelmente o número não tem WhatsApp — vale conferir o número |
|
|
295
|
+
| `delivered_before` | já entregamos antes, hoje não entrega | o número existe; a pessoa é que não está recebendo agora |
|
|
296
|
+
| ausente (mensagem antiga) | sem histórico carimbado | enuncie as DUAS possibilidades, sem escolher |
|
|
297
|
+
|
|
298
|
+
**Nunca afirme "esse número não tem WhatsApp" sem o carimbo `never_delivered`.** Foi exatamente esse
|
|
299
|
+
palpite que fez atendente encerrar conversa de paciente que existia (conta 56, conv 3629).
|
|
300
|
+
|
|
301
|
+
### "Mídia recusada pela Meta (131053) e a faixa vermelha sumiu sozinha" (30/07)
|
|
302
|
+
Comportamento novo, não é bug. O 131053 é um balde: uma das variantes (a que menciona `weblink`) é
|
|
303
|
+
TRANSITÓRIA — o buscador da Meta falhou ao baixar o arquivo pela URL. Nesse caso a plataforma reenvia
|
|
304
|
+
sozinha, agora por upload direto, e a mensagem fica verde sem precisar de F5. As demais variantes do
|
|
305
|
+
131053 (formato/tamanho recusado) NÃO são resgatadas — regra fail-closed de propósito, pra não ficar
|
|
306
|
+
reenviando eternamente algo que a Meta nunca vai aceitar.
|
|
307
|
+
|
|
308
|
+
### "A mensagem falhou dizendo 'Template not found or invalid template name'" (30/07)
|
|
309
|
+
Se a caixa é **WhatsApp oficial** e faz mais de 24h que o cliente não fala, a causa quase sempre é a
|
|
310
|
+
**janela de 24h fechada** — não um template faltando. Até 30/07 o erro gravado era esse texto
|
|
311
|
+
enganoso; hoje a mensagem diz que a janela fechou, e o classificador põe a falha no grupo
|
|
312
|
+
`window_expired` (fora do reenvio em lote — reenviar não adiantaria).
|
|
313
|
+
|
|
314
|
+
Regras de produto pra explicar ao cliente:
|
|
315
|
+
- **Mandar template NÃO abre a janela.** Só a mensagem do CLIENTE abre.
|
|
316
|
+
- Fora da janela, só template aprovado sai. Texto livre é recusado pela Meta.
|
|
317
|
+
- O follow-up automático da IA passou a entender isso: fora das 24h ele escolhe um modelo aprovado em
|
|
318
|
+
vez de escrever texto livre e tomar recusa (ver `lionchat://docs/best-practices`).
|
|
319
|
+
- Erro sem tradução deixou de existir: todo `external_error` agora vira texto em português na bolha e
|
|
320
|
+
no painel de falhas. Se aparecer erro em inglês cru pro usuário, isso é reportável.
|
|
321
|
+
|
|
286
322
|
### "O Messenger parou de enviar / 'Invalid parameter'" (24/07)
|
|
287
323
|
Causa raiz do apagão de 22 a 24/07: a Meta **aposentou a message tag** que o sistema mandava em todo
|
|
288
324
|
envio de Messenger. Corrigido em 24/07. Agora o Messenger respeita a **janela de 24h** de verdade:
|
package/endpoints.json
CHANGED
|
@@ -10091,14 +10091,14 @@
|
|
|
10091
10091
|
"type": "array",
|
|
10092
10092
|
"location": "body",
|
|
10093
10093
|
"required": true,
|
|
10094
|
-
"description": "[{attribute_key, filter_operator, query_operator, values[]}]"
|
|
10094
|
+
"description": "[{attribute_key, filter_operator, query_operator, values[]}] REGRA DO CONECTOR (query_operator) — LEIA ANTES DE GRAVAR: o conector liga a condicao com a SEGUINTE, logo a ULTIMA condicao TEM que ter query_operator: null (condicao UNICA tambem = null). Nas demais: 'AND' ou 'OR'. A API valida o VALOR do conector mas NAO a POSICAO — conector na ultima condicao SALVA COM SUCESSO, aparece certo na tela e a regra NUNCA dispara. Incidente real: 8 regras criadas pelo conector de IA entre 26 e 30/07/2026 em 3 contas, todas com conector na ultima condicao, todas nasceram mortas (732 erros/hora medidos em producao 03/08; a conta 62 ficou com as 6 regras de etiquetagem automatica paradas). attribute_key precisa ser campo padrao OU atributo personalizado que EXISTA na conta (senao a regra inteira falha na validacao: 'Automation conditions <chave> not supported') — conferir antes com lionchat_custom_attributes_list; atributo personalizado exige tambem custom_attribute_type ('conversation_attribute' ou 'contact_attribute'). filter_operator: equal_to, not_equal_to, contains, does_not_contain, is_present, is_not_present, is_greater_than, is_less_than, starts_with, days_before, days_ago, last_days, today, yesterday — cada campo aceita so um subconjunto. Na duvida, leia uma regra que ja funciona com lionchat_automation_rules_show e copie o formato. Detalhe no resource 'conversation-flows'."
|
|
10095
10095
|
},
|
|
10096
10096
|
{
|
|
10097
10097
|
"name": "actions",
|
|
10098
10098
|
"type": "array",
|
|
10099
10099
|
"location": "body",
|
|
10100
10100
|
"required": true,
|
|
10101
|
-
"description": "CADA item de actions DEVE ser um OBJETO {action_name (string), action_params (array)} — NUNCA um texto/string solto. Ex.: [{\"action_name\":\"send_message\",\"action_params\":[\"Oi\"]}]. [{action_name, action_params[]}] Actions novas (2026-07-21): 'update_contact_attribute' e 'update_conversation_attribute' — action_params: [{attribute_key, value}], value aceita texto fixo OU variável Liquid (ex. {{contact.phone_number}}); grava atributo personalizado com MERGE (não apaga os demais) e passa pelo porteiro de data. 'pending_conversation' (2026-07-20, sem params) — deixa a conversa PENDENTE (handoff; mensagem nova do cliente NÃO reabre)."
|
|
10101
|
+
"description": "CADA item de actions DEVE ser um OBJETO {action_name (string), action_params (array)} — NUNCA um texto/string solto. Ex.: [{\"action_name\":\"send_message\",\"action_params\":[\"Oi\"]}]. [{action_name, action_params[]}] Actions novas (2026-07-21): 'update_contact_attribute' e 'update_conversation_attribute' — action_params: [{attribute_key, value}], value aceita texto fixo OU variável Liquid (ex. {{contact.phone_number}}); grava atributo personalizado com MERGE (não apaga os demais) e passa pelo porteiro de data. 'pending_conversation' (2026-07-20, sem params) — deixa a conversa PENDENTE (handoff; mensagem nova do cliente NÃO reabre). ATENCAO — 'send_whatsapp_template': action_params: [{name, id, language, category, processed_params}]. 'name' e OBRIGATORIO e e o nome EXATO do modelo aprovado na Meta (o envio acontece por ele); 'language' precisa bater com o idioma aprovado (padrao pt_BR); processed_params: {\"body\": {\"1\": \"{{contact.first_name}}\"}}. NUNCA use template_name/template_id/template_category/template_language — esse e o formato dos nos do FlowBuilder e aqui e IGNORADO: a regra salva com sucesso, aparece na tela e NAO ENVIA NADA, sem erro nem log (incidente real conta 39 em 02/08/2026: 14h sem enviar, 9 leads perdidos). Confira o modelo antes com lionchat_inboxes_whatsapp_templates_list. So funciona em caixa WhatsApp API Oficial (Cloud). REGRA GERAL: action_params e SEMPRE um array (o backend le params[0]) e seu CONTEUDO nao e validado pela API. Se nao souber o formato de uma acao, leia uma regra existente com lionchat_automation_rules_show e copie — nunca invente nome de chave. Formato de TODAS as acoes no resource 'conversation-flows'."
|
|
10102
10102
|
},
|
|
10103
10103
|
{
|
|
10104
10104
|
"name": "active",
|
|
@@ -10189,14 +10189,14 @@
|
|
|
10189
10189
|
"type": "array",
|
|
10190
10190
|
"location": "body",
|
|
10191
10191
|
"required": false,
|
|
10192
|
-
"description": "Condicoes"
|
|
10192
|
+
"description": "Condicoes REGRA DO CONECTOR (query_operator) — LEIA ANTES DE GRAVAR: o conector liga a condicao com a SEGUINTE, logo a ULTIMA condicao TEM que ter query_operator: null (condicao UNICA tambem = null). Nas demais: 'AND' ou 'OR'. A API valida o VALOR do conector mas NAO a POSICAO — conector na ultima condicao SALVA COM SUCESSO, aparece certo na tela e a regra NUNCA dispara. Incidente real: 8 regras criadas pelo conector de IA entre 26 e 30/07/2026 em 3 contas, todas com conector na ultima condicao, todas nasceram mortas (732 erros/hora medidos em producao 03/08; a conta 62 ficou com as 6 regras de etiquetagem automatica paradas). attribute_key precisa ser campo padrao OU atributo personalizado que EXISTA na conta (senao a regra inteira falha na validacao: 'Automation conditions <chave> not supported') — conferir antes com lionchat_custom_attributes_list; atributo personalizado exige tambem custom_attribute_type ('conversation_attribute' ou 'contact_attribute'). filter_operator: equal_to, not_equal_to, contains, does_not_contain, is_present, is_not_present, is_greater_than, is_less_than, starts_with, days_before, days_ago, last_days, today, yesterday — cada campo aceita so um subconjunto. Na duvida, leia uma regra que ja funciona com lionchat_automation_rules_show e copie o formato. Detalhe no resource 'conversation-flows'."
|
|
10193
10193
|
},
|
|
10194
10194
|
{
|
|
10195
10195
|
"name": "actions",
|
|
10196
10196
|
"type": "array",
|
|
10197
10197
|
"location": "body",
|
|
10198
10198
|
"required": false,
|
|
10199
|
-
"description": "CADA item de actions DEVE ser um OBJETO {action_name (string), action_params (array)} — NUNCA um texto/string solto. Ex.: [{\"action_name\":\"send_message\",\"action_params\":[\"Oi\"]}]. Acoes Actions novas (2026-07-21): 'update_contact_attribute' e 'update_conversation_attribute' — action_params: [{attribute_key, value}], value aceita texto fixo OU variável Liquid (ex. {{contact.phone_number}}); grava atributo personalizado com MERGE (não apaga os demais) e passa pelo porteiro de data. 'pending_conversation' (2026-07-20, sem params) — deixa a conversa PENDENTE (handoff; mensagem nova do cliente NÃO reabre)."
|
|
10199
|
+
"description": "CADA item de actions DEVE ser um OBJETO {action_name (string), action_params (array)} — NUNCA um texto/string solto. Ex.: [{\"action_name\":\"send_message\",\"action_params\":[\"Oi\"]}]. Acoes Actions novas (2026-07-21): 'update_contact_attribute' e 'update_conversation_attribute' — action_params: [{attribute_key, value}], value aceita texto fixo OU variável Liquid (ex. {{contact.phone_number}}); grava atributo personalizado com MERGE (não apaga os demais) e passa pelo porteiro de data. 'pending_conversation' (2026-07-20, sem params) — deixa a conversa PENDENTE (handoff; mensagem nova do cliente NÃO reabre). ATENCAO — 'send_whatsapp_template': action_params: [{name, id, language, category, processed_params}]. 'name' e OBRIGATORIO e e o nome EXATO do modelo aprovado na Meta (o envio acontece por ele); 'language' precisa bater com o idioma aprovado (padrao pt_BR); processed_params: {\"body\": {\"1\": \"{{contact.first_name}}\"}}. NUNCA use template_name/template_id/template_category/template_language — esse e o formato dos nos do FlowBuilder e aqui e IGNORADO: a regra salva com sucesso, aparece na tela e NAO ENVIA NADA, sem erro nem log (incidente real conta 39 em 02/08/2026: 14h sem enviar, 9 leads perdidos). Confira o modelo antes com lionchat_inboxes_whatsapp_templates_list. So funciona em caixa WhatsApp API Oficial (Cloud). REGRA GERAL: action_params e SEMPRE um array (o backend le params[0]) e seu CONTEUDO nao e validado pela API. Se nao souber o formato de uma acao, leia uma regra existente com lionchat_automation_rules_show e copie — nunca invente nome de chave. Formato de TODAS as acoes no resource 'conversation-flows'."
|
|
10200
10200
|
}
|
|
10201
10201
|
],
|
|
10202
10202
|
"returns": "regra de automação atualizado",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lionchat/mcp-server",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.2",
|
|
4
4
|
"description": "MCP server for LionChat API — 547 tools + 10 resources + 9 prompts. Audit-log aware, completion API, progress notifications.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|