@lionchat/mcp-server 0.4.9 → 0.5.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/client.js CHANGED
@@ -175,6 +175,11 @@ export class LionChatClient {
175
175
  let retries429 = 0;
176
176
  let retries5xx = 0;
177
177
  let retriesNetwork = 0;
178
+ // AIDEV-NOTE: B1 — só retentamos 5xx/rede em métodos idempotentes. POST não é
179
+ // idempotente: reenviar após timeout/502 (quando o Rails JÁ processou) duplicaria
180
+ // mensagem/contato/conversa. 429 segue retentando p/ todos (é pré-processamento).
181
+ const httpMethod = (fetchOptions.method || 'GET').toUpperCase();
182
+ const isIdempotent = ['GET', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'].includes(httpMethod);
178
183
  // AIDEV-NOTE: Max possible attempts = 1 initial + 3 (429) + 1 (5xx) + 1 (network)
179
184
  // In practice, only one retry category applies per request
180
185
  const maxAttempts = 1 + MAX_RETRIES_429 + MAX_RETRIES_5XX + MAX_RETRIES_NETWORK;
@@ -197,19 +202,21 @@ export class LionChatClient {
197
202
  // once and short-circuit BEFORE parsing so an empty body never throws
198
203
  // "Unexpected end of JSON input". The operation succeeded; return clean success.
199
204
  const rawText = await response.text();
200
- if (response.status === 204 || rawText.trim() === '') {
201
- if (response.ok) {
202
- return { success: true, status: response.status };
203
- }
205
+ const isEmptyBody = response.status === 204 || rawText.trim() === '';
206
+ if (isEmptyBody && response.ok) {
207
+ return { success: true, status: response.status };
204
208
  }
205
- // AIDEV-NOTE: Parse response body
209
+ // AIDEV-NOTE: Parse response body.
210
+ // B9 — corpo vazio com status de erro: não tenta parsear (JSON.parse('') jogaria
211
+ // "Unexpected end of JSON input"); deixa responseBody undefined p/ getErrorMessage.
212
+ // B4 — sempre parseia em try/catch (mesmo com content-type application/json): um
213
+ // corpo malformado (proxy/CDN/502 parcial) cai no fallback de texto em vez de
214
+ // jogar SyntaxError cru no LLM.
206
215
  let responseBody;
207
- const contentType = response.headers.get('content-type') ?? '';
208
- if (contentType.includes('application/json')) {
209
- responseBody = JSON.parse(rawText);
216
+ if (isEmptyBody) {
217
+ responseBody = undefined;
210
218
  }
211
219
  else {
212
- // AIDEV-NOTE: Try parsing as JSON even without content-type header
213
220
  try {
214
221
  responseBody = JSON.parse(rawText);
215
222
  }
@@ -238,8 +245,8 @@ export class LionChatClient {
238
245
  await sleep(delayMs);
239
246
  continue;
240
247
  }
241
- // AIDEV-NOTE: 5xx — retry once after 2s
242
- if (response.status >= 500 && retries5xx < MAX_RETRIES_5XX) {
248
+ // AIDEV-NOTE: 5xx — retry once after 2s (apenas métodos idempotentes; ver B1)
249
+ if (response.status >= 500 && isIdempotent && retries5xx < MAX_RETRIES_5XX) {
243
250
  retries5xx++;
244
251
  await sleep(2000);
245
252
  continue;
@@ -253,8 +260,8 @@ export class LionChatClient {
253
260
  if (err instanceof LionChatApiError) {
254
261
  throw err;
255
262
  }
256
- // AIDEV-NOTE: Network/timeout errors — retry once after 2s
257
- if (isNetworkError(err) && retriesNetwork < MAX_RETRIES_NETWORK) {
263
+ // AIDEV-NOTE: Network/timeout errors — retry once after 2s (apenas idempotentes; ver B1)
264
+ if (isNetworkError(err) && isIdempotent && retriesNetwork < MAX_RETRIES_NETWORK) {
258
265
  retriesNetwork++;
259
266
  lastError = err;
260
267
  await sleep(2000);
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -187,6 +187,24 @@ POST /api/v1/accounts/{account_id}/kanban_items
187
187
  3. Comparar avg_first_response_time entre agentes
188
188
  ```
189
189
 
190
+ ### Criar campanha de WhatsApp (disparo em massa)
191
+ ```
192
+ 1. Montar audience: seções Label / Funnel / ConversationAttribute + audience_mode (sum|all)
193
+ 2. lionchat_campaigns_estimate_audience (MESMO audience+mode) → mostrar contagem ao usuário
194
+ 3. CONFIRMAR com o usuário (é envio em massa — seção 7b)
195
+ 4. lionchat_campaigns_create (inbox_id define o tipo: WhatsApp oficial, QR Code/WAHA, SMS, Website)
196
+ 5. Acompanhar com lionchat_campaigns_statistics (sent/delivered/read/failed)
197
+ ```
198
+ Estrutura do audience: `[{type:'Label', id}, {type:'Funnel', id, stages:[], include_won, include_lost}, {type:'ConversationAttribute', key, value}]`.
199
+ QR Code aceita `template_params` com `delay_min/delay_max/variations` (anti-bloqueio) e `bulk_actions`.
200
+
201
+ ### Criar ferramenta da IA (ai_tool)
202
+ ```
203
+ 1. lionchat_flow_tools_create (tool_name snake_case + tool_description + flow_data com nó end)
204
+ 2. POST /flow_tools/{id}/run pra testar com parâmetros reais
205
+ 3. POST /flow_tools/{id}/assistants (assistant_ids) pra vincular ao AI Agente
206
+ ```
207
+
190
208
  ### Mudar conta ativa (somente Conector OAuth)
191
209
  ```
192
210
  1. lionchat_list_my_accounts (ver todas)
@@ -241,12 +259,20 @@ Antes de escolher a ferramenta, cheque se a intenção bate com a coluna da dire
241
259
  | Intenção do usuário | Tool certa | Cuidado |
242
260
  |---|---|---|
243
261
  | Listar / ver não lidas | `lionchat_conversations_list` (`conversation_type: 'unread'`) ou `lionchat_conversations_meta` | NÃO use `lionchat_conversations_unread` — é AÇÃO DE ESCRITA (marca como não-lida) |
244
- | Buscar por texto (nome, telefone, conteúdo) | `lionchat_conversations_search` / `lionchat_contacts_search` | NÃO baixe tudo com `*_list` e filtre na mão |
262
+ | Buscar por texto (nome, telefone, conteúdo) | `lionchat_conversations_search` / `lionchat_contacts_search` | NÃO baixe tudo com `*_list` e filtre na mão. Busca aceita multi-termo (AND) e dados cadastrais (CPF/CNPJ por dígitos) |
245
263
  | Só a contagem / números | `lionchat_conversations_meta` / `lionchat_reports_summary` | Não liste o conteúdo completo |
246
264
  | Criar contato | `lionchat_contacts_create` base (path `/contacts`) | NÃO use as variantes `_1` … `_9` |
247
265
  | Pausar a IA agora (botão de pânico) | `lionchat_captain_assistants_update` (`paused: true`, top-level) | — |
248
- | Anexar arquivo a uma mensagem | `lionchat_upload_create` primeiro, depois usar o retorno em `lionchat_conversations_messages_create` | — |
266
+ | Anexar arquivo a uma mensagem | `lionchat_upload_create` primeiro, depois usar o retorno em `lionchat_conversations_messages_create` | Confira `lionchat_upload_limits` se o arquivo for grande |
249
267
  | Marcar conversa como **lida** | `lionchat_conversations_update_last_seen` | NÃO use `unread` (esse marca como NÃO-lida) |
268
+ | Criar/gerenciar **campanha** (disparo WhatsApp/SMS) | `lionchat_campaigns_*` (criar, estatísticas) | SEMPRE rode `campaigns_estimate_audience` antes de criar e mostre a contagem. Disparo em massa = confirmação obrigatória (seção 7b) |
269
+ | Criar **flow normal** (responde mensagens na caixa) | `lionchat_flows_create` | Ler design-guide antes (seção 11) |
270
+ | Criar **ferramenta da IA** (flow que o AI Agente invoca) | `lionchat_flow_tools_create` + vincular com `flow_tools` → assistants | NÃO use `flows_create` pra ai_tool. Nó `end` obrigatório. Teste com `flow_tools_run` antes de vincular |
271
+ | Ver **ligações de voz do WhatsApp** (histórico, transcrição) | `lionchat_whatsapp_calls_*` | NÃO confundir com `voip_*` (telefonia Zenvia — ramais/saldo). "Ligação no WhatsApp" = whatsapp_calls |
272
+ | **Jornada do Lead** (por onde o lead navegou no site) | `lionchat_journey_funnel_reports` + fases em `lionchat_liontrack_journey_stages_*` | Janela máx 30 dias; exige feature liontrack |
273
+ | **Exportar contatos** (CSV completo por e-mail) | `lionchat_contacts_export` | Respeita filtros/segmento aplicados |
274
+ | Mensagem pra OUTRO AGENTE (não cliente) | `lionchat_internal_chat_*` (salas e mensagens do time) | NÃO confundir com nota privada (dentro da conversa do cliente) |
275
+ | Achar contato pelo que aconteceu com ele (conversa/card) | `lionchat_contacts_filter` com `linked_records` | Ver api-conventions → registros vinculados |
250
276
 
251
277
  ## 9. Quando NÃO chamar nenhuma ferramenta
252
278
 
@@ -319,13 +319,60 @@ Quando rate-limited:
319
319
  }
320
320
  ```
321
321
 
322
- ### Search
322
+ ### Search (overhaul 2026-06-10)
323
323
 
324
- `GET /search?q=texto` — busca cross-entidade (conversations, contacts, messages)
324
+ `GET /search?q=texto` — busca cross-entidade (conversations, contacts, messages, articles, kanban_items)
325
325
 
326
- `GET /search/contacts?q=texto` — só contatos
326
+ `GET /search/contacts?q=texto` — só contatos (idem `/search/conversations`, `/search/messages`, `/search/articles`, `/search/kanban_items`)
327
327
 
328
- `GET /search/conversations?q=texto` — só conversas
328
+ **Multi-termo com E:** `q` aceita String (espaços = AND implícito) ou Array (`q[]=joao&q[]=silva`),
329
+ cap de 5 termos — cada termo precisa bater (cada um mantém seu OR entre campos).
330
+
331
+ **Busca cadastral:** CPF/CNPJ/RG/endereço/profissão entram na busca de contatos e conversas, com
332
+ match por dígitos que ignora pontuação (`31.104.475/0001-51` == `31104475000151`; mín 3 dígitos).
333
+ Telefone idem. Cards do Kanban são achados pelo contato/conversa vinculados.
334
+
335
+ **Filtros estruturados:** params `conversation_filters`, `contact_filters`, `kanban_filters`
336
+ (JSON-string na query) aplicam condições no mesmo formato dos endpoints `/filter` — mesma
337
+ validação (allowlist de chaves, operadores por tipo, cap 10 condições). Payload inválido = 422.
338
+
339
+ ```
340
+ GET /search/conversations?q=pix&conversation_filters=[{"attribute_key":"status","filter_operator":"equal_to","values":["open"]}]
341
+ ```
342
+
343
+ ### Filtro de contatos por registros vinculados (2026-06-10)
344
+
345
+ `POST /contacts/filter` ganhou 3 chaves novas que acham o CONTATO pelo que aconteceu com ele:
346
+ - `conversation_search` — por conversa vinculada (status/etiquetas/caixa)
347
+ - atributos da conversa — condição com `custom_attribute_type: "conversation_attribute"`
348
+ - `kanban_card` — por card vinculado (funil/etapa/prioridade/status)
349
+ Combináveis com E/OU e salváveis como segmento (custom_filters).
350
+
351
+ ### Exportação de contatos (2026-06-10)
352
+
353
+ `POST /contacts/export` (chega por e-mail) agora sai COMPLETO: cadastral achatado (16 colunas),
354
+ etiquetas, empresa/cidade/país, atributos do contato e da conversa (prefixos contato_/conversa_),
355
+ última conversa (nº/status/caixa/responsável/etiquetas/data) e card Kanban (funil/etapa/prioridade/
356
+ status/valor). Filtros/segmento aplicados valem na exportação. Passar `column_names` explícito
357
+ mantém o comportamento antigo (só as colunas pedidas).
358
+
359
+ ### Limites de upload
360
+
361
+ `GET /upload_limits` retorna o teto em MB por tipo (`image`, `video`, `audio`, `document`,
362
+ `fallback`). Consulte 1x antes de subir anexo grande — evita 422 no meio do fluxo.
363
+
364
+ ### Webhooks de saída — evento novo (2026-06)
365
+
366
+ `inbox_updated` entrou na lista de eventos assináveis (`webhooks_create/update`): dispara quando
367
+ uma caixa de entrada é autorizada/reautorizada. Entrega só pra quem assinou o evento.
368
+
369
+ ### Webhook Universal (entrada) — arrays no mapeamento (2026-06)
370
+
371
+ O `field_mapping` do webhook personalizado aceita caminhos com índice de array:
372
+ `messages.0.content`, `itens.1.sku`. Limites do achatamento: profundidade 5, 10 itens por array,
373
+ 500 chaves no total. O mapeamento é POSICIONAL — se a ordem do array variar entre eventos, o
374
+ mesmo caminho captura valores diferentes. Campo `flow_id` na criação liga o webhook a um flow
375
+ (webhook embutido — ver resource de fluxos).
329
376
 
330
377
  ## Headers úteis pra mandar
331
378
 
@@ -122,6 +122,81 @@ Pra reativar: `paused=false`. Toggle é auditado (`audited only: [:paused]`).
122
122
  - `config.instructions` (system prompt do agente) aceita até **20.000 caracteres** (antes 10k). Acima de 15k, o frontend mostra aviso "lost in the middle" — prefira colocar instruções críticas no início ou final.
123
123
  - **Cache automático** ativo em todos os 15 modelos suportados (GPT-4.1 Nano até GPT-5.2 Pro, o1, o3, o4-mini). Desconto 50-75% no input cachado, sem configuração. Reuso do prompt do agente em múltiplas conversas maximiza a economia.
124
124
 
125
+ ## Follow-up automático multi-etapa (2026-06)
126
+
127
+ O follow-up do AI Agente agora suporta **cadência de até 3 etapas** via `config.follow_up_steps`:
128
+
129
+ ```json
130
+ { "config": { "feature_follow_up": true, "follow_up_steps": [
131
+ { "after_minutes": 30, "prompt": "Pergunte gentilmente se ainda tem interesse" },
132
+ { "after_minutes": 240, "prompt": "Ofereça tirar dúvidas" },
133
+ { "after_minutes": 1140, "prompt": "Última tentativa, despeça-se cordialmente" }
134
+ ] } }
135
+ ```
136
+
137
+ Regras: cada etapa ≥ 5 min; soma total ≤ 1440 min (24h); máx 3 etapas. Campos legados
138
+ `follow_up_time` + `follow_up_prompt` continuam funcionando como 1 etapa única.
139
+ Dispara quando o CLIENTE fica inativo após resposta da IA. O motor de follow-up é dedicado e
140
+ **só-leitura** (não executa ferramentas, não coleta dado — só redige a mensagem de retomada,
141
+ com saída estruturada garantida). `paused=true` no assistente corta os follow-ups também.
142
+
143
+ ## Guardrails e diretrizes de resposta (2026-06)
144
+
145
+ Dois arrays no assistente (top-level, fora do config):
146
+ - `guardrails`: limites DUROS — o que a IA nunca pode fazer (ex: "Nunca ofereça desconto",
147
+ proteção anti-pitch: "Não faça discurso de vendas se o cliente só pediu informação").
148
+ - `response_guidelines`: estilo — como responder (ex: "Respostas curtas, sem emojis").
149
+
150
+ No UPDATE, esses arrays SUBSTITUEM o valor inteiro (não fazem merge) — leia antes, reenvie completo.
151
+
152
+ ## Coleta de dados pela IA — regra DITO ≠ SALVO (2026-06)
153
+
154
+ Como a coleta de dados/cenários funciona hoje (importante pra diagnosticar "IA repergunta dado"):
155
+ - A IA salva cada dado NA HORA em que o cliente informa (não acumula pro final).
156
+ - O que vale é o que está PERSISTIDO no contato/conversa — "o cliente já disse" não conta
157
+ enquanto não salvou (DITO ≠ SALVO). Se salvou, ela NÃO repergunta.
158
+ - Campo enviado no lugar errado é redirecionado (ex: CPF mandado como telefone vai pro cadastral).
159
+ - Cadastrais são imutáveis (primeira escrita vale) — ver data-model, seção Contatos.
160
+ - Cenários são instruções inline no prompt (sem troca de personagem); o raciocínio do cenário
161
+ fica no "caderninho" da conversa (campo scenario_checklist, visível no card Raciocínio).
162
+ - Sem AI Agente ativo na conversa = NENHUMA resposta de IA (motor V1 aposentado em 2026-06).
163
+
164
+ ## Automações: atributo de Conversa vs de Contato (2026-06)
165
+
166
+ Atributos customizados podem existir com o MESMO nome nos dois escopos (ex: utm_source).
167
+ Nas condições de automação, desambigue com `custom_attribute_type`:
168
+
169
+ ```json
170
+ { "attribute_key": "utm_source", "custom_attribute_type": "conversation_attribute",
171
+ "filter_operator": "equal_to", "values": ["google"] }
172
+ ```
173
+
174
+ Sem o tipo, o filtro pode bater no escopo errado. A UI mostra sufixo "(Conversa)/(Contato)".
175
+
176
+ ## Meta Lead e CAPI (2026-06)
177
+
178
+ - Conexão Meta Lead agora é **por página selecionada** (a BM virou só rótulo — antes puxava todas
179
+ as páginas da BM). O GET da integração traz `enrichment_active` e `pending_businesses` (BMs com
180
+ pendência de permissão).
181
+ - Meta CAPI: o evento `InitiateCheckout` foi RENOMEADO para `begin_checkout`.
182
+
183
+ ## Campanhas: audiência acumulativa (2026-06)
184
+
185
+ `audience` aceita 3 tipos de seção combináveis: `Label`, `Funnel` (com stages/include_won/include_lost)
186
+ e `ConversationAttribute` ({key, value}). O campo `audience_mode` define a combinação ENTRE seções:
187
+ - `"sum"` (default): união — contato em QUALQUER seção entra
188
+ - `"all"`: interseção — contato precisa atender TODAS as seções preenchidas
189
+
190
+ SEMPRE rode `campaigns_estimate_audience` com o MESMO audience+audience_mode antes de criar a
191
+ campanha e mostre a contagem ao usuário — estimativa e disparo usam o mesmo motor (não divergem).
192
+
193
+ ## Agendamento (booking): idempotência e limites (2026-06)
194
+
195
+ - Reservar o MESMO contato+evento+horário de novo retorna a reserva existente (não duplica) —
196
+ retry de rede é seguro.
197
+ - Rate limit da reserva pública: 10/5min por IP + 20/min por conta (429 ao estourar).
198
+ - Todo agendamento aparece vinculado a uma conversa (cria/reusa a conversa do contato).
199
+
125
200
  ## Variáveis de conta (account_variables)
126
201
 
127
202
  Pra dados que se repetem (slogans, endereços, horários):
@@ -291,6 +291,26 @@ Endpoint: `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/sc
291
291
  | `recurrence_count` | não | Quantas vezes repetir |
292
292
  | `template_params` | não | Parâmetros de template WhatsApp |
293
293
 
294
+ ## Flows e cadeias de automação
295
+
296
+ ### Disparo de flow por webhook (Webhook Universal embutido, 2026-06)
297
+
298
+ Além dos triggers de evento (mensagem recebida, conversa criada, etiqueta, card, cron), um flow
299
+ pode ser disparado por **webhook externo próprio**: cria-se a integração embutida via
300
+ `POST /custom_webhook_integrations` com `flow_id`, e o node `start` ganha um item
301
+ `webhook_received` com o `integration_id`. O sistema gera URL única; qualquer evento postado nela
302
+ resolve contato/conversa (mesmas regras do Webhook Universal) e dispara o flow.
303
+ Receita completa no resource **FlowBuilder — Guia de Design** (seção do trigger `webhook`).
304
+
305
+ ### Proteção anti-loop entre motores (2026-06)
306
+
307
+ Automações e flows podem se encadear (automação dispara flow, flow dispara automação...).
308
+ Cada hand-off entre motores incrementa uma profundidade interna; no **5º hand-off** a cadeia é
309
+ cortada silenciosamente (`MAX_CHAIN_DEPTH = 5`). Sintoma: "o flow X não disparou" no fim de uma
310
+ cadeia longa. É proteção contra loop infinito — redesenhe a cadeia pra ficar mais curta em vez
311
+ de contornar. Além disso, a IA que trava no anti-loop **avisa um humano** (notificação) em vez de
312
+ ficar muda (2026-06-05).
313
+
294
314
  ## Eventos importantes (pra automation)
295
315
 
296
316
  | Evento | Quando dispara |
@@ -149,6 +149,13 @@ Company
149
149
  - `additional_attributes` (jsonb): campos do sistema porém **EDITÁVEIS via API** (`permitted_params` permite `additional_attributes: {}`). Guarda chaves padrão como `city`, `company`, `country_code` — que são as chaves filtráveis em `lib/filters/filter_keys.yml` (tipo `additional_attributes`). NÃO é não-editável.
150
150
  - `custom_attributes` (jsonb): dado de negócio livre, definido pelo cliente via Atributos Customizados.
151
151
 
152
+ **Dados cadastrais (`additional_attributes.cadastral`):** CPF, CNPJ, RG, passaporte, nascimento,
153
+ gênero, estado civil, profissão e endereço completo moram em `additional_attributes->cadastral`.
154
+ São **IMUTÁVEIS por padrão** (primeira escrita vale) — alterar exige `force_update: true`, que SÓ
155
+ o painel humano usa. IA e integrações NUNCA passam force_update. Endpoint dedicado:
156
+ `PATCH /contacts/{id}/cadastral` (tool `contacts_update_cadastral`). NÃO grave cadastral como
157
+ custom_attribute. Regra absoluta relacionada: NUNCA sobrescrever `phone_number` já preenchido.
158
+
152
159
  **Padrões de `source_id` por canal:**
153
160
  - Waha: `5511999999999@c.us` (1-on-1) ou `120363xxx@g.us` (grupo) ou `XXXX@lid` (LID)
154
161
  - WhatsApp Cloud: `5511999999999` (E.164 sem prefixo)
@@ -221,11 +228,33 @@ Captain::Assistant
221
228
  ├── name
222
229
  ├── description
223
230
  ├── paused (boolean, default false) — botao de panico (2026-05-22). true = pausa respostas, follow-up e callbacks. Auditado. Top-level, NAO mora em config.
224
- ├── config (jsonb: model, temperature, instructions, feature_memory, feature_faq, ...)
225
- ├── guardrails (string[])
226
- ├── response_guidelines (string[])
231
+ ├── config (jsonb) — chaves principais:
232
+ │ model, temperature, instructions (max 20.000 chars), feature_memory, feature_faq,
233
+ │ feature_follow_up (bool), follow_up_steps (array de {after_minutes, prompt} — ATE 3 etapas,
234
+ │ cada uma >= 5 min, soma <= 1440 min/24h; legado follow_up_time+follow_up_prompt = 1 etapa),
235
+ │ activation_label (etiqueta que ativa o agente — unica por conta),
236
+ │ min_response_time / max_response_time (delay humanizado, 1-60s),
237
+ │ disabled_tools (array de IDs de tools desativadas pro assistente),
238
+ │ offer_ids / media_asset_ids / booking_event_type_ids (arrays de IDs vinculados),
239
+ │ products (array legado de produtos)
240
+ ├── guardrails (jsonb array de strings — limites duros injetados no prompt, ex: anti-pitch)
241
+ ├── response_guidelines (jsonb array de strings — diretrizes de estilo de resposta)
227
242
  └── active_conversations_count
228
243
 
244
+ ⚠️ UPDATE de assistant: `config` faz MERGE PARCIAL (chaves não enviadas são preservadas);
245
+ `guardrails`/`response_guidelines` SUBSTITUEM o array inteiro.
246
+
247
+ Captain::Scenario (cenários do assistente — instruções inline, sem handoff)
248
+ ├── assistant_id (FK)
249
+ ├── title / description
250
+ ├── instruction (text — tools referenciadas como links markdown [Titulo](tool://id))
251
+ ├── tools (jsonb — auto-extraído da instruction)
252
+ ├── enabled (bool)
253
+ └── trigger_type (llm_interpreted [default] | on_assistant_activation | on_first_customer_message)
254
+ ⚠️ trigger_type NAO é editável via API hoje — todo cenário criado por API fica em
255
+ llm_interpreted (a IA decide aplicar lendo a conversa). Os modos programáticos só
256
+ via banco/console por enquanto.
257
+
229
258
  Captain::AssistantResponse (FAQ)
230
259
  ├── assistant_id (FK)
231
260
  ├── question
@@ -360,9 +389,30 @@ MetaLeadIntegration (Facebook Lead Ads)
360
389
  ├── account_id (FK)
361
390
  ├── page_id
362
391
  ├── page_name
392
+ ├── business_id / business_name (BM dona da página — rótulo, desde 2026-06 a conexão é POR PÁGINA)
363
393
  ├── facebook_page_id (FK polimórfico)
364
394
  ├── status (active/token_expired/paused)
365
395
  └── meta_lead_forms (has_many)
396
+
397
+ CustomWebhookIntegration (Webhook Universal — entrada)
398
+ ├── account_id (FK)
399
+ ├── name / token (URL única) / active
400
+ ├── field_mapping (jsonb — suporta caminhos com índice de array: messages.0.content)
401
+ ├── event_automation_mapping (jsonb)
402
+ └── flow_id (FK opcional → Flow; presente = webhook EMBUTIDO de flow, oculto da listagem standalone)
403
+
404
+ LiontrackJourneyStage (regras de fase da Jornada do Lead — feature flag liontrack)
405
+ ├── account_id (FK)
406
+ ├── stage (nome da fase, ex: Topo/Meio/Fundo/Compra)
407
+ ├── url_pattern (match literal de substring, <= 255 chars — SEM regex)
408
+ └── position (int, ordem)
409
+
410
+ WhatsappCall (Ligação WhatsApp — enterprise, voz via Cloud API)
411
+ ├── account_id / conversation_id / contact_id (FKs)
412
+ ├── status (ringing/accepted/completed/failed) / direction
413
+ ├── duration_seconds / accepted_by_agent_id
414
+ ├── custom_name (observação) / favorited (bool)
415
+ └── transcript / transcript_status (pending/processing/completed/failed — IA da conta)
366
416
  ```
367
417
 
368
418
  ## Cardinalidades importantes
@@ -63,11 +63,18 @@ Todo node tem essa estrutura base:
63
63
  **Triggers válidos:** `message_received`, `conversation_created`, `conversation_resolved`, `conversation_reopened`, `label_added`, `label_removed`, `card_created`, `card_moved`, `cron`, `webhook`.
64
64
 
65
65
  **Campos de filtro por trigger (IMPORTANTE — nomes exatos):**
66
- - `message_received`: `keywords` (array) + `match_type` (`'exact'` ou `'contains'`, default `contains`). NÃO use `match_mode` aqui.
66
+ - `message_received`: `keywords` (array, obrigatório, cada termo com mín 3 chars) + `match_type` (`'exact'` ou `'contains'`, default `contains`). NÃO use `match_mode` aqui. Dispara em QUALQUER mensagem do cliente que case (não só na primeira) — só mensagem de cliente dispara, nunca de agente.
67
67
  - `conversation_created` / `conversation_reopened`: filtro opcional de keywords via `match_mode` (`'any'`, `'contains'`, `'exact'`, `'customer_initiated'`, `'agent_initiated'`) + `keywords`. Só ESTES dois triggers usam `match_mode`.
68
68
  - `label_added` / `label_removed`: `label_names` (array de slugs). NÃO use `label` (singular) — é ignorado.
69
69
  - `card_created` / `card_moved`: `funnel_ids` (array) + `funnel_stages` (array de `"funnel_id:stage"`).
70
70
 
71
+ **Trigger `webhook` — Webhook Universal EMBUTIDO (novo 2026-06):** o flow pode ser disparado por um webhook próprio, criado automaticamente. Receita via API:
72
+ 1. Criar o flow normalmente (`flows_create`).
73
+ 2. `POST /custom_webhook_integrations` com `{ "custom_webhook_integration": { "flow_id": <id do flow> } }` — o sistema cria a integração embutida (idempotente: repetir retorna a mesma; nome automático "Flow: <nome>"; auto-mapeia todos os eventos → este flow) e retorna a URL única do webhook.
74
+ 3. No node `start`, adicionar item `{ "type": "webhook_received", "config": { "integration_id": <id da integração> } }`.
75
+ 4. Salvar o flow (`flows_update`) — o save sincroniza a ativação do webhook embutido (remover o item desativa a integração automaticamente).
76
+ 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.
77
+
71
78
  **Handles que SAEM:** `success`.
72
79
 
73
80
  ### 2.2 `send_message`
@@ -142,6 +149,8 @@ Todo node tem essa estrutura base:
142
149
  - `validation: 'options'` → `option_<valor>` para cada valor em `acceptedOptions` (ex: `option_1`, `option_2`, `option_sim`) + `timeout`
143
150
  - `validation: 'regex'` → `success`, `timeout`
144
151
 
152
+ **Timeout AGORA dispara de verdade (corrigido 2026-06-09):** `waitTime` + `waitUnit` agendam o estouro — se o cliente não responder no prazo, o flow segue pelo handle `timeout`. Antes dessa data o backend ignorava o waitTime (flows antigos que dependiam do timeout passaram a funcionar). Sempre ligue um edge no handle `timeout` quando definir waitTime; sem edge, o flow simplesmente para ali no estouro.
153
+
145
154
  **REGRA:** depois de wait_response com options, NUNCA coloque node `condition` pra ramificar — ligue os edges direto nos handles `option_X`.
146
155
 
147
156
  ### 2.4 `condition`
@@ -163,6 +172,8 @@ Todo node tem essa estrutura base:
163
172
 
164
173
  **ATENÇÃO — atributo customizado é SINGULAR:** `contact.custom_attribute.X` e `conversation.custom_attribute.X` (também `account.custom_attribute.X`). Usar plural `custom_attributes` resolve VAZIO — vale tanto no `field` da condição quanto em mensagens/variáveis `{{...}}`.
165
174
 
175
+ **Dados cadastrais — forma curta é a canônica (2026-06):** `{{contact.cpf}}`, `{{contact.cnpj}}`, `{{contact.rg}}`, `{{contact.address.number}}`, `{{contact.address.street}}` etc. O backend traduz internamente pra `contact.cadastral.*` (flows antigos com a forma longa continuam resolvendo). NÃO use `contact.attributes.cpf` nem `contact.custom_attribute.cpf` — cadastral NÃO é custom attribute.
176
+
166
177
  **Operadores válidos (lista real do runtime):**
167
178
 
168
179
  | Operador | Uso |
@@ -224,11 +235,13 @@ Use operador numérico (`greater_than`, `less_than`, `number_range`) SÓ em atri
224
235
  | `assign_team` | `{ team_id }` | Atribui time |
225
236
  | `change_status` | `{ status: 'open' \| 'resolved' \| 'pending' \| 'snoozed' }` | Muda status da conversa |
226
237
  | `change_priority` | `{ priority: 'urgent' \| 'high' \| 'medium' \| 'low' }` | Muda prioridade |
227
- | `add_label` | `{ labels: ['slug1', 'slug2'] }` | Adiciona labels |
228
- | `remove_label` | `{ labels: ['slug'] }` | Remove labels |
238
+ | `add_label` | `{ labels: ['slug1', 'slug2'] }` | Adiciona labels ao CONTATO |
239
+ | `remove_label` | `{ labels: ['slug'] }` | Remove labels do CONTATO |
240
+ | `add_conversation_label` | `{ labels: ['slug'] }` | Adiciona labels à CONVERSA (não ao contato) |
241
+ | `remove_conversation_label` | `{ labels: ['slug'] }` | Remove labels da CONVERSA |
229
242
  | `mute_conversation` | `{}` | Silencia notificações |
230
243
  | `add_private_note` | `{ content: 'texto' }` | Adiciona nota interna |
231
- | `create_kanban_item` | `{ funnel_id, funnel_stage, item_details? }` | Cria card no Kanban |
244
+ | `create_kanban_item` | `{ funnel_id, funnel_stage, title?, description? }` | Cria card no Kanban — `funnel_id` e `funnel_stage` OBRIGATÓRIOS; `title`/`description` aceitam variáveis `{{ }}` |
232
245
  | `move_kanban_item_to_stage` | `{ funnel_stage }` | Move card (precisa ter card vinculado) |
233
246
  | `move_kanban_stage` | `{ funnel_id, funnel_stage }` | Idem |
234
247
  | `set_kanban_item_status` | `{ status: 'won' \| 'lost' \| 'active' }` | Marca status do card |
@@ -307,6 +320,8 @@ Lembre: o atributo lido é SINGULAR (`custom_attribute`).
307
320
 
308
321
  **`aiMode` válidos:** `generate`, `intent`, `sentiment`, `extract`.
309
322
 
323
+ **Contexto da conversa:** campo `contextMessages` define quantas mensagens recentes a IA enxerga — valores válidos `25`, `50`, `75`, `100` (ampliado em 2026-06; antes o teto era ~20). Os modos `intent`/`sentiment`/`extract` rodam no motor contido (texto puro, sem persona nem ferramentas — mais barato e sem risco de vazamento); `generate` usa o assistente Captain.
324
+
310
325
  **Intent — campo EXATO:** `aiIntents` é um ARRAY DE OBJETOS `{ "name": "..." }`. NÃO use `aiIntentOptions` (array de strings) — é ignorado. A intenção classificada também fica disponível na variável de sessão **`ai_intent`** (use como `{{ai_intent}}` adiante).
311
326
 
312
327
  **Handles que SAEM dependem do mode:**
@@ -381,7 +396,7 @@ Atualiza nome/descrição/foto de grupo WhatsApp. Use só quando flow roda em in
381
396
 
382
397
  **Handles que SAEM:** `success`, `error`.
383
398
 
384
- ### 2.12 `activate_flow`
399
+ ### 2.12 `activate_flow` (LEGADO — prefira action `start_flow`)
385
400
 
386
401
  ```json
387
402
  {
@@ -394,6 +409,8 @@ Atualiza nome/descrição/foto de grupo WhatsApp. Use só quando flow roda em in
394
409
 
395
410
  **Handles que SAEM:** `success`, `error`.
396
411
 
412
+ **ATENÇÃO:** este node saiu do menu do editor (legado) — o motor ainda executa flows antigos que o usam, mas em flows NOVOS use `action` com `key: 'start_flow'` e `config: { flow_id }`. Não crie nodes `activate_flow` novos.
413
+
397
414
  ### 2.13 `end` (encerra ramo / define retorno do ai_tool)
398
415
 
399
416
  Node terminal, sem handles de saída. Em flow `conversation` apenas encerra aquele ramo. Em flow `ai_tool` é OBRIGATÓRIO: o `data` do `end` define o que volta pro LLM (modo de saída + template do resultado).
@@ -422,10 +439,22 @@ O campo `flow_type` (definido na criação, IMUTÁVEL depois) decide a natureza
422
439
  | Inboxes | usa `inbox_ids` | **PROIBIDO** ter inboxes (validação barra) |
423
440
  | Campos extra | — | `tool_name` (snake_case, `[a-z][a-z0-9_]`, max 50) + `tool_description` (max 500) OBRIGATÓRIOS |
424
441
  | Retorno | manda mensagens | retorna dado estruturado ao LLM via node `end` |
425
- | Nodes permitidos | todos | SÓ: `start`, `end`, `api`, `condition`, `set_variable`, `ai`, `note` |
442
+ | Nodes permitidos | todos | `start`, `end`, `api`, `condition`, `set_variable`, `ai`, `note`, `randomizer`, `action`, `send_message` |
426
443
 
427
444
  Se o cliente pediu "uma ferramenta que a IA usa pra consultar X / calcular Y", é `ai_tool`. Se pediu "quando chega mensagem, faça Z", é `conversation`. Na dúvida, `conversation`.
428
445
 
446
+ **No flow `ai_tool`, o node `action` NÃO aceita as keys da aba "Sistema"** (`send_webhook` /
447
+ `start_flow`) — elas só valem em flow `conversation`. No `action` de um `ai_tool` use apenas keys
448
+ das abas Conversas / Contatos / Kanban (ex: `add_label`, `change_status`, `update_attribute`,
449
+ `create_kanban_item`). Para gravar atributo no `ai_tool`, use `action` com `update_attribute`
450
+ (o antigo node `save_attribute` foi removido — não existe mais em nenhum tipo de flow).
451
+
452
+ **Proteção anti-loop por profundidade (2026-06):** quando um flow dispara automação que dispara
453
+ outro flow (cadeia entre motores), cada hand-off incrementa um contador interno (`_activation_depth`).
454
+ No 5º hand-off (`MAX_CHAIN_DEPTH = 5`) a cadeia é cortada silenciosamente. Se um flow "não disparou"
455
+ no fim de uma cadeia automação→flow→automação, suspeite desse limite — é proteção, não bug.
456
+ Não tente contornar criando flows intermediários.
457
+
429
458
  ---
430
459
 
431
460
  ## 3. Edges
@@ -351,6 +351,88 @@
351
351
 
352
352
  ---
353
353
 
354
+ ## 11. Flow disparado por webhook externo (Webhook Universal embutido)
355
+
356
+ **Caso:** sistema externo (checkout, formulário, ERP) chama uma URL e o flow roda na conversa do contato — etiqueta + mensagem.
357
+
358
+ **Passo a passo via API (a ordem importa):**
359
+ 1. `flows_create` com o flow_data abaixo (sem o item webhook ainda)
360
+ 2. `POST /custom_webhook_integrations` com `{ "custom_webhook_integration": { "flow_id": <id> } }` → guarde `id` (integration_id) e a URL retornada
361
+ 3. `flows_update` adicionando o item `webhook_received` no start com o `integration_id`
362
+
363
+ ```json
364
+ {
365
+ "nodes": [
366
+ { "id": "n1", "type": "start", "position": { "x": 50, "y": 300 }, "data": { "label": "Início", "items": [
367
+ { "type": "webhook_received", "config": { "integration_id": 123 } }
368
+ ] } },
369
+ { "id": "n2", "type": "action", "position": { "x": 370, "y": 300 }, "data": { "label": "Marca origem", "items": [
370
+ { "key": "add_conversation_label", "config": { "labels": ["compra-confirmada"] } }
371
+ ] } },
372
+ { "id": "n3", "type": "send_message", "position": { "x": 690, "y": 300 }, "data": { "label": "Confirma", "messageItems": [
373
+ { "id": "m1", "type": "text", "content": "{{contact.name}}, recebemos a confirmação do seu pedido! 🎉" }
374
+ ] } }
375
+ ],
376
+ "edges": [
377
+ { "id": "e1", "source": "n1", "target": "n2", "sourceHandle": "success", "type": "deletable", "animated": true },
378
+ { "id": "e2", "source": "n2", "target": "n3", "sourceHandle": "success", "type": "deletable", "animated": true }
379
+ ]
380
+ }
381
+ ```
382
+
383
+ ---
384
+
385
+ ## 12. Ferramenta da IA (ai_tool) mínima — consulta API + retorno estruturado
386
+
387
+ **Caso:** a IA precisa consultar um sistema externo durante a conversa (ex: status do pedido). Criar via `flow_tools_create` (NÃO `flows_create`), depois vincular ao assistente com `POST /flow_tools/{id}/assistants`.
388
+
389
+ ```json
390
+ {
391
+ "tool_name": "consultar_pedido",
392
+ "tool_description": "Consulta o status do pedido do cliente pelo número. Use quando o cliente perguntar do pedido dele.",
393
+ "flow_data": {
394
+ "nodes": [
395
+ { "id": "n1", "type": "start", "position": { "x": 50, "y": 300 }, "data": { "label": "Início" } },
396
+ { "id": "n2", "type": "api", "position": { "x": 370, "y": 300 }, "data": { "label": "Consulta ERP", "method": "GET", "url": "https://erp.exemplo.com/pedidos/{{numero_pedido}}", "headers": [{ "key": "Authorization", "value": "Bearer {{env.ERP_TOKEN}}" }], "apiResponseVar": "pedido" } },
397
+ { "id": "n3", "type": "end", "position": { "x": 690, "y": 300 }, "data": { "label": "Retorno", "mode": "structured" } },
398
+ { "id": "n4", "type": "end", "position": { "x": 690, "y": 480 }, "data": { "label": "Erro", "mode": "structured" } }
399
+ ],
400
+ "edges": [
401
+ { "id": "e1", "source": "n1", "target": "n2", "sourceHandle": "success", "type": "deletable", "animated": true },
402
+ { "id": "e2", "source": "n2", "target": "n3", "sourceHandle": "success", "type": "deletable", "animated": true },
403
+ { "id": "e3", "source": "n2", "target": "n4", "sourceHandle": "error", "type": "deletable", "animated": true }
404
+ ]
405
+ }
406
+ }
407
+ ```
408
+
409
+ **Lembretes ai_tool:** nó `end` é OBRIGATÓRIO; sem `inbox_ids`; nodes permitidos = `start`, `end`, `api`, `condition`, `set_variable`, `ai`, `randomizer`, `action`, `send_message`, `note` (sem `wait`/`wait_response`/`update_group`); `action` sem keys da aba Sistema (`send_webhook`/`start_flow`). Teste com `POST /flow_tools/{id}/run` antes de vincular ao assistente.
410
+
411
+ ---
412
+
413
+ ## 13. Etiqueta na CONVERSA vs no CONTATO
414
+
415
+ **Caso:** marcar a conversa atual sem "sujar" o cadastro do contato (ex: assunto desta conversa), ou o inverso (perfil permanente do contato).
416
+
417
+ ```json
418
+ {
419
+ "nodes": [
420
+ { "id": "n1", "type": "start", "position": { "x": 50, "y": 300 }, "data": { "label": "Início", "triggers": [{ "type": "message_received", "keywords": ["orçamento"], "match_type": "contains" }] } },
421
+ { "id": "n2", "type": "action", "position": { "x": 370, "y": 300 }, "data": { "label": "Marca", "items": [
422
+ { "key": "add_conversation_label", "config": { "labels": ["pediu-orcamento"] } },
423
+ { "key": "add_label", "config": { "labels": ["interessado-em-comprar"] } }
424
+ ] } }
425
+ ],
426
+ "edges": [
427
+ { "id": "e1", "source": "n1", "target": "n2", "sourceHandle": "success", "type": "deletable", "animated": true }
428
+ ]
429
+ }
430
+ ```
431
+
432
+ **Regra de bolso:** fato sobre ESTA conversa → `add_conversation_label` / `remove_conversation_label`. Característica permanente do CONTATO → `add_label` / `remove_label`.
433
+
434
+ ---
435
+
354
436
  ## Como usar este catálogo
355
437
 
356
438
  1. **Identifique o pattern mais próximo** do que o cliente pediu