@lionchat/mcp-server 0.4.10 → 0.5.1

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.
@@ -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,40 @@ 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)
416
+
417
+ WavoipSetting (Ligação WP em caixa QR Code — 1 por inbox, 2026-06-11)
418
+ ├── inbox_id (FK) / device_id / device_token (cripto) / status / due_date
419
+ ├── record_all_calls (bool) / auto_transcribe (bool) / transcription_provider (groq|openai)
420
+ └── feature flag wavoip_calling; limite de plano wavoip_voice_inboxes; R$70/device/mês
421
+
422
+ ContactDocument (aba Documentos do contato, 2026-06-11)
423
+ ├── 3 fontes agregadas: upload direto + espelho dos cards Kanban + espelho das conversas (só image/file)
424
+ ├── dedup por checksum (arquivo repetido conta 1x no storage)
425
+ └── ações: preview, download, renomear, favoritar, excluir (conversas são só-leitura)
366
426
  ```
367
427
 
368
428
  ## Cardinalidades importantes
@@ -60,14 +60,23 @@ Todo node tem essa estrutura base:
60
60
  }
61
61
  ```
62
62
 
63
- **Triggers válidos:** `message_received`, `conversation_created`, `conversation_resolved`, `conversation_reopened`, `label_added`, `label_removed`, `card_created`, `card_moved`, `cron`, `webhook`.
63
+ **Triggers válidos:** `message_received`, `message_sent`, `conversation_created`, `conversation_resolved`, `conversation_reopened`, `label_added`, `label_removed`, `card_created`, `card_moved`, `cron`, `webhook`.
64
+
65
+ **Trigger `message_sent` (novo 2026-06-11):** par do message_received, mas pra mensagens de SAÍDA — dispara quando atendente, celular (eco do WhatsApp) ou a própria IA/flow envia mensagem (nota privada NÃO dispara). Config: `keywords` (opcional) + `match_type` (`contains`|`exact`). Caso de uso clássico: "quando eu responder do celular, desligar a IA". ATENÇÃO: mensagem da IA também dispara — se a ação for desativar a IA, use keywords que só humanos digitam ou aceite que a primeira resposta da IA aciona o flow. Protegido por anti-loop (profundidade 5) e sessão única por conversa+flow; nunca alimenta `waiting_input`.
64
66
 
65
67
  **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.
68
+ - `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
69
  - `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
70
  - `label_added` / `label_removed`: `label_names` (array de slugs). NÃO use `label` (singular) — é ignorado.
69
71
  - `card_created` / `card_moved`: `funnel_ids` (array) + `funnel_stages` (array de `"funnel_id:stage"`).
70
72
 
73
+ **Trigger `webhook` — Webhook Universal EMBUTIDO (novo 2026-06):** o flow pode ser disparado por um webhook próprio, criado automaticamente. Receita via API:
74
+ 1. Criar o flow normalmente (`flows_create`).
75
+ 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.
76
+ 3. No node `start`, adicionar item `{ "type": "webhook_received", "config": { "integration_id": <id da integração> } }`.
77
+ 4. Salvar o flow (`flows_update`) — o save sincroniza a ativação do webhook embutido (remover o item desativa a integração automaticamente).
78
+ 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.
79
+
71
80
  **Handles que SAEM:** `success`.
72
81
 
73
82
  ### 2.2 `send_message`
@@ -142,6 +151,8 @@ Todo node tem essa estrutura base:
142
151
  - `validation: 'options'` → `option_<valor>` para cada valor em `acceptedOptions` (ex: `option_1`, `option_2`, `option_sim`) + `timeout`
143
152
  - `validation: 'regex'` → `success`, `timeout`
144
153
 
154
+ **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.
155
+
145
156
  **REGRA:** depois de wait_response com options, NUNCA coloque node `condition` pra ramificar — ligue os edges direto nos handles `option_X`.
146
157
 
147
158
  ### 2.4 `condition`
@@ -163,6 +174,8 @@ Todo node tem essa estrutura base:
163
174
 
164
175
  **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
176
 
177
+ **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.
178
+
166
179
  **Operadores válidos (lista real do runtime):**
167
180
 
168
181
  | Operador | Uso |
@@ -224,11 +237,13 @@ Use operador numérico (`greater_than`, `less_than`, `number_range`) SÓ em atri
224
237
  | `assign_team` | `{ team_id }` | Atribui time |
225
238
  | `change_status` | `{ status: 'open' \| 'resolved' \| 'pending' \| 'snoozed' }` | Muda status da conversa |
226
239
  | `change_priority` | `{ priority: 'urgent' \| 'high' \| 'medium' \| 'low' }` | Muda prioridade |
227
- | `add_label` | `{ labels: ['slug1', 'slug2'] }` | Adiciona labels |
228
- | `remove_label` | `{ labels: ['slug'] }` | Remove labels |
240
+ | `add_label` | `{ labels: ['slug1', 'slug2'] }` | Adiciona labels ao CONTATO |
241
+ | `remove_label` | `{ labels: ['slug'] }` | Remove labels do CONTATO |
242
+ | `add_conversation_label` | `{ labels: ['slug'] }` | Adiciona labels à CONVERSA (não ao contato) |
243
+ | `remove_conversation_label` | `{ labels: ['slug'] }` | Remove labels da CONVERSA |
229
244
  | `mute_conversation` | `{}` | Silencia notificações |
230
245
  | `add_private_note` | `{ content: 'texto' }` | Adiciona nota interna |
231
- | `create_kanban_item` | `{ funnel_id, funnel_stage, item_details? }` | Cria card no Kanban |
246
+ | `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
247
  | `move_kanban_item_to_stage` | `{ funnel_stage }` | Move card (precisa ter card vinculado) |
233
248
  | `move_kanban_stage` | `{ funnel_id, funnel_stage }` | Idem |
234
249
  | `set_kanban_item_status` | `{ status: 'won' \| 'lost' \| 'active' }` | Marca status do card |
@@ -307,6 +322,8 @@ Lembre: o atributo lido é SINGULAR (`custom_attribute`).
307
322
 
308
323
  **`aiMode` válidos:** `generate`, `intent`, `sentiment`, `extract`.
309
324
 
325
+ **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.
326
+
310
327
  **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
328
 
312
329
  **Handles que SAEM dependem do mode:**
@@ -381,7 +398,7 @@ Atualiza nome/descrição/foto de grupo WhatsApp. Use só quando flow roda em in
381
398
 
382
399
  **Handles que SAEM:** `success`, `error`.
383
400
 
384
- ### 2.12 `activate_flow`
401
+ ### 2.12 `activate_flow` (LEGADO — prefira action `start_flow`)
385
402
 
386
403
  ```json
387
404
  {
@@ -394,6 +411,8 @@ Atualiza nome/descrição/foto de grupo WhatsApp. Use só quando flow roda em in
394
411
 
395
412
  **Handles que SAEM:** `success`, `error`.
396
413
 
414
+ **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.
415
+
397
416
  ### 2.13 `end` (encerra ramo / define retorno do ai_tool)
398
417
 
399
418
  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 +441,22 @@ O campo `flow_type` (definido na criação, IMUTÁVEL depois) decide a natureza
422
441
  | Inboxes | usa `inbox_ids` | **PROIBIDO** ter inboxes (validação barra) |
423
442
  | Campos extra | — | `tool_name` (snake_case, `[a-z][a-z0-9_]`, max 50) + `tool_description` (max 500) OBRIGATÓRIOS |
424
443
  | Retorno | manda mensagens | retorna dado estruturado ao LLM via node `end` |
425
- | Nodes permitidos | todos | SÓ: `start`, `end`, `api`, `condition`, `set_variable`, `ai`, `note` |
444
+ | Nodes permitidos | todos | `start`, `end`, `api`, `condition`, `set_variable`, `ai`, `note`, `randomizer`, `action`, `send_message` |
426
445
 
427
446
  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
447
 
448
+ **No flow `ai_tool`, o node `action` NÃO aceita as keys da aba "Sistema"** (`send_webhook` /
449
+ `start_flow`) — elas só valem em flow `conversation`. No `action` de um `ai_tool` use apenas keys
450
+ das abas Conversas / Contatos / Kanban (ex: `add_label`, `change_status`, `update_attribute`,
451
+ `create_kanban_item`). Para gravar atributo no `ai_tool`, use `action` com `update_attribute`
452
+ (o antigo node `save_attribute` foi removido — não existe mais em nenhum tipo de flow).
453
+
454
+ **Proteção anti-loop por profundidade (2026-06):** quando um flow dispara automação que dispara
455
+ outro flow (cadeia entre motores), cada hand-off incrementa um contador interno (`_activation_depth`).
456
+ No 5º hand-off (`MAX_CHAIN_DEPTH = 5`) a cadeia é cortada silenciosamente. Se um flow "não disparou"
457
+ no fim de uma cadeia automação→flow→automação, suspeite desse limite — é proteção, não bug.
458
+ Não tente contornar criando flows intermediários.
459
+
429
460
  ---
430
461
 
431
462
  ## 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
@@ -174,11 +174,21 @@ Glossário completo de termos, status codes, enums e conceitos da plataforma. Us
174
174
 
175
175
  - `id`: ID interno
176
176
  - `name`: nome do agente (ex: "Luna", "Diogo")
177
+ - `paused`: botão de pânico — `true` corta respostas/follow-ups/callbacks na hora (top-level, auditado)
178
+ - `guardrails`: array de limites duros injetados no prompt (ex: anti-pitch)
179
+ - `response_guidelines`: array de diretrizes de estilo de resposta
177
180
  - `config.feature_memory`: gera notas no contato ao resolver conversas
178
181
  - `config.feature_faq`: gera FAQs sugeridas ao resolver conversas
182
+ - `config.feature_follow_up` + `config.follow_up_steps`: follow-up automático em cadência de até
183
+ 3 etapas (cada ≥5 min, soma ≤24h) quando o cliente some — motor dedicado só-leitura
179
184
  - `config.model`: modelo OpenAI usado (gpt-4o, gpt-4o-mini)
180
185
  - `config.temperature`: 0.0-1.0
181
- - `config.instructions`: prompt sistema (Liquid template)
186
+ - `config.instructions`: prompt sistema (Liquid template, até 20.000 chars)
187
+ - `config.activation_label`: etiqueta que ativa o agente na conversa (única por conta)
188
+ - **Cenário (Captain::Scenario)**: instrução situacional inline do assistente; o raciocínio de
189
+ aplicação fica no "caderninho do cenário" da conversa (scenario_checklist, card Raciocínio)
190
+ - **Regra DITO ≠ SALVO**: a IA só considera coletado o dado que foi PERSISTIDO — salva cada dado
191
+ na hora e não repergunta o que já salvou
182
192
 
183
193
  ## Account (Conta)
184
194
 
@@ -309,3 +319,39 @@ Glossário completo de termos, status codes, enums e conceitos da plataforma. Us
309
319
  Campos MUTÁVEIS (atualizáveis livremente por IA/integração): `marital_status`, `profession` e todos os campos de `address`.
310
320
 
311
321
  `custom_attribute_definitions` (model=`contact_attribute`) fica reservado a dado de NEGÓCIO genérico que não tem modelo dedicado (ex: "plano contratado", "nicho do cliente").
322
+
323
+ ## Ligações — TRÊS sistemas distintos (não confundir!)
324
+
325
+ | Sistema | O que é | Tools | Canal |
326
+ |---|---|---|---|
327
+ | **Ligação WP (Wavoip)** | Voz pelo WhatsApp em caixa **QR Code/WAHA** — QR conecta um "device" Wavoip; widget de discagem, gravação e transcrição automática | `wavoip_*` (por inbox: status/token/calls/connect/disconnect/settings) | WhatsApp QR Code |
328
+ | **WhatsApp Calling (Cloud)** | Voz pelo WhatsApp na **API oficial** (enterprise) | `whatsapp_calls_*` + enable/disable_whatsapp_calling | WhatsApp oficial |
329
+ | **VoIP (Zenvia)** | Telefonia COMUM (ramais, saldo, recarga) | `voip_*` | Telefone |
330
+
331
+ Quando o usuário falar "ligação", descubra o canal: caixa QR Code → Wavoip; caixa oficial →
332
+ whatsapp_calls; telefone fixo/ramal → VoIP Zenvia.
333
+
334
+ **Wavoip (2026-06-11):** config por inbox (`record_all_calls`, `auto_transcribe`,
335
+ `transcription_provider` groq|openai), feature flag `wavoip_calling`, limite por plano
336
+ `wavoip_voice_inboxes`, R$70/device/mês. Conectar/configurar = admin; discar/histórico = membro
337
+ da caixa. WhatsappCall (Cloud): `status`, `custom_name`, `favorited`, `transcript`/`transcript_status`.
338
+
339
+ ## Chat interno da equipe (InternalChat)
340
+
341
+ Mensagens ENTRE agentes da conta (não envolve cliente). Salas `direct` (1:1) ou `multi_user`
342
+ (grupo), com reações, fixadas, anexos e não-lidas. Tools `internal_chat_*`. Não confundir com
343
+ nota privada (que mora DENTRO de uma conversa com cliente).
344
+
345
+ ## LionTrack / Jornada do Lead
346
+
347
+ Rastreamento de navegação do site (tracking_events, pageviews) + painel "Jornada do Lead" em
348
+ Relatórios: mapa visual de por onde os leads andam (nós = páginas, setas = transições), agrupado
349
+ por FASES configuráveis (LiontrackJourneyStage: padrão de URL → fase, match literal).
350
+ Feature flag `liontrack` (404 sem ela). Relatório: `journey_funnel_reports` (v2), janela máx 30
351
+ dias, URLs sem querystring (LGPD).
352
+
353
+ ## Idiomas da plataforma (2026-06)
354
+
355
+ A plataforma opera com 6 idiomas: `en`, `es`, `fr`, `it`, `pt`, `pt_BR` (default das contas
356
+ brasileiras: pt_BR). Conta com idioma antigo/descontinuado cai em inglês. Notas internas geradas
357
+ pela IA saem no idioma da conta.
@@ -253,6 +253,25 @@ Funil "Vendas"
253
253
 
254
254
  Endpoint: `GET /api/v2/kanban/items/counts` retorna contagem + soma por etapa.
255
255
 
256
+ ## Controle de acesso por funil (2026-06-10)
257
+
258
+ Funis agora têm visibilidade por usuário. Um funil é visível pra alguém quando:
259
+ - é admin da conta, OU
260
+ - tem permissão `kanban_view`/`kanban_manage` (custom role), OU
261
+ - o funil está aberto a todos, OU
262
+ - a pessoa participa do funil (está em `settings.agents` ou tem card atribuído)
263
+
264
+ **Efeitos práticos nas tools:**
265
+ - `funnels_list` retorna SÓ os funis visíveis pro usuário do token
266
+ - `funnels_show` / `stage_stats` de funil não-visível → **404** (não "lista vazia")
267
+ - A resposta dos cards traz selos de permissão calculados no backend:
268
+ `can_edit`, `can_move`, `can_delete`, `can_assign` (booleans)
269
+ - `kanban_items_move` sem permissão → **403** com mensagem traduzida (antes dava 500/sucesso falso)
270
+ - Cards embutidos na tela da conversa também respeitam a visibilidade
271
+
272
+ **Pro MCP:** antes de tentar mover/editar card, confira os campos `can_*` do show — se `can_move`
273
+ é false, explique ao usuário que ele não tem acesso àquele funil em vez de tentar mesmo assim.
274
+
256
275
  ## Funil arquivado vs ativo
257
276
 
258
277
  - `archived = true`: funil escondido da UI principal. Cards ainda existem mas não aparecem nas listas
@@ -280,6 +280,26 @@ atual. Se since-until = 7d, previous = 7d antes. Pra esses dois, passe `since/un
280
280
  inteiro e use o `previous` retornado em vez de comparar na mão.
281
281
  Nos demais (agente/time/inbox/label/canal e timeseries) NÃO há `previous` — chame duas vezes.
282
282
 
283
+ ## Jornada do Lead (LionTrack) — relatório novo (2026-06)
284
+
285
+ `GET /api/v2/accounts/{id}/journey_funnel_reports` — mapa agregado de navegação dos
286
+ leads no site ANTES de virarem conversa (nós = páginas, arestas = transições página A → página B,
287
+ agrupado por fases configuradas em `liontrack/journey_stages`).
288
+
289
+ **Filtros (query):** `since`/`until` (janela MÁX 30 dias — acima disso o servidor corta sozinho),
290
+ `utm_source`, `utm_campaign`, `device_name`, `country`, `contact_id` (trilha de 1 lead),
291
+ `with_conversation=true` (só quem virou conversa).
292
+
293
+ **Retorno:** `nodes` (página, fase, visitas, visitantes únicos), `edges` (transições com contagem),
294
+ totais. URLs vêm SEM querystring (proteção LGPD — e-mail/CPF em URL nunca aparecem).
295
+
296
+ **Gates:** feature flag `liontrack` (404 se desligada) + permissão de relatórios (admin ou
297
+ report_manage). As fases são geridas pelas tools `liontrack_journey_stages_*` (padrão de URL →
298
+ fase, match literal de substring, sem regex).
299
+
300
+ **Perguntas que esse relatório responde:** "por onde os leads entram?", "qual página perde mais
301
+ gente?", "quem veio da campanha X navegou por onde antes de chamar?".
302
+
283
303
  ## Quando o usuário pede algo MUITO específico que não existe num endpoint
284
304
 
285
305
  Se a pergunta requer cálculos custom (ex: "conversas por agente que duraram mais de X minutos"):