@lionchat/mcp-server 1.30.0 → 1.31.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.
- package/dist/docs/instructions.md +11 -2
- package/dist/docs/resources/agenda-multiplas-unidades.md +44 -2
- package/dist/docs/resources/assinatura-eletronica.md +19 -2
- package/dist/docs/resources/best-practices.md +7 -1
- package/dist/docs/resources/conversation-flows.md +12 -4
- package/dist/docs/resources/data-model.md +119 -1
- package/dist/docs/resources/filtros-e-relatorios.md +31 -2
- package/dist/docs/resources/flowbuilder-design-guide.md +62 -9
- package/dist/docs/resources/formularios-publicos.md +139 -0
- package/dist/docs/resources/glossary.md +23 -0
- package/dist/docs/resources/kanban-deep-dive.md +87 -4
- package/dist/docs/resources/reports-guide.md +11 -2
- package/dist/tools.js +69 -17
- package/dist/tools.js.map +1 -1
- package/endpoints.json +844 -69
- package/package.json +1 -1
|
@@ -62,7 +62,7 @@ Todo node tem essa estrutura base:
|
|
|
62
62
|
|
|
63
63
|
**ATENÇÃO — chave `items`, não `triggers` (corrigido 19/08/2026).** Os gatilhos vão em **`data.items`**, cada item no formato **`{ "key": "...", "config": { ...filtros... } }`**. O formato antigo (`data.triggers` + `type` + filtros soltos no topo) ainda é aceito pelo motor por compatibilidade, mas **NÃO deve ser usado em fluxo novo**: o editor do FlowBuilder lê apenas `data.items`, então um fluxo gravado no formato antigo **dispara normalmente mas abre com o bloco Início EM BRANCO no painel do cliente** — e um clique em "Concluir" naquele modal apagava o gatilho em silêncio. Foram 53 fluxos de 9 contas nesse estado até o conserto de 19/08. Alguns leitores do backend (`has_webhook_trigger?` do disparo por webhook, o filtro de Campanha de Fluxo, o gatilho LionTrack e o histórico de execução) também só entendem `items`.
|
|
64
64
|
|
|
65
|
-
**Triggers válidos:** `message_received`, `message_sent`, `conversation_created`, `conversation_resolved`, `conversation_reopened`, `team_changed`, `assignee_changed`, `label_added`, `label_removed`, `sla_missed`, `card_created`, `card_moved`, `card_won`, `card_lost`, `conversation_attribute_changed`, `card_attribute_changed`, `contact_attribute_changed`, `date_trigger`, `campaign_trigger`, `manual_trigger`, `webhook_received`, `page_track`, `group_participant_joined`, `group_participant_left`, `lead_form_completed`, `lead_form_milestone`, `lead_form_abandoned`, `booking_created`, `booking_cancelled`, `booking_rescheduled`, `booking_completed`.
|
|
65
|
+
**Triggers válidos:** `message_received`, `message_sent`, `conversation_created`, `conversation_resolved`, `conversation_reopened`, `team_changed`, `assignee_changed`, `label_added`, `label_removed`, `sla_missed`, `card_created`, `card_moved`, `card_won`, `card_lost`, `card_opened`, `card_snoozed`, `conversation_attribute_changed`, `card_attribute_changed`, `contact_attribute_changed`, `date_trigger`, `campaign_trigger`, `manual_trigger`, `webhook_received`, `page_track`, `group_participant_joined`, `group_participant_left`, `lead_form_completed`, `lead_form_milestone`, `lead_form_abandoned`, `booking_created`, `booking_cancelled`, `booking_rescheduled`, `booking_completed`.
|
|
66
66
|
|
|
67
67
|
**NÃO existem** os gatilhos `webhook` (o correto é **`webhook_received`**) nem `cron` (para disparo por data use `date_trigger`; para disparo em lote use `campaign_trigger` + Campanha de Fluxo). Até 19/08/2026 este guia listava os dois por engano — o fluxo 180 da conta 54 ficou ATIVO com `webhook` e **nunca disparou uma vez em 26 dias**, sem erro nenhum.
|
|
68
68
|
|
|
@@ -74,6 +74,7 @@ Todo node tem essa estrutura base:
|
|
|
74
74
|
- `label_added` / `label_removed`: `label_names` (array de slugs). NÃO use `label` (singular) — é ignorado.
|
|
75
75
|
- `card_created` / `card_moved`: `funnel_ids` (array de STRINGS, ex.: `["37"]` — número puro `[37]` NÃO casa) + `funnel_stages` (array de `"funnel_id:chave_da_etapa"`, ex.: `"37:agendamento_pendente"`). A `chave_da_etapa` é a CHAVE INTERNA da etapa no funil (slug legível em funis de template; pode ser um UUID/`stage_<n>` em etapa criada à mão ou funil duplicado) — NÃO o nome exibido na tela. Sem `funnel_ids` → dispara em qualquer funil; com `funnel_ids` mas sem `funnel_stages` → qualquer etapa daquele(s) funil(is). O card precisa estar num funil listado em `funnel_ids` pra o filtro de etapa valer. ATENÇÃO: dois flows ATIVOS na mesma inbox com `card_created`/`card_moved` de funil/etapa sobrepostos são bloqueados na criação/ativação (ver `flow_trigger_conflict` no fim deste guia).
|
|
76
76
|
- `team_changed`: `team_ids` (array de STRINGS; vazio = qualquer equipe). `assignee_changed`: `agent_ids` (array de STRINGS; vazio = qualquer atendente). `card_won` / `card_lost`: `funnel_ids` (array de STRINGS) — disparam SÓ quando o STATUS do card vira ganho/perdido, nunca por etapa com esse nome.
|
|
77
|
+
- `card_opened` ("Card aberto") / `card_snoozed` ("Card adiado") — NOVOS 11/10/2026, mesma config `funnel_ids` (array de STRINGS; vazio = qualquer funil). `card_snoozed` dispara quando o card é ADIADO. `card_opened` dispara quando um card adiado ABRE (pela data, por alguém ou por automação) e também quando um card ganho/perdido é REABERTO — card NOVO não dispara (para isso existe `card_created`). Pela data, o fluxo sai pela fila de disparos agendados, uma vez por card. Use `{{trigger.kanban.previous_status}}` (`snoozed`/`won`/`lost`) para separar "voltou do adiamento" de "reabriram um ganho/perdido".
|
|
77
78
|
- `page_track` (LionTrack, só flow individual): `{ "track_type": "visited_page"|"event_fired", "urls": [...], "operator": "contains"|"exact"|"starts_with", "event_names": [...], "event_operator": "equals"|"contains", "cooldown_hours": 24 }` — `cooldown_hours` (padrão 24, mínimo 1) não re-dispara pro mesmo contato dentro da janela.
|
|
78
79
|
- `conversation_attribute_changed` / `card_attribute_changed` (novo 2026-07-08): disparam na VIRADA de um atributo (da CONVERSA ou do CARD do kanban) pro valor que casa — RE-ENTRAM toda vez que o atributo muda pro valor alvo. Config: `{ "logic": "and"|"or", "rules": [ { "attr_key": "...", "operator": "...", "value": "..." } ] }` (uma rule pode usar `values: [...]` no lugar de `value` pra multi-valor). O `attrSource` é IMPLÍCITO pela chave do gatilho (conversa vs card) — NÃO informe. Operadores (contexto REATIVO — desde 09/07 `is_empty`/`is_not_empty` NÃO valem aqui, pois "está vazio AGORA" dispararia a cada evento; use-os só no nó Condição): `equal`/`not_equal`/`contains`/`not_contains`/`starts_with`/`ends_with`/`greater_than`/`less_than`/`number_range`. Só `card_attribute_changed` aceita `funnel_id`/`card_source` opcionais dentro da rule (pra achar o card). Rule sem `attr_key` é ignorada.
|
|
79
80
|
- `contact_attribute_changed` (novo 2026-07-22 — "Atributo do contato muda"): dispara quando um atributo personalizado do **CONTATO** muda e a condição casa — mesmo com o contato fora de flow. Item: `{ "key": "contact_attribute_changed", "config": { "logic": "and"|"or", "rules": [ { "attrSource": "contact", "attr_key": "...", "operator": "...", "value": "..." } ] } }` (1 a 10 rules; `values: [...]` pra multi-valor). **DIFERENTE dos irmãos de 08/07: aqui o `attrSource` VAI na rule e é SEMPRE `"contact"`.** Operadores iguais aos do nó Condição. **VERSÃO SEGURA por decisão de produto:** dispara SÓ na conversa mais recente que JÁ EXISTE numa caixa do flow (reabre se resolvida); contato sem conversa NÃO dispara e NUNCA cria conversa. Dedup de 30s por contato + anti-loop por profundidade de cadeia (flow que muda atributo que dispara flow…). Só flows de conversa.
|
|
@@ -152,7 +153,7 @@ Receita completa: `flows_create`/`flows_update` com o item no start → `flows_l
|
|
|
152
153
|
4. Salvar o flow (`flows_update`) — o save sincroniza a ativação do webhook embutido (remover o item desativa a integração automaticamente).
|
|
153
154
|
Webhooks embutidos NÃO aparecem na listagem de integrações standalone; excluir o flow destrói o webhook; duplicar o flow NÃO copia o gatilho embutido. Rate limit do endpoint público: 60/min por token.
|
|
154
155
|
|
|
155
|
-
**Gatilhos de AGENDAMENTO — Booking NATIVO do LionChat (2026-08-20):** `booking_created` (alguém marcou pelo link público, pela IA ou pelo painel), `booking_cancelled` (paciente cancelou pelo link, IA cancelou ou a equipe cancelou na Agenda), `booking_rescheduled` (a data/hora mudou — link do paciente, IA, editar/adiar na Agenda), `booking_completed` (equipe concluiu na Agenda; exige a Agenda unificada ligada na conta). **Não é e-Clínica.** Config (tudo opcional, vazio = todos): `booking_event_type_ids` (array de ids de tipo de agendamento, **STRING**), `agent_ids` (array de ids de usuário — o RESPONSÁVEL da tarefa), `create_conversation` (boolean, padrão `false`: só dispara para quem já tem conversa numa caixa do flow; `true` = cria a conversa na 1ª caixa do flow). Exemplo: `{ "key": "booking_created", "config": { "booking_event_type_ids": ["44"], "agent_ids": [], "create_conversation": true } }`. São INERTES a evento de conversa (quem dispara é o `Booking::FlowTriggerDispatcher`, por CONTA — caixa do flow só define onde a conversa é criada/reusada). Variáveis no flow: `{{booking.date}}` (DD/MM/AAAA), `{{booking.time}}`, `{{booking.weekday}}`, `{{booking.datetime}}` (ISO), `{{booking.type}}`, `{{booking.type_format}}` (presencial/videochamada), `{{booking.duration}}`, `{{booking.agent}}`, `{{booking.status}}` (confirmado/cancelado/remarcado/concluído), `{{booking.description}}`, `{{booking.cancel_url}}`, `{{booking.reschedule_url}}`, `{{booking.color}}`, `{{booking.id}}`; só no remarcado: `{{booking.previous_date}}`, `{{booking.previous_time}}`, `{{booking.previous_datetime}}`; `{{booking.meeting_url}}` NÃO vem no criado (nasce vazio). Data/hora vêm da TAREFA da Agenda (sempre atuais). Regras: o evento mais novo SUBSTITUI a rodada ativa do mesmo flow na mesma conversa (2ª consulta do mesmo paciente, ou cancelado chegando com o criado ainda esperando resposta); excluir a tarefa, reabrir cancelada ou desfazer conclusão NÃO disparam; adiar (snooze) conta como remarcado; tipo com confirmação/lembrete próprios ligados + `booking_created` = o paciente pode receber duas mensagens (a tela avisa). Colisão entre flows é por CONTA: mesmo kind + tipos se cruzando + agentes se cruzando (vazio = todos). Há também `{{booking.event}}` (`created`|`cancelled`|`rescheduled`|`completed` — bom pra condição; não aparece no seletor da tela, mas resolve); `{{trigger.type}}` = a chave do gatilho (ex.: `booking_created`), `{{trigger.kind}}` = `created`|`cancelled`|`rescheduled`|`completed` e `{{trigger.booking_id}}`. SÓ flow de conversa **individual** (a tela nem oferece em flow de grupo); **nunca dispara flow `ai_tool`**. Em caixa WhatsApp OFICIAL, conversa criada nova (ou parada há mais de 24h) está FORA da janela — texto livre no 1º bloco cai em `window_closed`/erro; comece por template.
|
|
156
|
+
**Gatilhos de AGENDAMENTO — Booking NATIVO do LionChat (2026-08-20):** `booking_created` (alguém marcou pelo link público, pela IA ou pelo painel), `booking_cancelled` (paciente cancelou pelo link, IA cancelou ou a equipe cancelou na Agenda), `booking_rescheduled` (a data/hora mudou — link do paciente, IA, editar/adiar na Agenda), `booking_completed` (equipe concluiu na Agenda; exige a Agenda unificada ligada na conta). **Não é e-Clínica.** Config (tudo opcional, vazio = todos): `booking_event_type_ids` (array de ids de tipo de agendamento, **STRING**), `agent_ids` (array de ids de usuário — o RESPONSÁVEL da tarefa), `create_conversation` (boolean, padrão `false`: só dispara para quem já tem conversa numa caixa do flow; `true` = cria a conversa na 1ª caixa do flow). Exemplo: `{ "key": "booking_created", "config": { "booking_event_type_ids": ["44"], "agent_ids": [], "create_conversation": true } }`. São INERTES a evento de conversa (quem dispara é o `Booking::FlowTriggerDispatcher`, por CONTA — caixa do flow só define onde a conversa é criada/reusada). Variáveis no flow: `{{booking.date}}` (DD/MM/AAAA), `{{booking.time}}`, `{{booking.weekday}}`, `{{booking.datetime}}` (ISO), `{{booking.type}}`, `{{booking.type_format}}` (presencial/videochamada), `{{booking.duration}}`, `{{booking.agent}}`, `{{booking.status}}` (confirmado/cancelado/remarcado/concluído), `{{booking.description}}`, `{{booking.cancel_url}}`, `{{booking.reschedule_url}}`, `{{booking.confirm_url}}`, `{{booking.calendar_url}}` (16/10: página onde o cliente salva o compromisso na agenda DELE, sem e-mail; no remarcado já sai com a hora nova — é o jeito de avisar a mudança, pedindo para apagar o compromisso antigo), `{{booking.color}}`, `{{booking.id}}`; só no remarcado: `{{booking.previous_date}}`, `{{booking.previous_time}}`, `{{booking.previous_datetime}}`; `{{booking.meeting_url}}` NÃO vem no criado (nasce vazio). Data/hora vêm da TAREFA da Agenda (sempre atuais). Regras: o evento mais novo SUBSTITUI a rodada ativa do mesmo flow na mesma conversa (2ª consulta do mesmo paciente, ou cancelado chegando com o criado ainda esperando resposta); excluir a tarefa, reabrir cancelada ou desfazer conclusão NÃO disparam; adiar (snooze) conta como remarcado; tipo com confirmação/lembrete próprios ligados + `booking_created` = o paciente pode receber duas mensagens (a tela avisa). Colisão entre flows é por CONTA: mesmo kind + tipos se cruzando + agentes se cruzando (vazio = todos). Há também `{{booking.event}}` (`created`|`cancelled`|`rescheduled`|`completed` — bom pra condição; não aparece no seletor da tela, mas resolve); `{{trigger.type}}` = a chave do gatilho (ex.: `booking_created`), `{{trigger.kind}}` = `created`|`cancelled`|`rescheduled`|`completed` e `{{trigger.booking_id}}`. SÓ flow de conversa **individual** (a tela nem oferece em flow de grupo); **nunca dispara flow `ai_tool`**. Em caixa WhatsApp OFICIAL, conversa criada nova (ou parada há mais de 24h) está FORA da janela — texto livre no 1º bloco cai em `window_closed`/erro; comece por template.
|
|
156
157
|
|
|
157
158
|
**TRAVA DE GATILHO DUPLICADO (2026-06-16) — leia ANTES de ativar/criar flow ativo:** o sistema BLOQUEIA ter dois flows ATIVOS com o MESMO gatilho na MESMA inbox e mesmo `conversation_mode` (evita o evento disparar dois flows). Colisão = mesmo tipo de gatilho + config cruzando (mesmas keywords/funil/labels/url/etc) + inbox compartilhada + mesmo modo. EXCEÇÕES que podem coexistir: `webhook_received`, `manual_trigger` e `campaign_trigger` (este último porque não dispara por evento — é só uma autorização para a campanha).
|
|
158
159
|
- **`date_trigger` separa por HORÁRIO (24/09/2026):** dois flows no mesmo campo de data, mesma direção e mesmos dias NÃO colidem se os dois tiverem horário FIXO diferente (ex.: "1 dia depois às 08:00" e "às 14:00"). Horário vindo de atributo/fórmula continua colidindo (só existe na hora do disparo); `send_time` vazio conta como 09:00 e "8:00" = "08:00". A entrega é de 10 em 10 minutos — horários a menos de 10 min podem sair juntos.
|
|
@@ -397,6 +398,7 @@ só pra destravar, ela pode sair.
|
|
|
397
398
|
| `conversation_has_ai_agent` / `conversation_no_ai_agent` / `conversation_not_ai_agent` | agente de IA atribuído (novo 2026-08-01) — ver abaixo |
|
|
398
399
|
| `contact_has_label` / `contact_no_label` / `conversation_has_label` / `conversation_no_label` | labels |
|
|
399
400
|
| `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" }` |
|
|
401
|
+
| `kanban_snoozed` (11/10/2026) | card ADIADO no funil — `field: '_kanban_status'`, `funnel_id` separado, igual às irmãs `kanban_won`/`kanban_lost` (mesma regra do card que iniciou o fluxo). Não existe condição "card aberto" |
|
|
400
402
|
| `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) |
|
|
401
403
|
| `pagetrack_visited` / `pagetrack_event` | LionTrack |
|
|
402
404
|
| `sla_check` | status do SLA da conversa (usa `value` = código fixo; ver abaixo) |
|
|
@@ -457,7 +459,7 @@ campanha"):
|
|
|
457
459
|
`origin_first_kind`/`origin_first_platform`, `origin_last_kind`/`origin_last_platform`, `origin_*` em geral
|
|
458
460
|
(origem unificada), `ctwa_*` (anúncio click-to-WhatsApp: `ctwa_ad_id`, `ctwa_ad_title`, `ctwa_campaign_name`,
|
|
459
461
|
`ctwa_adset_name`...), `meta_lead_*` (formulário Meta Lead Ads), `lt_*` (LionTrack: UTMs, página, dispositivo).
|
|
460
|
-
Veja a lista real com `lionchat_custom_attributes_list` (`attribute_model: conversation
|
|
462
|
+
Veja a lista real com `lionchat_custom_attributes_list` (`attribute_model: conversation_attribute` — com o sufixo; só `conversation` devolve a lista VAZIA —, `include_system: true` — as chaves de campanha são atributos de sistema).
|
|
461
463
|
- **Valores fechados** de `origin_kind` (e `origin_first_kind`/`origin_last_kind`): `paid_ad` (Anúncio),
|
|
462
464
|
`lead_form` (Formulário), `organic` (Orgânico), `direct` (Direto), `referral` (Indicação), `manual` (Origem
|
|
463
465
|
cadastrada). O painel mostra o rótulo em português, mas a comparação é pelo VALOR — `"Anúncio"` nunca casa.
|
|
@@ -558,6 +560,7 @@ o botão "Usar variável" ao lado do campo alterna lista fixa ↔ variável.
|
|
|
558
560
|
| `set_kanban_item_status` | `{ status: 'won' \| 'lost' \| 'active' }` | Marca status do card |
|
|
559
561
|
| `set_won` | `{}` | Atalho pra ganho |
|
|
560
562
|
| `set_lost` | `{ reason? }` | Atalho pra perdido |
|
|
563
|
+
| `snooze_kanban_item` (11/10/2026) | `{ funnel_id, amount, unit: 'hours' \| 'days', card_source? }` | "Adiar card": ADIA o card por N horas ou dias a partir da execução (`amount` inteiro, 1 ou mais; mínimo 1 hora). Só card aberto; adiar de novo troca a data. `card_source: 'trigger'` mira o card que iniciou o fluxo (aí `funnel_id` não é exigido). Diferente das irmãs de card: card ganho/perdido, sem card ou fluxo que NÃO veio de card com `card_source: 'trigger'` = ERRO visível no passo, nunca pulado. `set_open` (e `set_kanban_item_status` com `open`) num card ADIADO abre o card na hora e dispara "Card aberto". Ver "Card adiado" no kanban-deep-dive |
|
|
561
564
|
| `assign_agent_card` | `{ agent_id, mode? }` | Responsável do card. `mode`: `'add'` (default — SOMA na lista), `'replace'` (só o escolhido fica; atribui antes de remover os demais) ou `'remove_all'` (tira TODOS os responsáveis; `agent_id` dispensado) |
|
|
562
565
|
| `add_card_note` | `{ text }` | Nota no card. **A chave é `text`**, igual à irmã `add_private_note`. Aqui é mais grave: o motor lê SÓ `text`, sem rede — nota criada com `content` sairia REALMENTE vazia, não só invisível no formulário. Corrigido em 04/09 (a linha dizia `content`); a gravação normaliza `content` para `text` |
|
|
563
566
|
| `add_card_checklist` | `{ template_id, funnel_id?, card_source? }` | Aplica um MODELO de checklist ao card (vira um grupo). `template_id` de `kanban_config.checklist_templates`. Um modelo por bloco (repita o bloco pra mais de um) |
|
|
@@ -573,7 +576,7 @@ o botão "Usar variável" ao lado do campo alterna lista fixa ↔ variável.
|
|
|
573
576
|
|
|
574
577
|
**Handles que SAEM:** `success`. Não tem handle `error` — falhas viram warning silencioso e o flow continua.
|
|
575
578
|
|
|
576
|
-
**`card_source` (blocos de card) — opcional:** as ações de card aceitam `card_source`: `'funnel'` (default — procura o card pelo `funnel_id`) ou `'trigger'` (usa o card que DISPAROU o flow, em flows iniciados por `card_created`/`card_moved`/`card_won`/`card_lost`). Com `'trigger'`, `funnel_id` deixa de ser obrigatório — EXCETO em `move_kanban_stage`/`create_kanban_item`, cujo funil/etapa são o DESTINO. Sem card-gatilho disponível, a ação é pulada (não cai no fallback de funil). Aplica-se a `move_kanban_stage`, `set_won`/`set_lost`/`set_open`, `assign_agent_card`, `add_card_note`, `add_card_checklist`, `add_card_offer`, `update_attribute` (com `attr_source: 'card'`) e às condições `card_attr_equals`/`card_attr_contains` (gravando `card_source` na própria regra).
|
|
579
|
+
**`card_source` (blocos de card) — opcional:** as ações de card aceitam `card_source`: `'funnel'` (default — procura o card pelo `funnel_id`) ou `'trigger'` (usa o card que DISPAROU o flow, em flows iniciados por `card_created`/`card_moved`/`card_won`/`card_lost`/`card_opened`/`card_snoozed`). Com `'trigger'`, `funnel_id` deixa de ser obrigatório — EXCETO em `move_kanban_stage`/`create_kanban_item`, cujo funil/etapa são o DESTINO. Sem card-gatilho disponível, a ação é pulada (não cai no fallback de funil). Aplica-se a `move_kanban_stage`, `set_won`/`set_lost`/`set_open`, `snooze_kanban_item` (esta, sem card-gatilho, dá ERRO em vez de pular), `assign_agent_card`, `add_card_note`, `add_card_checklist`, `add_card_offer`, `update_attribute` (com `attr_source: 'card'`) e às condições `card_attr_equals`/`card_attr_contains` (gravando `card_source` na própria regra).
|
|
577
580
|
|
|
578
581
|
**`send_conversion` — Enviar conversão (2026-09-01):**
|
|
579
582
|
|
|
@@ -623,6 +626,12 @@ o botão "Usar variável" ao lado do campo alterna lista fixa ↔ variável.
|
|
|
623
626
|
|
|
624
627
|
**Empresa e Cargo (2026-09-25):** `contact.company_name` e `contact.job_title` valem em CONDIÇÃO (`attr_source: 'contact'`, `attr_key` igual ao path), em filtro de regras e como variável (`{{contact.company_name}}`, `{{contact.job_title}}`). São SÓ LEITURA: a ação "Alterar atributo do contato" NÃO grava esses dois (o texto Empresa anda junto com a empresa vinculada — para ligar a empresa use `lionchat_contacts_update` com `company_id`).
|
|
625
628
|
|
|
629
|
+
**Empresa do contato (2026-10-16):** a empresa ligada ao contato da conversa (no máximo UMA por contato) vale como VARIÁVEL e como CONDIÇÃO, só com o módulo Empresas ligado.
|
|
630
|
+
- Variável em qualquer bloco de mensagem: `{{contact.company.name}}`, `{{contact.company.legal_name}}`, `{{contact.company.cnpj}}`, `{{contact.company.phone}}`, `{{contact.company.email}}`, `{{contact.company.address.city}}`, `{{contact.company.address.state}}` e `{{contact.company.custom_attribute.<chave>}}` (campo personalizado da empresa). Contato sem empresa = vazio. Data do campo personalizado: DD/MM/AAAA no bloco de mensagem; crua (AAAA-MM-DD) em API, Definir variável e Condição — igual ao atributo do contato.
|
|
631
|
+
- Condição (bloco Condição, aba Atributos, card "Atributo da empresa"): `{ "valueType": "attr_config", "attrSource": "company", "attr_key": "segmento", "operator": "equal", "value": "", "values": ["Varejo"] }`. `attr_key` = chave do campo personalizado OU cadastro com prefixo `company.name`, `company.legal_name`, `company.cnpj` (comparado só pelos dígitos), `company.phone`, `company.email`, `company.address.city`, `company.address.state`. Contato sem empresa = valor vazio (`not_equal`/`is_empty` casam). Módulo Empresas DESLIGADO = a regra NUNCA casa, nem a negativa.
|
|
632
|
+
- `attrSource` fora de `contact`/`conversation`/`card`/`company` NÃO casa (antes comparava a última mensagem do cliente) e marca o bloco com aviso.
|
|
633
|
+
- NÃO vale em condição de SAÍDA (`exit_conditions`), gatilho de entrada, parâmetro de ferramenta de IA nem em `update_attribute` (a ação não grava na empresa).
|
|
634
|
+
|
|
626
635
|
**Campos NATIVOS do contato (2026-07-29):** com `attr_source: 'contact'`, `attr_key` também aceita os paths canônicos `contact.name`, `contact.email`, `contact.cpf`, `contact.cnpj`, `contact.rg`, `contact.passport`, `contact.date_of_birth`, `contact.gender`, `contact.marital_status`, `contact.profession` e `contact.address.{cep,street,number,complement,neighborhood,city,state,country}` — gravam na ficha nativa do contato (não em custom_attributes). Regras: telefone/identifier/etiquetas NÃO são aceitos (mapa fechado — chave fora dele vira atributo personalizado comum); documentos, nascimento, gênero e **e-mail** só preenchem campo VAZIO; nome/profissão/estado civil/endereço sobrescrevem; valor em branco nunca grava; gênero aceita `m|f|o|na` e estado civil `solteiro|casado|uniao_estavel|divorciado|separado|viuvo`; data de nascimento em `dd/mm/aaaa` ou `aaaa-mm-dd`. Recusas aparecem no histórico de execução (passo 'skipped'/'error' com mensagem).
|
|
627
636
|
|
|
628
637
|
**Campos NATIVOS do contato em CONDIÇÃO (2026-08-13):** o bloco de Condições e o filtro do gatilho de data passaram a LER os mesmos paths nativos (`contact.name`, `contact.cpf`, `contact.marital_status`, `contact.address.city`, ...) na fonte `contact` — antes só liam atributo personalizado e o campo da ficha voltava vazio, jogando tudo na saída padrão em silêncio. Use com `is_empty`/`is_not_empty` para montar "o CPF está preenchido?". Aceita a forma curta (`contact.cpf`) e a longa (`contact.cadastral.cpf`). **`contact.label` NÃO é aceito** em condição (consulta cara em caminho reativo). **Gênero e estado civil são listas fechadas**: compare com o valor canônico (`m|f|o|na`, `solteiro|casado|uniao_estavel|divorciado|separado|viuvo`) — comparar com "Masculino" nunca casa.
|
|
@@ -959,6 +968,24 @@ erro). Número de celular BR escrito sem o 9 é corrigido pelo WhatsApp antes de
|
|
|
959
968
|
sessão do canal, orçamento 8 s). Antes de 21/08 o passo dava SUCESSO mesmo com o lead fora do grupo. A
|
|
960
969
|
mesma correção do 9º dígito vale no `add_participants`.
|
|
961
970
|
|
|
971
|
+
**Quem volta só com o código interno (2026-10-09):** o WhatsApp devolve a pessoa RECÉM-COLOCADA só com o
|
|
972
|
+
código interno dela (`<código>@lid`, sem telefone) — e horas depois continua assim. Até 09/10 o bloco comparava
|
|
973
|
+
só telefone: `add_participants` acusava `nobody_changed`/`not_added` com a pessoa DENTRO do grupo (o fluxo
|
|
974
|
+
parava), `create` dava `partial` falso (e mandava convite para quem já estava) e `remove_participants` dava
|
|
975
|
+
SUCESSO falso. Desde 09/10 o bloco confere pelo telefone e, só para quem não casou, pergunta ao WhatsApp o
|
|
976
|
+
código daquele telefone. Sem resposta do WhatsApp = conta como NÃO colocado (nunca inventa que entrou). Limite
|
|
977
|
+
conhecido: número que não passou pela conferência de existência (fora do Brasil) e volte só com o código
|
|
978
|
+
continua contando como fora.
|
|
979
|
+
|
|
980
|
+
**De onde veio cada número (2026-10-09):** nas operações com `groupParticipants`, o passo do bloco no
|
|
981
|
+
HISTÓRICO da execução (não a variável `{{grupo.*}}`) traz `participant_sources` — um item por número com
|
|
982
|
+
`number`, `source` (a LINHA do campo de participantes de onde ele saiu), `typed` (`true` = digitado, sem
|
|
983
|
+
variável), `informed` (o número como foi escrito, quando o WhatsApp usa outra forma) e, quando a linha é UM
|
|
984
|
+
atributo personalizado sozinho (`{{conversation.custom_attribute.x}}` / `{{contact.custom_attribute.x}}`),
|
|
985
|
+
`filled_by`/`filled_at` (quem preencheu aquele atributo e quando). É só anotação: nunca muda quem vai no
|
|
986
|
+
pedido; origem e autor podem faltar, mas nunca saem errados. Use para responder "de onde saiu esse número?"
|
|
987
|
+
em vez de concluir que o número "não está configurado".
|
|
988
|
+
|
|
962
989
|
**Convite no privado de quem ficou de fora (opcional, nasce desligado; só `create`/`add_participants`;
|
|
963
990
|
2026-08-21 — entra com o próximo deploy do app depois de 21/08/2026):** `groupInviteOnFailure: true` +
|
|
964
991
|
`groupInviteMessage` (texto OBRIGATÓRIO nesse modo — sem texto = `invite_status: 'sem_mensagem'` e nada
|
|
@@ -1064,6 +1091,31 @@ de conexão e viram bola de neve visual. Ao gerar `position`:
|
|
|
1064
1091
|
|
|
1065
1092
|
---
|
|
1066
1093
|
|
|
1094
|
+
### 2.15 `ai_call` — "Ligar com IA" (17/10/2026)
|
|
1095
|
+
|
|
1096
|
+
So em conta com `ai_calling` + `lioncalls_calling`. A IA liga para o **telefone do contato** da conversa do flow
|
|
1097
|
+
pela linha de ligacao do WhatsApp (LionCalls).
|
|
1098
|
+
|
|
1099
|
+
```json
|
|
1100
|
+
{ "id": "ligar", "type": "ai_call", "position": {"x": 600, "y": 0},
|
|
1101
|
+
"data": { "aiCallAgentId": 4, "aiCallInboxId": 82 } }
|
|
1102
|
+
```
|
|
1103
|
+
|
|
1104
|
+
- `aiCallAgentId`: id de `lionchat_captain_call_agents_list`. O que a IA fala, a voz e o **tempo maximo** da ligacao
|
|
1105
|
+
vem do agente (`max_duration_seconds`, 30-600 s; no tempo o motor desliga sozinho).
|
|
1106
|
+
- `aiCallInboxId`: id de `meta.dial_inboxes` da mesma lista (caixa com a ligacao ligada).
|
|
1107
|
+
- Saidas: `answered` (atendeu), `no_answer` (nao atendeu/recusou), `error` (nao deu pra ligar; motivo no historico).
|
|
1108
|
+
`answered`/`no_answer` sem edge = o flow termina; `error` sem edge = execucao "Falhou".
|
|
1109
|
+
- Liga **uma vez**. Para insistir, outro `ai_call` depois de `no_answer` (com um `wait` no meio). **Nunca** ligue
|
|
1110
|
+
`error` direto em outro `ai_call`.
|
|
1111
|
+
- Nao confere horario (use `condition` antes). Linha ocupada: espera a vez por ate 2 h (a IA sempre deixa uma vaga
|
|
1112
|
+
para a equipe).
|
|
1113
|
+
- **Proibido** em flow `action`, em flow de grupo e em `ai_tool` (o save recusa). Id de outra conta tambem e recusado.
|
|
1114
|
+
|
|
1115
|
+
**Receita — a IA de atendimento pede a ligacao:** etiqueta `ligar`; o cenario manda por a etiqueta quando o cliente
|
|
1116
|
+
pede para falar por telefone; flow `conversation` com gatilho `label_added` (`label_names: ["ligar"]`) -> action
|
|
1117
|
+
`remove_conversation_label` (`labels: ["ligar"]`) logo depois do start -> `ai_call`.
|
|
1118
|
+
|
|
1067
1119
|
## 2-B. Três tipos de flow: `conversation`, `ai_tool` e `action`
|
|
1068
1120
|
|
|
1069
1121
|
O campo `flow_type` (definido na criação, IMUTÁVEL depois) decide a natureza do flow:
|
|
@@ -1180,7 +1232,7 @@ Sempre presente:
|
|
|
1180
1232
|
|
|
1181
1233
|
| Variável | Conteúdo |
|
|
1182
1234
|
|---|---|
|
|
1183
|
-
| `{{trigger.type}}` | código do **EVENTO** que disparou — **NÃO é a chave do item do Início**. Valores reais: `message_created` (gatilho `message_received`), `message_sent`, `conversation_created`, `conversation_opened` (gatilho `conversation_reopened`), `conversation_resolved`, `label_added`, `label_removed`, `team_changed`, `assignee_changed`, `sla_missed`, `kanban_item_created`/`card_created`, `kanban_item_stage_changed`/`card_moved`, `card_status_changed` (`card_won` e `
|
|
1235
|
+
| `{{trigger.type}}` | código do **EVENTO** que disparou — **NÃO é a chave do item do Início**. Valores reais: `message_created` (gatilho `message_received`), `message_sent`, `conversation_created`, `conversation_opened` (gatilho `conversation_reopened`), `conversation_resolved`, `label_added`, `label_removed`, `team_changed`, `assignee_changed`, `sla_missed`, `kanban_item_created`/`card_created`, `kanban_item_stage_changed`/`card_moved`, `card_status_changed` (`card_won`, `card_lost`, `card_opened` e `card_snoozed` — olhe `{{trigger.kanban.status}}`: `won`/`lost`/`open`/`snoozed`; rótulo "Situação do card mudou" desde 11/10/2026), `conversation_attributes_changed`, `card_attributes_changed`, `contact_attribute_changed`, `group_participant_joined`/`_left`, `webhook_received`, `date_trigger`, `manual` (sidebar), `kanban_manual` (botão do card), `campaign` (Campanha de Fluxo), `page_track`, `activated_by_flow` (fluxo chamou fluxo), `lead_form` (os 3 gatilhos de formulário — `trigger.kind` diz `completed`/`milestone`/`abandoned`), `booking_created`/`booking_cancelled`/`booking_rescheduled`/`booking_completed`. Compare SEMPRE com esses códigos numa condição |
|
|
1184
1236
|
| `{{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 |
|
|
1185
1237
|
| `{{trigger.activated_at}}` | quando disparou (ISO 8601). Desde 20/08/2026 `name` e `activated_at` são preenchidos em TODOS os caminhos de disparo (antes só no de evento de conversa) |
|
|
1186
1238
|
| `{{trigger.kanban_item_id}}` / `{{trigger.funnel_id}}` | só quando veio do Kanban |
|
|
@@ -1220,9 +1272,10 @@ Oferecidos no autocompletar (só quando o bloco Início tem o gatilho que os pre
|
|
|
1220
1272
|
|
|
1221
1273
|
| Gatilhos do Início | Variáveis |
|
|
1222
1274
|
|---|---|
|
|
1223
|
-
| `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) |
|
|
1275
|
+
| `card_created`, `card_moved`, `card_won`, `card_lost`, `card_opened`, `card_snoozed`, `card_attribute_changed` | `{{trigger.kanban.title}}`, `{{trigger.kanban.funnel_name}}`, `{{trigger.kanban.stage_name}}`, `{{trigger.kanban.stage}}` (código da etapa) |
|
|
1224
1276
|
| `card_moved` | `{{trigger.kanban.previous_stage_name}}`, `{{trigger.kanban.previous_stage}}` |
|
|
1225
|
-
| `card_won`, `card_lost` | `{{trigger.kanban.status}}` (`won`/`lost`) |
|
|
1277
|
+
| `card_won`, `card_lost`, `card_opened`, `card_snoozed` | `{{trigger.kanban.status}}` (`won`/`lost`/`open`/`snoozed`) |
|
|
1278
|
+
| `card_opened` | `{{trigger.kanban.previous_status}}` (`snoozed` = voltou do adiamento; `won`/`lost` = reabriram um ganho/perdido) |
|
|
1226
1279
|
| `label_added`, `label_removed` | `{{trigger.label.name}}` |
|
|
1227
1280
|
| `assignee_changed` | `{{trigger.assignee.name}}` (vazio = responsável removido) |
|
|
1228
1281
|
| `team_changed` | `{{trigger.team.name}}` (vazio = equipe removida) |
|
|
@@ -1235,7 +1288,7 @@ Resolvem mas NÃO aparecem no seletor (produtor único — só o gatilho daquela
|
|
|
1235
1288
|
`{{trigger.eclinica.event|unit|date|time|compromisso|idagenda}}`, `{{trigger.lead.form|page|ad|adset|campaign|platform}}`
|
|
1236
1289
|
(nome do anúncio, não dado de pessoa), `{{trigger.dtmf.key|campaign}}`, `{{trigger.reminder.date|time|compromisso|unit|days_before}}`,
|
|
1237
1290
|
além de `{{trigger.kanban.id}}`/`funnel_id` (use `{{trigger.kanban_item_id}}`/`{{trigger.funnel_id}}`),
|
|
1238
|
-
`{{trigger.assignee.id}}`, `{{trigger.team.id}}
|
|
1291
|
+
`{{trigger.assignee.id}}`, `{{trigger.team.id}}` (`{{trigger.kanban.previous_status}}` passou a ser oferecida no `card_opened`, 11/10/2026) e
|
|
1239
1292
|
`{{trigger.group.participants_count}}`. As RESPOSTAS do lead do Meta não viram variável (só aparecem no
|
|
1240
1293
|
histórico). Sessões anteriores a 22/08 não têm fatos gravados: essas variáveis saem vazias nelas.
|
|
1241
1294
|
O bloco do card chama-se `kanban` — nunca `card`. Se o cliente precisar de um dado que não está aqui,
|
|
@@ -1280,7 +1333,7 @@ texto trocava o protocolo pelo id interno do banco.
|
|
|
1280
1333
|
{ "attr_key": "status", "attrSource": "conversation", "operator": "equal", "value": "cancelado" }
|
|
1281
1334
|
] }
|
|
1282
1335
|
```
|
|
1283
|
-
- `attrSource` (`'contact'`|`'conversation'`|`'card'`) VAI na rule (ao contrário do gatilho de entrada por atributo, onde é implícito).
|
|
1336
|
+
- `attrSource` (`'contact'`|`'conversation'`|`'card'`) VAI na rule (ao contrário do gatilho de entrada por atributo, onde é implícito). `'company'` NÃO vale aqui (só no bloco Condição): a regra de saída não lê a empresa.
|
|
1284
1337
|
- `operator` (contexto REATIVO — desde 09/07 SEM `is_empty`/`is_not_empty`, que dispararia a cada evento; use-os só no nó Condição): `equal`/`not_equal`/`contains`/`not_contains`/`starts_with`/`ends_with`/`greater_than`/`less_than`/`number_range`. Multi-valor via `values: [...]` no lugar de `value`.
|
|
1285
1338
|
- Reativa (09/07): só é reavaliada quando o atributo VIGIADO daquela rule realmente muda — não a cada mensagem. Cada rule exige `attr_key` + (`value` ou `values`); rule sem isso é ignorada.
|
|
1286
1339
|
- `card` aceita `funnel_id`/`card_source` opcionais na rule.
|
|
@@ -35,6 +35,7 @@ caixa de WhatsApp vinculada e (opcionalmente) dispara um fluxo do FlowBuilder no
|
|
|
35
35
|
| **Formulário público** (este documento) | Página de captação hospedada pelo LionChat, com blocos e link próprio |
|
|
36
36
|
| **MetaLeadForm** | Formulário de anúncio da Meta (Facebook/Instagram Lead Ads) — outro módulo |
|
|
37
37
|
| **Flow / FlowBuilder** | Motor de automação de conversa. O formulário *dispara* fluxos, mas não é um fluxo |
|
|
38
|
+
| **Formulário do WhatsApp** (17/10/2026) | Formulário nativo da Meta, preenchido DENTRO do WhatsApp, aberto por botão de modelo de mensagem. Ferramentas `lionchat_whatsapp_forms_*` — seção própria no fim deste documento |
|
|
38
39
|
|
|
39
40
|
## Ferramentas disponíveis
|
|
40
41
|
|
|
@@ -608,3 +609,141 @@ agendar (com `required: true` essa saída deixa de existir). O tipo de evento ve
|
|
|
608
609
|
blocos. Teste o trecho seguinte pela página pública.
|
|
609
610
|
- **`stats.views` é de vida inteira** (ignora `days`); `stats.milestones` não vê marco em `items`.
|
|
610
611
|
- **`name` é interno; `settings.public_title` é o que o lead vê** (vazio = cai no `name`).
|
|
612
|
+
|
|
613
|
+
## Formulário do WhatsApp (WhatsApp Flows da Meta) — 17/10/2026
|
|
614
|
+
|
|
615
|
+
Segundo tipo da área Formulários. É o formulário **nativo do WhatsApp**: o cliente toca num botão de um modelo de
|
|
616
|
+
mensagem e preenche sem sair do WhatsApp; as respostas voltam para a conversa ("Formulário respondido", pergunta por
|
|
617
|
+
pergunta). Só caixa do **WhatsApp Oficial** (Cloud API). Montar, publicar, aposentar e excluir = só administrador;
|
|
618
|
+
listar e ver = qualquer pessoa da conta. Não confundir com o **Formulário público** (o resto deste documento, página
|
|
619
|
+
com link próprio) nem com o formulário de anúncio da Meta (MetaLeadForm).
|
|
620
|
+
|
|
621
|
+
### Ferramentas
|
|
622
|
+
|
|
623
|
+
| Ferramenta | Para quê |
|
|
624
|
+
|---|---|
|
|
625
|
+
| `lionchat_whatsapp_forms_list` | Lista (`inbox_id` filtra pela conta do WhatsApp; `with_questions=true` traz `questions: [{code, label}]`; `refresh=true` relê o estado na Meta) |
|
|
626
|
+
| `lionchat_whatsapp_forms_show` | Rascunho completo, `save_targets`, `image_urls`, `limits` (os limites da Meta, por tipo), `published_version`, `version_outdated` |
|
|
627
|
+
| `lionchat_whatsapp_forms_create` | Cria rascunho `{name, inbox_id, editor_data?}` — nada vai para a Meta ainda |
|
|
628
|
+
| `lionchat_whatsapp_forms_update` | Salva `name`, `editor_data` (SUBSTITUI o rascunho inteiro) e/ou `save_targets` |
|
|
629
|
+
| `lionchat_whatsapp_forms_images` | Sobe imagem POR LINK (`url` http/https de imagem pública): o servidor baixa, reduz para o limite da Meta e devolve `{blob_id, url, width, height}` |
|
|
630
|
+
| `lionchat_whatsapp_forms_publish` | Gera o arquivo, cria/edita na Meta e publica |
|
|
631
|
+
| `lionchat_whatsapp_forms_preview` | Endereço da prévia oficial da Meta (abre sem login, 30 dias) |
|
|
632
|
+
| `lionchat_whatsapp_forms_deprecate` | Aposenta na Meta — IRREVERSÍVEL |
|
|
633
|
+
| `lionchat_whatsapp_forms_destroy` | Exclui rascunho ou aposentado |
|
|
634
|
+
|
|
635
|
+
### Passo a passo
|
|
636
|
+
1. `_create` com `name` (único na conta do WhatsApp — a Meta recusa nome repetido ao publicar) e `inbox_id` de uma
|
|
637
|
+
caixa oficial da conta (outra caixa = 422 `inbox_must_be_official`).
|
|
638
|
+
2. Imagem (se houver): `_images` com o link → use o `blob_id` em `{ "type": "image", "image": "<blob_id>" }`.
|
|
639
|
+
3. `_update` com o `editor_data` completo (leia com `_show` antes de editar: o rascunho é substituído inteiro).
|
|
640
|
+
4. `_publish`. Fica PARA SEMPRE na conta do WhatsApp do cliente (só dá para aposentar). Republicar depois de editar
|
|
641
|
+
mantém os modelos funcionando, sem nova aprovação.
|
|
642
|
+
5. Botão no modelo: `lionchat_inboxes_whatsapp_templates_create` com
|
|
643
|
+
`{type: 'BUTTONS', buttons: [{type: 'FLOW', text: 'Preencher', flow_id: '<meta_flow_id>', flow_action: 'navigate'}]}`
|
|
644
|
+
(`meta_flow_id` vem do `_list`/`_show`; o formulário tem de estar publicado; no máximo 1 botão FLOW por modelo; texto
|
|
645
|
+
do botão até 25). A Meta costuma aprovar em minutos e pode trocar a categoria para Marketing. Trocar o formulário do
|
|
646
|
+
botão de um modelo aprovado manda o modelo de volta para análise.
|
|
647
|
+
6. Envie o modelo como qualquer outro (conversa, campanha, fluxo, automação). O componente que a Meta exige para o
|
|
648
|
+
botão de formulário é montado pelo servidor — não mande nada a mais.
|
|
649
|
+
7. (Opcional) Fluxo com gatilho `whatsapp_form_answered` — config `{whatsapp_form_id: '<id nosso, STRING>'}` (vazio =
|
|
650
|
+
qualquer formulário; lista também é aceita). Variáveis `{{trigger.form.name}}`, `{{trigger.form.id}}`,
|
|
651
|
+
`{{trigger.form.f_<n>}}` (a resposta de cada pergunta já em texto).
|
|
652
|
+
|
|
653
|
+
### O `editor_data`
|
|
654
|
+
```json
|
|
655
|
+
{ "category": "SURVEY", "next_label": "Continuar", "submit_label": "Enviar",
|
|
656
|
+
"screens": [
|
|
657
|
+
{ "title": "Seus dados",
|
|
658
|
+
"fields": [
|
|
659
|
+
{ "type": "heading", "text": "Conte um pouco sobre você" },
|
|
660
|
+
{ "type": "image", "image": "123", "alt_text": "Logo da clínica" },
|
|
661
|
+
{ "type": "short_text", "label": "Seu nome", "required": true, "max_chars": 60 },
|
|
662
|
+
{ "type": "single_choice", "label": "Como nos achou?",
|
|
663
|
+
"options": [{ "label": "Instagram" }, { "label": "Indicação", "description": "Amigo ou parente" }] },
|
|
664
|
+
{ "type": "calendar", "label": "Entrada", "mode": "range", "end_label": "Saída", "days": ["Fri", "Sat"] },
|
|
665
|
+
{ "type": "photo", "label": "Foto do documento", "max_files": 2 },
|
|
666
|
+
{ "type": "link", "text": "Nossos termos", "url": "https://exemplo.com/termos" }
|
|
667
|
+
] } ] }
|
|
668
|
+
```
|
|
669
|
+
- `category`: SIGN_UP, SIGN_IN, APPOINTMENT_BOOKING, LEAD_GENERATION, CONTACT_US, CUSTOMER_SUPPORT, SURVEY, OTHER.
|
|
670
|
+
- `next_label` (botão das telas do meio) e `submit_label` (botão da última tela, que envia): até 35 caracteres.
|
|
671
|
+
Só a ÚLTIMA tela envia; as anteriores levam para a seguinte.
|
|
672
|
+
- Campo NOVO vai sem `code`: o servidor dá `f_<n>` (opções `o_<n>`). Código já publicado NUNCA é reaproveitado.
|
|
673
|
+
- Perguntas (limite do texto da pergunta entre parênteses — use `helper`, até 80, para explicar mais):
|
|
674
|
+
`short_text`, `email`, `phone`, `number`, `long_text` (20); `date` e `calendar` (40); `single_choice` (30; até 200
|
|
675
|
+
opções, passou de 20 vira lista suspensa) e `multiple_choice` (30; até 20 opções); opção até 30, descrição da opção
|
|
676
|
+
até 300; `opt_in` (aceite, 120; `read_more_url` mostra um "Ler mais" que abre o link); `photo` e `document` (80;
|
|
677
|
+
`description` até 300, `max_files` 1-10, `max_size_mb` 1-25 — a foto sai SEMPRE com no máximo 5 MB, o limite de
|
|
678
|
+
recebimento do WhatsApp oficial; foto: `source` camera_gallery|camera|gallery; arquivo: `file_kinds`
|
|
679
|
+
pdf|word|spreadsheet|presentation|image|text|compressed|video). `required: true` = obrigatória (na foto/arquivo
|
|
680
|
+
vira "pelo menos 1").
|
|
681
|
+
- Ajustes: `max_chars` (NÚMERO 1-4000), `min_date`/`max_date` "AAAA-MM-DD" (data fixa — não existe "a partir de
|
|
682
|
+
hoje"), calendário `mode` single|range + `end_label`/`end_helper` (rótulo e ajuda do fim; a ajuda vai nas DUAS
|
|
683
|
+
pontas ou em nenhuma) + `title` (80) + `description` (300) + `days` (Mon..Sun, os dias que podem ser escolhidos);
|
|
684
|
+
escolha múltipla `min_selected`/`max_selected` (nunca acima do número de opções, mínimo nunca acima do máximo).
|
|
685
|
+
- Conteúdo (`text`): `heading` e `subheading` (80), `paragraph` e `caption` (4096), `link` (`text` até 25 + `url`
|
|
686
|
+
http/https), `image` (`image` = `blob_id` do `_images`, `alt_text` até 100).
|
|
687
|
+
- Tetos: 10 telas; 40 campos e 5 aceites por tela; título de tela 30; por tela 1 foto/arquivo, 3 imagens e 2 links;
|
|
688
|
+
até 10 arquivos no formulário inteiro (soma do `max_files`).
|
|
689
|
+
|
|
690
|
+
### Salvar x publicar (onde cada erro aparece)
|
|
691
|
+
- **Salvar** (`_create`/`_update`) recusa com 422 `{errors: [...]}` só o FORMATO: tipo desconhecido, número fora da
|
|
692
|
+
faixa, data fora do formato, lista com valor desconhecido, `category` fora da lista, telas fora de 1-10, mais de 40
|
|
693
|
+
campos ou 5 aceites numa tela, opções em formato errado. Limite de caracteres da Meta NÃO barra o salvar
|
|
694
|
+
(dá para salvar no meio do caminho).
|
|
695
|
+
- **Publicar** recusa com 422 `{problems: [{code, screen, field, limit}], error, form}` (`screen`/`field` começam em
|
|
696
|
+
0). Códigos de `problems`:
|
|
697
|
+
|
|
698
|
+
| code | O que corrigir |
|
|
699
|
+
|---|---|
|
|
700
|
+
| `no_questions` | o formulário não tem nenhuma pergunta |
|
|
701
|
+
| `empty_label` / `empty_text` | pergunta sem texto / conteúdo sem texto |
|
|
702
|
+
| `too_long` (`limit`) | texto acima do limite daquele tipo (pergunta, ajuda, fim do intervalo, link, texto alternativo) |
|
|
703
|
+
| `title_too_long` / `button_too_long` | título de tela acima de 30 / botão acima de 35 |
|
|
704
|
+
| `description_too_long` | descrição de foto/arquivo/calendário acima de 300 |
|
|
705
|
+
| `no_options` / `empty_option` / `option_too_long` / `option_description_too_long` | escolha sem opções / opção vazia / opção acima de 30 / descrição de opção acima de 300 |
|
|
706
|
+
| `selection_invalid` | mínimo/máximo de marcações impossível |
|
|
707
|
+
| `date_range_invalid` | data mínima depois da máxima |
|
|
708
|
+
| `empty_end_label` / `range_helper_incomplete` / `calendar_title_too_long` | intervalo sem rótulo do fim / ajuda numa ponta só / título do calendário acima de 80 |
|
|
709
|
+
| `invalid_url` / `invalid_read_more_url` | link ou "Ler mais" sem http/https |
|
|
710
|
+
| `no_image` / `image_missing` | imagem sem arquivo / arquivo que não é deste formulário (suba de novo pelo `_images`) |
|
|
711
|
+
| `too_many_links` / `too_many_images` / `too_many_pickers` | mais de 2 links / 3 imagens / 1 foto-arquivo na mesma tela |
|
|
712
|
+
| `too_many_files` | soma de arquivos acima de 10 no formulário |
|
|
713
|
+
|
|
714
|
+
`error.kind`: `no_channel` (nenhuma caixa oficial dessa conta do WhatsApp), `busy` (publicação em andamento),
|
|
715
|
+
`duplicate_name` (nome já usado nessa conta do WhatsApp), `validation` (a Meta recusou o arquivo; a mensagem diz
|
|
716
|
+
onde), `meta`, `network`, `too_large`, `unexpected`.
|
|
717
|
+
- `_update` durante uma publicação devolve 409 `busy`.
|
|
718
|
+
|
|
719
|
+
### "Salvar em" (`save_targets`)
|
|
720
|
+
`{"f_1": "contact.name", "f_2": "custom.cidade"}` no `_update`. Destinos: `contact.name`, `contact.email`,
|
|
721
|
+
`contact.cadastral.<cpf|rg|cnpj|passport|profession|marital_status|gender|date_of_birth>`,
|
|
722
|
+
`contact.address.<cep|street|number|complement|neighborhood|city|state|country>`, `custom.<chave do contato>`,
|
|
723
|
+
`conversation_custom.<chave da conversa>`. O atributo precisa existir na conta (`lionchat_custom_attributes_list`)
|
|
724
|
+
e não ser protegido; destino inválido = 422 (inclusive código de pergunta de foto/arquivo, ou que não existe no
|
|
725
|
+
rascunho nem na última publicação). Telefone nunca. Vale na hora (não precisa publicar). Grava quando o cliente
|
|
726
|
+
envia: dado novo vence, resposta em branco não apaga, valor que não cabe no tipo do atributo não grava. Pergunta
|
|
727
|
+
tirada do rascunho mantém o destino até publicar de novo (a versão no ar ainda pergunta). Foto e arquivo não têm
|
|
728
|
+
destino: chegam como anexo da própria mensagem de resposta.
|
|
729
|
+
|
|
730
|
+
### Como a resposta chega (para ler depois)
|
|
731
|
+
- Mensagem ENTRANTE na conversa do cliente, texto fixo "Formulário respondido", `content_type: form`, com
|
|
732
|
+
`content_attributes.items` (`[{name: 'f_1', label: 'Seu nome'}]`) e `content_attributes.submitted_values`
|
|
733
|
+
(`[{name: 'f_1', value: 'Maria'}]`) — leia por `lionchat_conversations_messages_list`.
|
|
734
|
+
- Os valores já vêm legíveis: opção pelo nome, data DD/MM/AAAA, intervalo "DD/MM/AAAA a DD/MM/AAAA", aceite Sim/Não,
|
|
735
|
+
foto/arquivo "N arquivos: nomes" (os arquivos vêm como anexos da mesma mensagem; arquivo acima do limite de
|
|
736
|
+
recebimento fica de fora).
|
|
737
|
+
- `content_attributes.whatsapp_form`: `form_id`, `publication_number`, `flow_token` e `raw` (as respostas cruas).
|
|
738
|
+
Sem nenhuma resposta: "Formulário respondido (nenhuma resposta preenchida)"; ilegível: "Formulário recebido (não
|
|
739
|
+
foi possível ler as respostas)" com `whatsapp_form.unreadable = true`.
|
|
740
|
+
- A IA de atendimento lê as respostas; a resposta reabre a conversa como qualquer mensagem do cliente. Fluxo parado
|
|
741
|
+
em "Aguardar resposta" só segue depois do "Salvar em" gravar.
|
|
742
|
+
|
|
743
|
+
### Armadilhas
|
|
744
|
+
- **Aposentar (`_deprecate`) é irreversível** e derruba todo modelo que abre o formulário. Confirme com o usuário.
|
|
745
|
+
- `_destroy` só apaga rascunho ou aposentado (publicado = `deprecate_first`).
|
|
746
|
+
- `version_outdated: true` no `_show` = publicado numa versão que a Meta não aceita mais: publicar de novo.
|
|
747
|
+
- `flow_id` do botão é o `meta_flow_id` (número da Meta), não o `id` nosso; o gatilho do fluxo usa o `id` nosso.
|
|
748
|
+
- Imagem: só por LINK de imagem pública (página da web, endereço interno ou arquivo que não é imagem = 422
|
|
749
|
+
`fetch_failed`/`invalid_image`; acima de 10 MB = `file_too_large`).
|
|
@@ -214,6 +214,13 @@ comportamento intencional.
|
|
|
214
214
|
- `funnel_stage`: nome da etapa atual (string)
|
|
215
215
|
- `position`: ordem dentro da etapa (inteiro)
|
|
216
216
|
- `stage_entered_at`: timestamp de quando entrou na etapa atual
|
|
217
|
+
- Situação (11/10/2026): `item_details.status` guarda `open`/`won`/`lost`; a resposta traz também `effective_status`
|
|
218
|
+
(`open`, **`snoozed`** = adiado, `won`, `lost`) e `snoozed_until`. **Card adiado** = card aberto que sai da coluna até
|
|
219
|
+
uma data e volta sozinho nela ("Adiar até" na tela). Ferramentas `lionchat_kanban_items_snooze`/`_unsnooze`; regras
|
|
220
|
+
em kanban-deep-dive, seção "Card adiado".
|
|
221
|
+
- Venda (13/10/2026): `item_details.attributed_to` = **vendedor** do ganho ("Atribuir ganho a");
|
|
222
|
+
`item_details.co_attributed_to` = **co-participante da venda** (ex.: o SDR), só em card ganho. Regras em
|
|
223
|
+
kanban-deep-dive, seção "Co-participante da venda".
|
|
217
224
|
|
|
218
225
|
### `item_details` (jsonb)
|
|
219
226
|
```json
|
|
@@ -529,6 +536,22 @@ A plataforma opera com 6 idiomas: `en`, `es`, `fr`, `it`, `pt`, `pt_BR` (default
|
|
|
529
536
|
brasileiras: pt_BR). Conta com idioma antigo/descontinuado cai em inglês. Notas internas geradas
|
|
530
537
|
pela IA saem no idioma da conta.
|
|
531
538
|
|
|
539
|
+
## Formulário do WhatsApp (WhatsappForm) — 17/10/2026
|
|
540
|
+
|
|
541
|
+
Formulário NATIVO da Meta (WhatsApp Flows), preenchido DENTRO do WhatsApp e aberto por um botão FLOW num modelo
|
|
542
|
+
de mensagem. Só caixa do WhatsApp Oficial. Montado no LionChat (2º tipo da área Formulários) e publicado na conta
|
|
543
|
+
do WhatsApp do cliente. Ferramentas `lionchat_whatsapp_forms_*`; regras completas no resource
|
|
544
|
+
`lionchat://docs/formularios-publicos`, seção "Formulário do WhatsApp". Três formulários que NÃO são a mesma coisa:
|
|
545
|
+
**Formulário público** (LeadForm, página com link próprio), **Formulário do WhatsApp** (este) e **formulário de
|
|
546
|
+
anúncio da Meta** (MetaLeadForm, Lead Ads).
|
|
547
|
+
|
|
548
|
+
| Status | Significado |
|
|
549
|
+
|---|---|
|
|
550
|
+
| `draft` | rascunho, nunca publicado (pode excluir) |
|
|
551
|
+
| `publishing` | publicação em andamento |
|
|
552
|
+
| `published` | no ar; `unpublished_changes: true` = o rascunho mudou depois da última publicação |
|
|
553
|
+
| `deprecated` | aposentado na Meta (irreversível); pode excluir |
|
|
554
|
+
|
|
532
555
|
## LeadForm (Formulário público de captação)
|
|
533
556
|
|
|
534
557
|
Formulário de captura próprio da conta, com página pública (link `/forms/<conta>/<slug>`), montado
|
|
@@ -141,6 +141,8 @@ Um card individual dentro de uma etapa.
|
|
|
141
141
|
| `activities` | jsonb array — log de atividades |
|
|
142
142
|
| `checklist` | **O que fica guardado:** jsonb array de tarefas do card (item: `text`/`completed`/`position` + `group_id`/`group_name` opcionais para agrupar). **O que a API devolve é OUTRA coisa** — ver o aviso logo abaixo |
|
|
143
143
|
| `timer_started_at`, `timer_duration` | Timer interno do card |
|
|
144
|
+
| `effective_status` | **Só na resposta, não é coluna (11/10/2026).** A situação EFETIVA do card: `open`, `snoozed` (adiado), `won` ou `lost`. `item_details.status` continua `open` num card adiado — quem quer saber se ele está adiado lê ESTE campo. Vem em `kanban_items_list`/`_show`/`_filter`/`_search`, na busca geral, na ficha do contato e no card embutido em `conversations_show`. Ver "Card adiado" no fim |
|
|
145
|
+
| `snoozed_until` | **Só na resposta (11/10/2026).** Até quando o card está adiado (ISO 8601); `null` quando não está adiado |
|
|
144
146
|
|
|
145
147
|
> **ATENÇÃO — na maioria das respostas o `checklist` NÃO é a lista de tarefas, e sim um resumo com
|
|
146
148
|
> os números:** `{ total_count, completed_count, groups: [{ group_id, group_name, total_count,
|
|
@@ -198,9 +200,9 @@ Como gravar pelo `lionchat_kanban_items_update` (`kanban_item.item_details`):
|
|
|
198
200
|
- Mandar objeto (`{"origem_lead": "Facebook Ads"}`) no lugar da lista **APAGA todos os campos do card**: o
|
|
199
201
|
servidor só aceita itens `{name, type, value}` e o objeto vira vazio.
|
|
200
202
|
- Lista fechada de chaves do `item_details` (outras são descartadas em silêncio): title, description, status,
|
|
201
|
-
reason, win_reason, loss_reason, attributed_to,
|
|
202
|
-
custom_attributes, offers, closed_offers, closed_offer, deadline_at,
|
|
203
|
-
conversation_id, automations, notes.
|
|
203
|
+
reason, win_reason, loss_reason, attributed_to, co_attributed_to (13/10/2026, ver "Co-participante da venda"),
|
|
204
|
+
duplicated_from_id, priority, value, currency, custom_attributes, offers, closed_offers, closed_offer, deadline_at,
|
|
205
|
+
scheduling_type, scheduled_at, conversation_id, automations, notes.
|
|
204
206
|
- Para mudar UM campo sem reenviar a lista, as ações de automação/macro `update_card_attribute`
|
|
205
207
|
(`[{funnel_id, attribute_key: "<nome do campo>", value}]`) mexem só naquela entrada.
|
|
206
208
|
|
|
@@ -284,6 +286,10 @@ Log automático de eventos do card:
|
|
|
284
286
|
|
|
285
287
|
Tipos comuns: `created`, `stage_changed`, `agent_assigned`, `agent_removed`, `note_added`, `value_changed`, `priority_changed`, `archived`.
|
|
286
288
|
|
|
289
|
+
Desde 11/10/2026 também `item_snoozed` (o card foi adiado — leva `snoozed_until`) e `item_unsnoozed` (o card adiado
|
|
290
|
+
abriu — leva `reason`: `person` = alguém abriu, `automation` = automação, macro ou fluxo, `due` = chegou a data; e a
|
|
291
|
+
data que estava marcada).
|
|
292
|
+
|
|
287
293
|
Quem fez: `by_user_id`/`user` traz a pessoa; ação de automação ou flow vem com o nome da regra/fluxo;
|
|
288
294
|
ação da IA (desde 21/08/2026 — entra com o próximo deploy do app depois de 21/08/2026) vem como
|
|
289
295
|
`"IA: <nome do assistente>"` com `id` nulo — antes saía sem autor. Ao explicar um histórico de card,
|
|
@@ -503,7 +509,7 @@ PUT /api/v1/accounts/43/funnels/43
|
|
|
503
509
|
| trigger_type | trigger_value |
|
|
504
510
|
|---|---|
|
|
505
511
|
| `card_created` | `"card_created"` (literal — NUNCA vazio) |
|
|
506
|
-
| `status_change` | `"won"` ou `"
|
|
512
|
+
| `status_change` | `"won"`, `"lost"` ou `"snoozed"` (desde 11/10/2026: roda quando o card é ADIADO; trocar a data de um card já adiado NÃO roda de novo). NÃO existe `"open"` aqui |
|
|
507
513
|
| `stage_moved` | chave da etapa de DESTINO no hash `funnel.stages` (ex. `"agendar_instalacao"` — a chave, NÃO o campo `id` interno) |
|
|
508
514
|
|
|
509
515
|
**Ações (`action` + `action_config`):**
|
|
@@ -647,6 +653,9 @@ Cada card pode receber atributos custom de 3 origens diferentes. **A escolha do
|
|
|
647
653
|
`funnel_stage` com o slug que aparece em `kanban_items_show` e compare com `funnels_show`.
|
|
648
654
|
3. `position` está faltando? (cards sem position vão pro fim)
|
|
649
655
|
4. Está em outro funil? (mover entre funis muda `funnel_id`)
|
|
656
|
+
5. Está **adiado**? (desde 11/10/2026) Card adiado sai da coluna e só aparece com o botão **Adiados** ligado no topo
|
|
657
|
+
do quadro. Confira `effective_status`/`snoozed_until` em `lionchat_kanban_items_show`: ele volta sozinho na data, ou
|
|
658
|
+
abra agora com `lionchat_kanban_items_unsnooze`. Ver "Card adiado" abaixo.
|
|
650
659
|
|
|
651
660
|
## Diagnóstico: "Valor do pipeline errado"
|
|
652
661
|
|
|
@@ -747,3 +756,77 @@ com o `retroativo_em` certo.
|
|
|
747
756
|
|
|
748
757
|
A hora é montada em **UTC**, com o horário atual no dia escolhido. É o mesmo motivo do diagnóstico
|
|
749
758
|
acima: o relatório compara o carimbo como texto, então a data escolhida tem que ser a data contada.
|
|
759
|
+
|
|
760
|
+
## Card adiado — "Adiar até" (2026-10-11)
|
|
761
|
+
|
|
762
|
+
O card ganha uma situação a mais: **Adiado** — "este negócio só volta a importar no dia X". Ele sai da coluna e, na
|
|
763
|
+
data marcada, **abre sozinho** e volta para a coluna (disparando o fluxo "Card aberto", se houver).
|
|
764
|
+
|
|
765
|
+
| Regra | Detalhe |
|
|
766
|
+
|---|---|
|
|
767
|
+
| O que é | Situação **do card**, não da conversa. Mensagem do cliente NÃO abre o card; adiar o card não mexe na conversa. |
|
|
768
|
+
| Como fica gravado | `item_details.status` **continua `open`** — o adiamento mora numa tabela à parte (`kanban_item_snoozes`). Por isso o aplicativo de celular, os webhooks do cliente e a IA de atendimento continuam vendo `open`/`won`/`lost`. Para saber se está adiado, leia `effective_status` (`snoozed`) e `snoozed_until`. |
|
|
769
|
+
| Quem pode | Quem pode editar o card. Só card **aberto** pode ser adiado (ganho/perdido = 422). |
|
|
770
|
+
| Data | Pelo menos **1 hora** à frente (menos que isso = 422). Sem prazo máximo. Adiar um card já adiado **troca a data**. |
|
|
771
|
+
| O que NÃO encerra | Mover de etapa ou de funil, editar, nota, tarefa, responsável. |
|
|
772
|
+
| O que encerra | Marcar **ganho** ou **perdido** (por qualquer caminho); **abrir** de propósito (`lionchat_kanban_items_unsnooze`, `lionchat_kanban_items_create_2` com `status: "open"`, ação "Aberto" de automação/macro/fluxo); e a chegada da data. |
|
|
773
|
+
| `status: "open"` no `lionchat_kanban_items_update` | **NÃO abre** card adiado (é o mesmo salvar que o aplicativo faz o tempo todo). Para abrir, use `lionchat_kanban_items_unsnooze` ou o `change_status`. |
|
|
774
|
+
| Na data | O sistema abre o card numa rodada de até ~5 minutos depois da hora e dispara "Card aberto" **uma vez por card**. Esse fluxo entra na fila de disparos agendados: depois dos lembretes de consulta e, em caixa QR Code, no ritmo da caixa (um lote grande que vence junto sai aos poucos). |
|
|
775
|
+
| "Criar card" acha um adiado | Trata como card que **já existe**: não cria outro, move se a etapa for diferente e **não muda a situação** (continua adiado). Vale para automação, macro, fluxo e IA. |
|
|
776
|
+
|
|
777
|
+
**Ferramentas:**
|
|
778
|
+
- `lionchat_kanban_items_snooze` — `POST .../kanban_items/{id}/snooze` com `snoozed_until`.
|
|
779
|
+
- `lionchat_kanban_items_unsnooze` — `DELETE .../kanban_items/{id}/snooze` (abre agora e dispara "Card aberto").
|
|
780
|
+
- Automações de dentro do funil (`settings.automations`): gatilho `status_change` com `trigger_value: "snoozed"`
|
|
781
|
+
("Adiado" na tela do funil) roda quando o card passa de aberto para adiado.
|
|
782
|
+
- Automação e macro: ação `snooze_kanban_item` — `[{"funnel_id": 31, "amount": 3, "unit": "days"}]` (`unit` `hours`
|
|
783
|
+
ou `days`; `amount` inteiro, 1 ou mais). Em regra de evento de CARD basta `[{"amount": 3, "unit": "days"}]` (o card
|
|
784
|
+
é o do evento). Diferente das outras ações de card, ela **falha visível** quando não dá para adiar (card fechado,
|
|
785
|
+
sem card no funil, tempo inválido) — nunca passa verde sem adiar.
|
|
786
|
+
- Fluxo: ação `snooze_kanban_item`, gatilhos `card_opened` ("Card aberto") e `card_snoozed` ("Card adiado") e
|
|
787
|
+
condição `kanban_snoozed`. Ver o resource do FlowBuilder.
|
|
788
|
+
|
|
789
|
+
**Onde o adiado aparece e como filtrar:**
|
|
790
|
+
|
|
791
|
+
| Lugar | Comportamento |
|
|
792
|
+
|---|---|
|
|
793
|
+
| Quadro (`lionchat_kanban_items_list`) | Sem nenhum `show_*`, a lista traz TODAS as situações (o adiado vem com `status: "open"` e `effective_status: "snoozed"`). Com qualquer `show_*`: `show_open` vale `true` salvo se vier `"false"` (= aberto e **não** adiado) e `show_snoozed=true` inclui os adiados. **Só os adiados:** `show_snoozed=true` **e** `show_open=false`. Esta lista **ignora** `statuses`. |
|
|
794
|
+
| Filtro rico (`lionchat_kanban_items_filter`), exportação e relatório da etapa | `statuses: ["open"]` = aberto e **não** adiado; `statuses: ["snoozed"]` = adiados. |
|
|
795
|
+
| Ficha do contato (`lionchat_contacts_kanban_items_list`) | `status=snoozed` = adiados; `status=open` deixa os adiados de fora. |
|
|
796
|
+
| Busca geral (`lionchat_search_kanban_items`) | `kanban_filters` com `statuses: ["snoozed"]`. |
|
|
797
|
+
| Números | `lionchat_funnels_open_counts` conta aberto e **não** adiado. `lionchat_funnels_stage_report` traz a linha `snoozed` — mas esse relatório SEMPRE aplica os botões de situação com o padrão da tela: sem `show_*` conta só os abertos não adiados e as linhas `won`/`lost`/`snoozed` voltam zeradas (mande `show_won`/`show_lost`/`show_snoozed=true`). No relatório agregado (`lionchat_kanban_items_list_3`), `statusDistribution.open` **continua incluindo** os adiados (é a soma que o aplicativo lê) e `statusDistribution.snoozed` vem ao lado: abertos de verdade = `open − snoozed`. Parados, maiores negócios, ranking e previsão já deixam o adiado de fora. |
|
|
798
|
+
| Histórico do card | `item_snoozed` (com a data) e `item_unsnoozed` (com o motivo). |
|
|
799
|
+
|
|
800
|
+
**Laço de cadência é permitido:** um fluxo "Card aberto" que manda mensagem e adia de novo roda até alguém parar (no
|
|
801
|
+
máximo uma volta por hora por card). Avise o cliente antes de montar. **Abrir à mão também dispara "Card aberto"**: se o
|
|
802
|
+
fluxo manda mensagem, o cliente recebe na hora.
|
|
803
|
+
|
|
804
|
+
## Co-participante da venda (vendedor + SDR) — 2026-10-13
|
|
805
|
+
|
|
806
|
+
No ganho, além do vendedor (`attributed_to`, "Atribuir ganho a"), dá para marcar **UM co-participante** — ex.: o SDR
|
|
807
|
+
que trouxe a venda. A venda conta INTEIRA para o vendedor; o co-participante tem números próprios no relatório.
|
|
808
|
+
Marcar alguém como co-participante **não dá acesso ao card** nem o põe como responsável.
|
|
809
|
+
|
|
810
|
+
**Como gravar:**
|
|
811
|
+
- Junto com o ganho: `lionchat_kanban_items_create_2` (`change_status`) com `status: "won"` e `co_attributed_to: <id do
|
|
812
|
+
agente>`. Fora de `won` o parâmetro é ignorado.
|
|
813
|
+
- Depois, num card JÁ ganho: `lionchat_kanban_items_update` com `kanban_item.item_details.co_attributed_to`. Para tirar,
|
|
814
|
+
mande `null`.
|
|
815
|
+
- Mande SÓ o id (número). O nome (`co_attributed_name`) o próprio card preenche — nunca envie.
|
|
816
|
+
- Objeto ou lista no lugar do id = 422 antes de gravar.
|
|
817
|
+
|
|
818
|
+
**Recusas (422, com `error` legível):** id que não é número; pessoa que não é membro da conta; o próprio vendedor do
|
|
819
|
+
card; pessoa sem acesso ao funil (vale: funil sem lista de agentes, agente da lista do funil ou dos times dele,
|
|
820
|
+
administrador, ou quem já é responsável do card). A conferência só roda quando o valor MUDA — quem perdeu o acesso
|
|
821
|
+
depois não trava outro salvamento.
|
|
822
|
+
|
|
823
|
+
**O que mais saber:**
|
|
824
|
+
- Reabrir ou marcar como perdido **apaga** o co-participante (o campo só existe em card ganho).
|
|
825
|
+
- A ação "marcar como ganho" de fluxo, automação e macro NÃO marca co-participante (decisão do dono): ganho por ação
|
|
826
|
+
nasce sem ele, que entra depois pela tela, por `lionchat_kanban_items_update` ou pela planilha de "Importar vendas"
|
|
827
|
+
(coluna de co-participante, por nome ou e-mail).
|
|
828
|
+
- Duplicar o card não copia o co-participante.
|
|
829
|
+
- Histórico: marcado junto com o ganho vai dentro do registro da mudança de status; marcado depois gera
|
|
830
|
+
`co_participant_changed` (antes e depois, com nome e quem marcou).
|
|
831
|
+
- Números: `coParticipantRanking`, `sharedSalesSummary`/`sharedSalesBySeller` (com `include_shared_sales=true`) no
|
|
832
|
+
relatório agregado e a lista `lionchat_kanban_items_shared_sales` — ver `lionchat://docs/filtros-e-relatorios` §4.
|
|
@@ -155,7 +155,8 @@ conversa antiga que NÃO aparece no relatório de hoje (régua antiga por criaç
|
|
|
155
155
|
| "retrospectiva do ano" | `lionchat_reports_list_15` |
|
|
156
156
|
| "satisfação", "CSAT", "nota dos clientes" | `lionchat_csat_metrics` |
|
|
157
157
|
| "SLA", "cumprimento de prazo" (se a conta tiver Enterprise) | `lionchat_sla_metrics` |
|
|
158
|
-
| "quantos agendamentos", "taxa de comparecimento", "agendamentos por tipo/atendente" | `lionchat_booking_reports` (ver "Agendamentos" no fim deste guia) |
|
|
158
|
+
| "quantos agendamentos", "taxa de comparecimento", "agendamentos por tipo/atendente" | `lionchat_booking_reports` (ver "Agendamentos" no fim deste guia). Conta sem Booking (relatório zerado, compromissos marcados à mão na Agenda): `source=agenda` |
|
|
159
|
+
| "vendas com SDR", "comissão dividida", "quanto cada SDR trouxe", "vendas sozinho x compartilhadas" | `lionchat_kanban_items_list_3` (`coParticipantRanking`; `include_shared_sales=true` para o quadro) e a lista `lionchat_kanban_items_shared_sales` — ver `lionchat://docs/filtros-e-relatorios` §4 |
|
|
159
160
|
|
|
160
161
|
---
|
|
161
162
|
|
|
@@ -523,7 +524,9 @@ mesma conta misturar duas lojas e não bater com o relatório da Meta. Com qualq
|
|
|
523
524
|
`orphan_leads` (leads sem conversa ainda), `unique_leads` (deduplicados por TELEFONE),
|
|
524
525
|
`won_leads` (leads em cards de estágio de Ganho) e `conversion_rate`.
|
|
525
526
|
- `unclassified` — `{conversations, won, conversion_rate}` das conversas SEM origem (entram em `totals` mas nao em `by_platform`;
|
|
526
|
-
a venda de uma conversa iniciada pela propria empresa mora aqui).
|
|
527
|
+
a venda de uma conversa iniciada pela propria empresa mora aqui). Desde 16/10/2026 a conversa criada pelo nosso
|
|
528
|
+
lado (automação, fluxo, formulário) nasce com a origem que a ficha do contato já tinha; antes ela caía aqui
|
|
529
|
+
até o cliente responder. Vale só de hoje pra frente: as conversas antigas nesse caso continuam sem origem.
|
|
527
530
|
- Arrays de quebra: `by_platform`, `by_kind`, `by_campaign`, `by_adset`, `by_creative`. Cada linha
|
|
528
531
|
tem `{value, conversations, won, conversion_rate}`.
|
|
529
532
|
|
|
@@ -868,6 +871,12 @@ Resposta: `totals` (`total`, `pending`, `completed`, `cancelled`, `snoozed`, `at
|
|
|
868
871
|
`attendance_rate`, `attendance_basis`), `timeline`, `by_event_type`, `by_agent`, `by_origin` e
|
|
869
872
|
`treatments`.
|
|
870
873
|
|
|
874
|
+
- **`source=agenda`** (14/10): troca a fonte para os compromissos marcados À MÃO na Agenda, sem
|
|
875
|
+
Booking — ligação, reunião, videochamada e tipos da conta (tarefa comum e evento do Google ficam
|
|
876
|
+
fora). Use quando a conta não usa Booking e o relatório normal vem zerado. Nessa opção o tipo vai em
|
|
877
|
+
`task_type` (não `event_type_id`; a lista vem em `appointment_types`), `by_agent` conta pelos
|
|
878
|
+
responsáveis (quem tem dois aparece nas duas linhas, os totais contam uma vez), `by_origin` vem vazio
|
|
879
|
+
e `treatments` vem nulo.
|
|
871
880
|
- **`attended` / `no_show`** (15/09) são as marcas Compareceu/Faltou do compromisso
|
|
872
881
|
(`account_tasks.attendance`), um eixo próprio: **não mudam a situação** — compromisso "faltou"
|
|
873
882
|
continua `pending` até alguém concluir ou cancelar, igual a Agenda mostra.
|