@lionchat/mcp-server 1.23.0 → 1.24.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 +21 -2
- package/dist/docs/resources/agenda-multiplas-unidades.md +44 -1
- package/dist/docs/resources/api-conventions.md +56 -2
- package/dist/docs/resources/best-practices.md +52 -2
- package/dist/docs/resources/data-model.md +11 -6
- package/dist/docs/resources/filtros-e-relatorios.md +15 -0
- package/dist/docs/resources/flowbuilder-design-guide.md +4 -1
- package/dist/docs/resources/glossary.md +4 -2
- package/dist/docs/resources/kanban-deep-dive.md +133 -24
- package/dist/tools.js +3 -2
- package/dist/tools.js.map +1 -1
- package/endpoints.json +708 -92
- package/package.json +1 -1
|
@@ -170,10 +170,29 @@ Detalhes completos em `lionchat://docs/api-conventions` → "Wrapper de body".
|
|
|
170
170
|
### Regras de formato silenciosas
|
|
171
171
|
|
|
172
172
|
- **Label.title**: kebab-case ou snake_case, **SEM espaço**. `"Lead Emive"` ❌ → `"lead-emive"` ✅
|
|
173
|
-
- **win_reasons / loss_reasons**: array de `{id, title}`, NÃO strings
|
|
173
|
+
- **win_reasons / loss_reasons**: array de `{id, title}`, NÃO strings. O `id` é **TEXTO estável** (`"perda-preco"`),
|
|
174
|
+
nunca número. A lista SUBSTITUI a atual: leia antes e reenvie os MESMOS `id` (trocar o `id` tira o nome dos
|
|
175
|
+
cards já marcados). Motivo sem `id`/`title`, `id` repetido ou lista de textos → recusado com 422
|
|
176
|
+
- **motivo no card**: `item_details.status` `"lost"`/`"won"` + `loss_reason`/`win_reason` = o `id` (texto) de um
|
|
177
|
+
motivo cadastrado + `reason` = o título. Motivo livre: `loss_reason` nulo e o texto em `reason`
|
|
174
178
|
- **linked_conversations**: array de `{display_id: N}`, NÃO inteiros direto
|
|
175
179
|
- **phone**: E.164 (`+5511...`), sem espaços/parênteses
|
|
176
|
-
- **funnel.stages** keys: snake_case slug
|
|
180
|
+
- **funnel.stages** keys: snake_case slug; cada etapa é OBJETO com `name` texto
|
|
181
|
+
- **Lista de objetos é lista de objetos**: onde o formato pede `[{id: 5}]`, número solto (`[5]`) ou objeto
|
|
182
|
+
único no lugar da lista quebra a leitura — às vezes a tela da conta inteira (incidente 18/09, funil).
|
|
183
|
+
|
|
184
|
+
### Gravação: TROCA inteira × SOMA (conferido no código em 18/09/2026)
|
|
185
|
+
|
|
186
|
+
Muitos campos objeto/lista são **trocados inteiros** no update: o que não vier no envio é APAGADO. Nesses,
|
|
187
|
+
**leia antes** (show) e **reenvie tudo** com o item alterado. A descrição de cada ferramenta diz qual é qual.
|
|
188
|
+
|
|
189
|
+
| TROCA inteira (leia e reenvie tudo) | SOMA (só as chaves enviadas mudam) |
|
|
190
|
+
|---|---|
|
|
191
|
+
| `custom_attributes` da CONVERSA (`conversations_create_3` — só `captain_*` sobrevive; apaga utm/gclid/ctwa/origin) | `custom_attributes` do CONTATO (`contacts_update`) |
|
|
192
|
+
| card: cada chave de `item_details` (a lista `custom_attributes` do card, `offers`, `notes`), `assigned_agents`, coluna `custom_attributes` | `item_details` do card no 1º nível (chave não enviada fica) |
|
|
193
|
+
| `funnel.settings`, `funnel.stages` (etapa ausente = removida), `kanban_config.global_custom_attributes` | `channel.additional_attributes` da caixa WhatsApp/Instagram/Facebook/TikTok |
|
|
194
|
+
| `flow_data` do fluxo, `actions` de macro/automação, `query` de filtro salvo, `audience` de campanha | `roles_layout` do modelo de contrato |
|
|
195
|
+
| `settings` de integração (hooks), mapas de evento de gateway/Omie/Conta Azul/Meta Lead/Google Ads | |
|
|
177
196
|
|
|
178
197
|
### Native first
|
|
179
198
|
|
|
@@ -141,12 +141,55 @@ Google dela — inclusive a **mesma pessoa** com contas Google diferentes, uma p
|
|
|
141
141
|
|
|
142
142
|
- Agenda **sem** pessoas e **sem** equipes: todo mundo da conta enxerga.
|
|
143
143
|
- Marcando pessoas e/ou equipes: só elas. Quem entrar na equipe ganha acesso sozinho.
|
|
144
|
-
- **Administrador enxerga todas**, sempre.
|
|
144
|
+
- **Administrador enxerga todas**, sempre. Desde 21/09, **quem tem a caixinha `agenda_manage`** ("Gerenciar
|
|
145
|
+
agenda da equipe") também enxerga todas — é a função da secretária.
|
|
145
146
|
- `member_user_ids` e `member_team_ids` **substituem a lista inteira** (idioma do `InboxMember`).
|
|
146
147
|
|
|
148
|
+
### `agenda_manage`: a caixinha da secretária (21/09)
|
|
149
|
+
|
|
150
|
+
Permissão de função personalizada (`custom_roles.permissions`). Quem a tem, **sem ser administrador**:
|
|
151
|
+
- vê a agenda e os compromissos de TODA a conta (`tasks_list` deixa de recortar por pessoa);
|
|
152
|
+
- cria, edita, remarca, cancela e exclui compromisso de qualquer pessoa;
|
|
153
|
+
- marca pelo `booking_event_type` de qualquer pessoa (`tasks_create` com `booking_event_type_id` de outro);
|
|
154
|
+
- cria/edita/apaga `booking_event_types` de outra pessoa (inclusive mandando `user_id` de outro no create);
|
|
155
|
+
- lê e ajusta a disponibilidade de outra pessoa (`agent_availability_*`) e abre o painel de Agentes.
|
|
156
|
+
|
|
157
|
+
**NÃO** permite criar/editar/apagar AGENDA (unidade): `agendas_create/update/destroy` seguem só administrador —
|
|
158
|
+
agenda é recurso do plano, com limite. Sem a caixinha, o atendente vê só a própria agenda e a de quem ligou
|
|
159
|
+
`agenda_public` no perfil, e não mexe na dos outros.
|
|
160
|
+
|
|
147
161
|
A listagem de compromissos já vem recortada pelas agendas que o usuário enxerga, **mesmo sem mandar
|
|
148
162
|
`agenda_id`**. Ler ou editar compromisso de uma agenda que a pessoa não enxerga devolve 404.
|
|
149
163
|
|
|
164
|
+
**Quem não enxerga NENHUMA agenda não vê compromisso nenhum** (21/09). Antes, "lista de agendas
|
|
165
|
+
visíveis vazia" abria em vez de fechar: o recorte tratava igual dois estados opostos — *a conta não
|
|
166
|
+
tem agenda nenhuma* (aí não há o que recortar, devolve tudo) e *a conta tem agendas e esta pessoa não
|
|
167
|
+
foi posta em nenhuma* (aí ela não pode ver nada). Medido: atendente fora das duas agendas da conta
|
|
168
|
+
enxergava todos os compromissos.
|
|
169
|
+
|
|
170
|
+
## 6.1. Toda conta tem a agenda "Principal" (21/09)
|
|
171
|
+
|
|
172
|
+
Antes, a agenda de uma conta era **implícita**: não havia linha no banco e todo compromisso nascia com
|
|
173
|
+
`agenda_id` NULO. A aba Agendas abria dizendo "Nenhuma agenda ainda" numa conta que **tinha** agenda —
|
|
174
|
+
e não havia onde escolher quem a enxerga.
|
|
175
|
+
|
|
176
|
+
Hoje `Agenda.garantir_padrao!` (chamada no `index`) materializa essa agenda como **Principal**, marcada
|
|
177
|
+
`is_default`, com o fuso da conta. Vale para **toda conta, com ou sem o recurso de múltiplas agendas**:
|
|
178
|
+
quem tem uma agenda só pode editá-la e escolher equipes/pessoas — só não pode **criar outra**, o que
|
|
179
|
+
continua barrado por `Agendas::Quota` (motivo `feature_off`, que é avaliado ANTES do número).
|
|
180
|
+
|
|
181
|
+
**NEVER CHANGE / GOTCHAS**
|
|
182
|
+
- A condição é "não existe agenda **PADRÃO**", nunca "não existe agenda": enquanto o defeito do
|
|
183
|
+
`is_default` esteve no ar, quem criou agenda ficou **sem padrão** e com os compromissos antigos
|
|
184
|
+
invisíveis. Perguntar só por "existe agenda?" deixaria essas contas quebradas para sempre.
|
|
185
|
+
- **Não promover** uma agenda existente a padrão: ela é um LUGAR que o cliente nomeou (uma filial), e
|
|
186
|
+
herdar os compromissos da agenda de antes jogaria o histórico inteiro dentro da filial errada.
|
|
187
|
+
- A Principal nasce **sem membros** — lista vazia é visível a todos, então ninguém perde acesso no
|
|
188
|
+
deploy.
|
|
189
|
+
- Criar agenda: a pergunta "é a primeira?" tem que ir ao **banco** (`exists?`) e **antes** do `.new`.
|
|
190
|
+
`conta.agendas.new(...)` ACRESCENTA o registro não salvo à coleção em memória, então o `.empty?`
|
|
191
|
+
que existia ali respondia sempre `false` e `is_default` **nunca** era marcado.
|
|
192
|
+
|
|
150
193
|
---
|
|
151
194
|
|
|
152
195
|
## 7. Programa de sessões (15/09)
|
|
@@ -73,7 +73,61 @@ Praticamente nunca — exceto se você está testando legacy/curl e quer ser exp
|
|
|
73
73
|
}
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
Regras (conferidas no servidor desde 21/09):
|
|
77
|
+
|
|
78
|
+
- O `id` é **texto estável** (`"wr-1"`, `"perda-preco"`) — **nunca número**. Número é convertido para texto
|
|
79
|
+
(`7` vira `"7"`), mas o certo é já mandar texto. Motivo cadastrado com `id` numérico derrubava o relatório do
|
|
80
|
+
funil (conta 137, 21/09).
|
|
81
|
+
- Como a lista **substitui** a atual, **reenvie os mesmos `id`** dos motivos que já existem. Trocar o `id` de um
|
|
82
|
+
motivo faz os cards já marcados com ele perderem o nome no relatório.
|
|
83
|
+
- Recusado com **422** (mensagem diz o formato): lista de textos soltos (`["motivo"]` — antes APAGAVA os motivos da
|
|
84
|
+
conta em silêncio), motivo sem `id`, motivo sem `title`, `id` repetido. O servidor **não inventa** `id`.
|
|
85
|
+
- Lista vazia (`[]`) limpa os motivos.
|
|
86
|
+
|
|
87
|
+
**Marcar o card com o motivo** (`PATCH /kanban_items/{id}`, `item_details` mescla no 1º nível):
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{ "item_details": { "status": "lost", "loss_reason": "perda-preco", "reason": "Preço alto" } }
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`loss_reason`/`win_reason` = o `id` (texto) de um motivo cadastrado; `reason` = o título. Motivo livre (fora da
|
|
94
|
+
lista): `loss_reason` nulo e o texto em `reason`.
|
|
95
|
+
|
|
96
|
+
### Outras listas de OBJETOS — formato conferido no servidor (desde 21/09)
|
|
97
|
+
|
|
98
|
+
Estes campos são **listas de objetos**. Mandar lista de textos/números soltos, lista misturada (alguns objetos e
|
|
99
|
+
alguns textos) ou um objeto solto no lugar da lista é recusado com **422**, e a mensagem mostra o formato certo.
|
|
100
|
+
Antes o servidor aceitava, gravava **lista vazia** e respondia 200 — ou seja, apagava a configuração do cliente.
|
|
101
|
+
|
|
102
|
+
| Ferramenta | Campo | Formato |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| `custom_dashboards_create/update` | `widgets` | `[{"widget_type": "conversations_timeseries", "metric": "conversations", ...}]`; dentro de cada bloco, `columns` também é lista de objetos |
|
|
105
|
+
| `kanban_config_update` | `global_custom_attributes` | `[{"name": "Origem", "type": "text"}]` (`list_values` é lista de textos) |
|
|
106
|
+
| `kanban_config_update` | `checklist_templates` | `[{"name": "Onboarding", "items": [{"text": "Ligar"}]}]` — `items` é lista de objetos |
|
|
107
|
+
| `funnels_create/update` | `global_custom_attributes` | igual ao do Kanban |
|
|
108
|
+
| `booking_event_types_create/update` | `confirmation_blocks` e `follow_up_schedules_attributes[].blocks` | `[{"type": "text", "content": "Olá"}]` |
|
|
109
|
+
| `inboxes_update` | `csat_config.survey_rules` | **objeto** `{"operator": "contains", "values": ["vip"]}` — `values` é lista de textos |
|
|
110
|
+
|
|
111
|
+
Continua valendo: a lista **substitui** a anterior (leia com GET e reenvie inteira) e `[]` limpa.
|
|
112
|
+
Recebeu 422 de formato? **Não repita a mesma chamada**: leia a mensagem, corrija o formato e mande de novo.
|
|
113
|
+
|
|
114
|
+
### Recusa por PERMISSÃO (401) — o que mudou em 21/09
|
|
115
|
+
|
|
116
|
+
O servidor responde **401** (não 403) quando o usuário do token não tem a permissão. Não retente; explique ao usuário.
|
|
117
|
+
|
|
118
|
+
- **Fluxos** (`flows_create/update/destroy/toggle`, duplicar, fixar teste, testar nó): só **administrador** ou cargo com
|
|
119
|
+
**Gerenciar FlowBuilder**. `flows_list` e `flows_show` seguem abertos. "Gerenciar Regras de Automação" **não** libera fluxo.
|
|
120
|
+
- **Respostas de formulário** (`lead_forms_responses_list/show`, `lead_forms_stats`, `lead_forms_test_run`): administrador ou
|
|
121
|
+
**Gerenciar Formulários**. As respostas de UM contato continuam em `contacts_form_entries_list`.
|
|
122
|
+
- **Mesclar contatos** (`contacts_create_4` — "Mesclar Contatos", `POST actions/contact_merge`): administrador ou **Gerenciar contatos**
|
|
123
|
+
(mesclar apaga uma das fichas).
|
|
124
|
+
- **Configuração do Kanban** (`kanban_config_update`): motivos de ganho/perda = qualquer usuário; campos do card, checklists e
|
|
125
|
+
`config` = administrador ou **Gerenciar Funis**; webhook e liga/desliga = só administrador. A recusa lista as chaves barradas.
|
|
126
|
+
- **Card do Kanban**: `kanban_items_show/update` e os arquivos do card devolvem **404** para card que o usuário não enxerga no
|
|
127
|
+
quadro. Cargo sem opção de Kanban só edita o card dele ou o sem responsável.
|
|
128
|
+
- **Tipo de agendamento** (`booking_event_types_update/destroy`): só o dono do link ou administrador.
|
|
129
|
+
- **Relatório do Kanban** (`kanban_items` reports): traz `metrics.visibilityScope` — `partial` significa "só os cards que ESTE
|
|
130
|
+
usuário vê". Diga isso ao usuário antes de apresentar o número como total da conta.
|
|
77
131
|
|
|
78
132
|
## Restrições de formato em campos comuns
|
|
79
133
|
|
|
@@ -282,7 +336,7 @@ Vale pra automações, filtro avançado de conversas/contatos e busca "+ Filtro"
|
|
|
282
336
|
| Código | Significado | O que fazer |
|
|
283
337
|
|---|---|---|
|
|
284
338
|
| `400` Bad Request | Parâmetros mal formados | Confira sintaxe |
|
|
285
|
-
| `401` Unauthorized | Token inválido ou
|
|
339
|
+
| `401` Unauthorized | Token inválido/expirado **ou usuário sem a permissão** (o LionChat recusa permissão com 401, não 403) | Reporte ao usuário (não retente) |
|
|
286
340
|
| `403` Forbidden | Sem permissão (papel insuficiente) | Reporte (não retente) |
|
|
287
341
|
| `404` Not Found | Recurso não existe (ou de outra conta) | Confira ID |
|
|
288
342
|
| `422` Unprocessable Entity | Validação falhou | Leia mensagem, corrija |
|
|
@@ -172,10 +172,13 @@ valores desta lista:
|
|
|
172
172
|
| Econômicos / rápidos | `gpt-4.1-nano`, `gpt-4o-mini`, `gpt-4.1-mini`, `gpt-5.4-nano`, `gpt-5.4-mini` |
|
|
173
173
|
| Intermediários | `gpt-4o`, `gpt-4.1`, `gpt-5-mini`, `gpt-5.4` |
|
|
174
174
|
| Raciocínio | `o3-mini`, `o4-mini` |
|
|
175
|
-
| Premium | `gpt-5`, `gpt-5.2`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-terra`, `gpt-5.6-sol`, `o1`, `o3` |
|
|
175
|
+
| Premium | `gpt-5`, `gpt-5.2`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-terra`, `gpt-5.6-sol`, `gpt-6-sol`, `o1`, `o3` |
|
|
176
|
+
| Custo-benefício (nova geração) | `gpt-6-luna` — US$ 0,10/0,50 por 1M tokens, raciocínio, sem temperatura; liberado em 23/09/2026 |
|
|
176
177
|
|
|
177
178
|
**`GPT-5.2 Pro` não existe.** O valor válido é `gpt-5.2`, sem "Pro".
|
|
178
179
|
|
|
180
|
+
> **Família `gpt-6` (`gpt-6-luna`, `gpt-6-sol`) — LIBERADA em 23/09/2026**, pelo mesmo trilho do `gpt-5.6`: sem temperatura e fora do bloco de IA do Formulário de Lead. `gpt-6-astra` NÃO está disponível.
|
|
181
|
+
>
|
|
179
182
|
> **Família `gpt-5.6` (`gpt-5.6-luna`, `gpt-5.6-terra`, `gpt-5.6-sol`) — LIBERADA em 09/2026.**
|
|
180
183
|
> Foi removida em 29/07/2026 porque recusa function tools no canal antigo da OpenAI e deixava a IA MUDA.
|
|
181
184
|
> Desde 09/2026 o servidor fala com esses três pela porta `/v1/responses` (só para eles — nenhum outro
|
|
@@ -190,6 +193,47 @@ valores desta lista:
|
|
|
190
193
|
> Desde 29/07 o erro vira uma **nota privada em português** na conversa (`llm_request_rejected`) — é o
|
|
191
194
|
> primeiro lugar a olhar quando "a IA parou de responder logo depois de mexerem nas configurações".
|
|
192
195
|
|
|
196
|
+
## Ligação por IA — Agentes de ligação (2026-09-24)
|
|
197
|
+
|
|
198
|
+
A ligação por voz **saiu do agente de texto**. Desde 24/09 ela mora em **Agentes de ligação**, uma área
|
|
199
|
+
própria: cada agente de ligação tem um objetivo e **não ocupa vaga de IA do plano**. As chaves antigas
|
|
200
|
+
`config.call_*` do `captain_assistants_update` **não existem mais** — mandar elas não tem efeito.
|
|
201
|
+
|
|
202
|
+
| Ferramenta | Para quê |
|
|
203
|
+
|---|---|
|
|
204
|
+
| `captain_call_agents_list` | lista os agentes de ligação e `meta.dial_inboxes` (caixas que podem ligar) |
|
|
205
|
+
| `captain_call_agents_create` / `_update` / `_duplicate` / `_destroy` | cadastro |
|
|
206
|
+
| `captain_call_test_phones_list` / `_create` / `_destroy` | números autorizados a receber ligação de teste |
|
|
207
|
+
| `captain_call_agents_test_call` | **liga de verdade** para um número de teste cadastrado |
|
|
208
|
+
| `captain_call_agents_test_call_status` | tocando / atendeu / não atendeu, e em qual conversa ficou |
|
|
209
|
+
|
|
210
|
+
Campos do agente de ligação: `name`, `objective` (roteiro, até 4000), `first_message` (até 400), `style`
|
|
211
|
+
(jeito de falar, até 1200), `voice_provider` (`openai` padrão ou `elevenlabs`), `engine` (`gptlive` padrão
|
|
212
|
+
ou `realtime`, só na OpenAI), `voice_id`, `elevenlabs_agent_id` (obrigatório na ElevenLabs),
|
|
213
|
+
`max_duration_seconds` (30 a 600, padrão 180) e **`captain_assistant_id`**.
|
|
214
|
+
|
|
215
|
+
**Como a ligação trabalha (GPT-Live).** A voz conversa e **só consulta** agenda (horários livres, agenda do
|
|
216
|
+
atendente, quem está trabalhando). Quando o cliente pede algo que precisa ser FEITO — mandar link,
|
|
217
|
+
endereço ou proposta pelo WhatsApp, mover o card, anotar — a voz **repassa** ao agente de texto de
|
|
218
|
+
`captain_assistant_id`, diz "já pedi, vai chegar no seu WhatsApp" e **segue a conversa** (nunca diz "já
|
|
219
|
+
mandei"). O agente de texto executa na conversa daquele contato, com as ferramentas e a configuração
|
|
220
|
+
DELE, e decide se escreve ao cliente. Regras fixas desse pedido: roda mesmo com atendente humano na
|
|
221
|
+
conversa ou com a IA pausada; não liga a IA na conversa nem mexe na IA que já estava lá; não passa para
|
|
222
|
+
humano, não encerra, não transfere e não agenda retorno (fluxos rodam completos); no máximo 3 pedidos
|
|
223
|
+
por ligação; caixa oficial fora da janela de 24h faz as ações mas não escreve.
|
|
224
|
+
Sem `captain_assistant_id` (ou no motor `realtime`/ElevenLabs), a voz **só conversa**.
|
|
225
|
+
|
|
226
|
+
**Voz.** É **própria** do agente de ligação — não mexe na voz do áudio da IA no WhatsApp
|
|
227
|
+
(`config.voice_provider`/`config.voice_id` do agente de texto continuam sendo só do WhatsApp). No GPT-Live
|
|
228
|
+
use `captain_voices_list` com `engine=gptlive`: aceita alloy, ash, ballad, coral, echo, sage, shimmer, verse,
|
|
229
|
+
**marin** e **cedar** (as duas mais naturais de telefone); voz fora disso cai na marin.
|
|
230
|
+
|
|
231
|
+
**Ligação de teste.** Só para número **cadastrado** em `captain_call_test_phones` (o telefone nunca vai no
|
|
232
|
+
corpo, só o id). Cria contato e conversa de verdade, pode disparar automações de "conversa criada" e fica
|
|
233
|
+
gravada. Limite de 10 por hora na conta. Precisa da Ligação com IA liberada na conta e da linha da caixa
|
|
234
|
+
conectada; recusa volta 422 com o motivo em `message`. Depois que a ligação termina, a transcrição do
|
|
235
|
+
próprio fornecedor aparece no card da ligação.
|
|
236
|
+
|
|
193
237
|
## Follow-up automático multi-etapa (2026-06)
|
|
194
238
|
|
|
195
239
|
O follow-up do AI Agente agora suporta **cadência de até 3 etapas** via `config.follow_up_steps`:
|
|
@@ -463,7 +507,13 @@ puxados. Se a ativação reclamar de sample, NÃO é bloqueio — a integração
|
|
|
463
507
|
- `ContactLabel` `{id}` — etiqueta de CONTATO (novo)
|
|
464
508
|
- `ContactAttribute` `{key, value}` — atributo do contato (novo)
|
|
465
509
|
- `CardAttribute` `{key, value}` — atributo do card Kanban (novo)
|
|
466
|
-
- `AgentTeam` `{assignee_ids:[], team_ids:[]}` — responsável atual OU time da
|
|
510
|
+
- `AgentTeam` `{assignee_ids:[], team_ids:[], assignee_mode?, team_mode?}` — responsável atual OU time da
|
|
511
|
+
conversa. **Modos (24/09/2026):** `assignee_mode:'none'` = conversa SEM responsável ("Sem atendente"),
|
|
512
|
+
`'any'` = com qualquer responsável; `team_mode:'none'|'any'` igual para time. Ausente/`'specific'` = usa os
|
|
513
|
+
ids (comportamento de sempre). Vale QUALQUER conversa do contato, de qualquer status. Atendente e time
|
|
514
|
+
SEMPRE somam (um OU outro) — inclusive em blocos `AgentTeam` separados, que viram UMA seção só; o
|
|
515
|
+
`audience_mode:'all'` cruza o AgentTeam com as OUTRAS seções (etiqueta, funil, atributo), não atendente com
|
|
516
|
+
time. "Sem atendente E com time" não é montável hoje. Mesmos modos na `exclusion`.
|
|
467
517
|
|
|
468
518
|
O campo `audience_mode` define a combinação ENTRE seções:
|
|
469
519
|
- `"sum"` (default): união — contato em QUALQUER seção entra
|
|
@@ -215,7 +215,8 @@ Funnel
|
|
|
215
215
|
├── name
|
|
216
216
|
├── stages (jsonb: hash com slug_etapa => { name, color, position, description, checklist_templates })
|
|
217
217
|
├── settings (jsonb: { agents: [], goals: [], automations: [{trigger_type, action, action_config, enabled}] })
|
|
218
|
-
├── global_custom_attributes (jsonb array
|
|
218
|
+
├── global_custom_attributes (jsonb array — NENHUMA tela lê este campo do funil; os campos da aba do card
|
|
219
|
+
│ são os do KanbanConfig acima)
|
|
219
220
|
├── meta_events_config (jsonb: won/lost/stages → Meta Pixel/CAPI events; cada bloco: enabled, name,
|
|
220
221
|
│ is_standard, value_strategy, value_fixed, currency, messaging_name — este último é o evento de
|
|
221
222
|
│ ANÚNCIO DE WHATSAPP, tri-estado: ausente = automático, '' = não enviar, um dos 14 nomes da Meta;
|
|
@@ -241,9 +242,10 @@ KanbanItem
|
|
|
241
242
|
├── stage_entered_at (datetime)
|
|
242
243
|
├── position (int, ordem dentro da etapa)
|
|
243
244
|
├── conversation_display_id (FK opcional → Conversation.display_id)
|
|
244
|
-
├── item_details (jsonb
|
|
245
|
-
|
|
246
|
-
├──
|
|
245
|
+
├── item_details (jsonb — os campos da aba Campos ficam em item_details.custom_attributes, LISTA de
|
|
246
|
+
│ {name, type, value}; nunca objeto {chave: valor})
|
|
247
|
+
├── custom_attributes (jsonb — coluna que NENHUMA tela mostra; nao confundir com a lista acima)
|
|
248
|
+
├── assigned_agents (jsonb array — para gravar: lista de NUMEROS [5, 12])
|
|
247
249
|
├── linked_conversations (jsonb array de { display_id })
|
|
248
250
|
├── checklist (jsonb array de itens — NAO e tabela separada; ver abaixo)
|
|
249
251
|
├── activities (jsonb)
|
|
@@ -492,7 +494,7 @@ daquele tipo no calendário; vazio = cor do agente. A tarefa devolve `booking_co
|
|
|
492
494
|
|
|
493
495
|
## e-Clínicas (Efficient) — integração de clínicas
|
|
494
496
|
|
|
495
|
-
|
|
497
|
+
19 eventos de webhook, cada um mapeável a automação OU flow na tela Integrações > e-Clínica
|
|
496
498
|
(o mapeamento e os lembretes passaram a ser editáveis por MCP em 31/08/2026, com
|
|
497
499
|
`lionchat_eclinica_integrations_update` — ele **SUBSTITUI** o objeto inteiro, então leia com
|
|
498
500
|
`_show` e devolva completo, senão apaga o resto):
|
|
@@ -502,7 +504,10 @@ daquele tipo no calendário; vazio = cor do agente. A tarefa devolve `booking_co
|
|
|
502
504
|
`cliente_inclusao_pagamento`, `controle_laboratorio_novo`, `controle_laboratorio_alterado`,
|
|
503
505
|
`agendamento_aguardando`, `odontograma_aprovado`, `procedimento_finalizado`,
|
|
504
506
|
`cliente_alteracao_pagamento`, `odontograma_finalizado`, `inclusao_procedimento`
|
|
505
|
-
(capturados ao vivo, não documentados pelo e-Clínica)
|
|
507
|
+
(capturados ao vivo, não documentados pelo e-Clínica) +
|
|
508
|
+
`agendamento_confirmado_link` e `agendamento_cancelado_link` (18/09/2026 — o PACIENTE confirmando/
|
|
509
|
+
cancelando pelo link do portal, ecli.co; confirmado processa como `agendamento_alterado`, mantendo o
|
|
510
|
+
lembrete; cancelado processa EXATAMENTE como `agendamento_desmarcado`, cancelando o lembrete).
|
|
506
511
|
|
|
507
512
|
O recurso `eclinica_integration` da conta passou a ser ligado e desligado pelo PRÓPRIO cadastro da
|
|
508
513
|
integração (10/09/2026, `auto_managed`): sumiu do Super Admin e não há passo manual — os blocos de
|
|
@@ -36,6 +36,14 @@ E/OU é encadeado condição a condição (sem parênteses).
|
|
|
36
36
|
Atributo personalizado: informe `custom_attribute_type` na condição — `'conversation_attribute'`
|
|
37
37
|
(atributo da conversa) ou `'contact_attribute'`. Sem ele o escopo pode sair errado.
|
|
38
38
|
|
|
39
|
+
**`contact_attribute` lê a FICHA DO CONTATO da conversa (funciona de verdade desde 24/09/2026).** Antes o
|
|
40
|
+
servidor ignorava o valor e lia o atributo da própria conversa — por isso lead de formulário da Meta
|
|
41
|
+
(formulário, anúncio, campanha e 1ª/última origem ficam SÓ no contato) não era achado. Agora a conversa entra
|
|
42
|
+
quando o contato dela casa. Chave precisa ter cadastro de atributo DE CONTATO na conta (senão 422). Exemplo:
|
|
43
|
+
`{attribute_key:'meta_lead_form_name', custom_attribute_type:'contact_attribute', filter_operator:'contains',
|
|
44
|
+
values:['vendas']}`. Negativos (`not_equal_to`, `does_not_contain`, `is_not_present`) incluem a conversa cujo
|
|
45
|
+
contato não tem o dado. Texto compara sem maiúscula/acento.
|
|
46
|
+
|
|
39
47
|
- `chat_type` em `conversations_filter` funciona desde 19/08/2026 (antes respondia 500). `group` =
|
|
40
48
|
conversa de grupo de WhatsApp; `individual` cobre também canal, transmissão e status. Com
|
|
41
49
|
`not_equal_to`, conversa sem contato vinculado NÃO some do resultado.
|
|
@@ -162,6 +170,13 @@ Params: `funnel_id` (obrigatório), `from`, `to`, `user_ids[]` (agentes), `team_
|
|
|
162
170
|
| `moved` | só quando entrou na etapa atual (mesma expressão do `stage_date_*` da seção 3) | "o que se mexeu no período" |
|
|
163
171
|
| `closed` | só ganhos/perdidos no período | **a pergunta de receita** — é a régua certa pra "quanto vendemos em julho" |
|
|
164
172
|
|
|
173
|
+
**Ganho/perda pela DATA DO FECHAMENTO (23/09/2026).** Com a régua `any` o relatório traz também cards que
|
|
174
|
+
nasceram no período mas fecharam DEPOIS dele. Por isso, para "quanto ganhamos/perdemos em julho", leia
|
|
175
|
+
`wonInPeriod`/`wonValueInPeriod` e `lostInPeriod`/`lostValueInPeriod` (este último é campo NOVO) — **nunca**
|
|
176
|
+
`statusDistribution`, que é a foto do status de HOJE (serve só para "negócios abertos agora"). Desde 23/09 os
|
|
177
|
+
motivos de ganho/perda, os perdidos recentes, a receita por semana e o ranking de vendedores também contam só
|
|
178
|
+
o que FECHOU no período — antes somavam por status de hoje e divergiam do quadro de Ganhos na mesma tela.
|
|
179
|
+
|
|
165
180
|
O relatório de UMA etapa — tool `lionchat_funnels_stage_report` (`GET /funnels/:id/stage_report`, o
|
|
166
181
|
painel que abre dentro do quadro) — tem as MESMAS 4 opções de régua, mesmo parâmetro `date_basis` e as
|
|
167
182
|
MESMAS expressões da seção 3, mas o **padrão dele é `moved`**, não `any`. Não é inconsistência: ele
|
|
@@ -140,6 +140,7 @@ Webhooks embutidos NÃO aparecem na listagem de integrações standalone; exclui
|
|
|
140
140
|
**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.
|
|
141
141
|
|
|
142
142
|
**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).
|
|
143
|
+
- **`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.
|
|
143
144
|
- Ao **ativar** (`flows_toggle` inativo→ativo) ou **criar já ativo**: qualquer conflito é barrado.
|
|
144
145
|
- Ao **editar** um flow já ativo: só conflito NOVO é barrado (duplicados que já existiam são preservados).
|
|
145
146
|
- A API responde **422** com `{ "error_code": "flow_trigger_conflict", "conflicts": [{ flow_id, flow_name, trigger_type, inbox_id, inbox_name }] }`.
|
|
@@ -705,7 +706,9 @@ Exemplo: `{"aiMode":"sentiment","aiAssistantId":"12","aiModel":"gpt-4.1-mini","a
|
|
|
705
706
|
curinga** — não existe "a família gpt-5 inteira":
|
|
706
707
|
`gpt-4o-mini`, `gpt-4o`, `gpt-4.1-nano`, `gpt-4.1-mini`, `gpt-4.1`, `gpt-5-mini`, `gpt-5`,
|
|
707
708
|
`gpt-5.2`, `gpt-5.4-nano`, `gpt-5.4-mini`, `gpt-5.4`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-terra`,
|
|
708
|
-
`gpt-5.6-sol`, `o1`, `o3`, `o3-mini`, `o4-mini`.
|
|
709
|
+
`gpt-5.6-sol`, `gpt-6-luna`, `gpt-6-sol`, `o1`, `o3`, `o3-mini`, `o4-mini`.
|
|
710
|
+
A família **`gpt-6` (luna/sol) entrou em 23/09/2026** pelo mesmo trilho do `gpt-5.6` (porta `/v1/responses`,
|
|
711
|
+
sem temperatura, fora do Formulário de Lead).
|
|
709
712
|
A família **`gpt-5.6` (luna/terra/sol) voltou em 09/2026** (tinha sido removida em 2026-07-29 porque
|
|
710
713
|
recusa function tools no canal antigo): o servidor fala com esses três pela porta `/v1/responses`.
|
|
711
714
|
Eles ignoram a temperatura do bloco (só o padrão) e **NÃO valem no bloco de IA do Formulário de Lead**
|
|
@@ -388,13 +388,15 @@ mandar). Detalhes em `lionchat://docs/best-practices`.
|
|
|
388
388
|
|
|
389
389
|
**Onde fica armazenado:** `kanban_config.win_reasons` e `kanban_config.loss_reasons` (jsonb arrays na tabela `kanban_configs`).
|
|
390
390
|
|
|
391
|
-
**Formato:** array de objetos `{id, title}
|
|
391
|
+
**Formato:** array de objetos `{id, title}`, com `id` em **texto estável** (nunca número) — detalhes e erros 422 em
|
|
392
|
+
`lionchat://docs/api-conventions` → "Estrutura interna das listas":
|
|
392
393
|
```json
|
|
393
394
|
"win_reasons": [
|
|
394
395
|
{"id": "wr-1", "title": "Preço competitivo"},
|
|
395
396
|
{"id": "wr-2", "title": "Indicação forte"}
|
|
396
397
|
]
|
|
397
398
|
```
|
|
399
|
+
**No card:** `item_details.loss_reason` / `win_reason` guardam o `id` (texto) do motivo escolhido; `reason`, o título.
|
|
398
400
|
|
|
399
401
|
**Endpoint:** `PUT /api/v1/accounts/{id}/kanban_config` com body wrapped:
|
|
400
402
|
```json
|
|
@@ -414,7 +416,7 @@ mandar). Detalhes em `lionchat://docs/best-practices`.
|
|
|
414
416
|
|---|---|---|
|
|
415
417
|
| Motivo de Ganho/Perda do card | `kanban_config.win_reasons` / `loss_reasons` | ❌ NÃO |
|
|
416
418
|
| Atributo em TODO card | `kanban_config.global_custom_attributes` | só se não couber acima |
|
|
417
|
-
|
|
|
419
|
+
| Valor de um campo em UM card | `item_details.custom_attributes` — LISTA `[{name, type, value}]` casando com o campo de `kanban_config.global_custom_attributes` | a coluna `kanban_item.custom_attributes` NÃO aparece em tela nenhuma — não use pra dado que o cliente precisa ver |
|
|
418
420
|
| CPF, RG, CNPJ, endereço, data nasc., gênero do cliente | mecanismo NATIVO cadastral: `PATCH /contacts/{id}/cadastral` (`update_cadastral`) | ❌ NÃO (tem nativo) |
|
|
419
421
|
| Tag pro contato (residencial, empresarial) | `labels` | ✅ SIM via Label |
|
|
420
422
|
| Etapa do funil | `funnel.stages` | ❌ NÃO |
|
|
@@ -16,6 +16,7 @@ Container de etapas. Conta pode ter vários funis (ex: "Vendas", "Pós-venda", "
|
|
|
16
16
|
| `archived` | Boolean — funis arquivados não aparecem na UI ativa |
|
|
17
17
|
| `active` | Boolean — controla se aceita movimentação |
|
|
18
18
|
| `settings` | jsonb — config customizada (ex: cores, automações) |
|
|
19
|
+
| `settings.agents` | agentes do funil. Grave `[{"id": <id do agente>}]` — cada item é um OBJETO, nunca número solto (ids de `lionchat_agents_list`); o sistema completa nome, e-mail, cargo e foto — é o que o editor do funil, o card e a conversa mostram. Agente de outra conta fica sem nome e sem acesso. `settings` é substituído INTEIRO no update: leia o funil antes e reenvie goals+agents+teams+automations. |
|
|
19
20
|
|
|
20
21
|
### Stages (Etapas) — dentro de `funnel.stages`
|
|
21
22
|
|
|
@@ -65,8 +66,8 @@ Stages NÃO são tabela separada. São armazenadas como jsonb dentro do Funnel:
|
|
|
65
66
|
|
|
66
67
|
| Campo | Tipo | O que guarda |
|
|
67
68
|
|---|---|---|
|
|
68
|
-
| `win_reasons` | jsonb array | **Motivos de Ganho** — `[{id, title}]
|
|
69
|
-
| `loss_reasons` | jsonb array | **Motivos de Perda** — mesma estrutura
|
|
69
|
+
| `win_reasons` | jsonb array | **Motivos de Ganho** — `[{id, title}]`, `id` em **texto estável** (nunca número). Aparecem como dropdown quando o vendedor marca "Ganho" num card. NATIVO. NÃO usar custom_attribute. |
|
|
70
|
+
| `loss_reasons` | jsonb array | **Motivos de Perda** — mesma estrutura e mesma regra do `id`. Aparece ao marcar "Descartado". |
|
|
70
71
|
| `checklist_templates` | jsonb array | Templates de checklist reusáveis — `[{id, name, items: [{id, text}]}]`. Aplicados manualmente ou via automação `apply_checklist_template`. |
|
|
71
72
|
| `global_custom_attributes` | jsonb array | Atributos globais que aparecem em TODOS os cards de TODOS os funis — `[{name, type, is_list, list_values}]`. |
|
|
72
73
|
| `config` | jsonb hash | Configurações gerais (title, default_view, auto_assignment, support_email, dragbar_enabled, etc) |
|
|
@@ -82,7 +83,8 @@ Stages NÃO são tabela separada. São armazenadas como jsonb dentro do Funnel:
|
|
|
82
83
|
| DELETE | `/api/v1/accounts/{id}/kanban_config` | Remove (não afeta cards/funis) |
|
|
83
84
|
| POST | `/api/v1/accounts/{id}/kanban_config/test_webhook` | Dispara payload de teste |
|
|
84
85
|
|
|
85
|
-
**
|
|
86
|
+
**Body raiz ou com o envelope `kanban_config` — os dois funcionam** (conferido 21/09: `{"loss_reasons": [...]}` na
|
|
87
|
+
raiz grava e recusa normalmente). Exemplo com envelope:
|
|
86
88
|
|
|
87
89
|
```json
|
|
88
90
|
PUT /api/v1/accounts/43/kanban_config
|
|
@@ -100,7 +102,11 @@ PUT /api/v1/accounts/43/kanban_config
|
|
|
100
102
|
}
|
|
101
103
|
```
|
|
102
104
|
|
|
103
|
-
|
|
105
|
+
**Regras dos motivos** (servidor, desde 21/09): `id` em texto estável — número é convertido (`7` → `"7"`), mas mande
|
|
106
|
+
texto; a lista SUBSTITUI a atual, então reenvie os MESMOS `id` dos motivos que já existem (trocar o `id` tira o nome
|
|
107
|
+
dos cards já marcados); lista de textos soltos, motivo sem `id`/`title` ou `id` repetido → **422** com o formato
|
|
108
|
+
(antes, a lista de textos APAGAVA os motivos em silêncio). No card: `item_details.loss_reason`/`win_reason` = o `id`
|
|
109
|
+
(texto) + `reason` = o título. Detalhes em `lionchat://docs/api-conventions` → "Estrutura interna das listas".
|
|
104
110
|
|
|
105
111
|
**`win_reasons` e `loss_reasons` aceitam array de OBJETOS `{id, title}`, NÃO strings simples.** Strings causam 500. O `id` é qualquer string única (UUID ou slug curto tipo `wr-1`).
|
|
106
112
|
|
|
@@ -114,7 +120,7 @@ Se mandar `{"win_reasons": [...]}` direto (sem o wrapper `kanban_config`) → **
|
|
|
114
120
|
| Atributo que aparece em TODO card | `kanban_config.global_custom_attributes` | ❌ custom_attribute de conversation |
|
|
115
121
|
| Atributo só de um contato (CPF, endereço) | `custom_attribute_definitions` model=contact_attribute | ❌ kanban_config |
|
|
116
122
|
| Atributo só de uma conversa (motivo, tag interna) | `custom_attribute_definitions` model=conversation_attribute | ❌ kanban_config |
|
|
117
|
-
|
|
|
123
|
+
| Valor de um campo num card (aparece na aba Campos) | `item_details.custom_attributes` — LISTA `[{name, type, value}]`, com o campo definido em `kanban_config.global_custom_attributes` | ❌ `kanban_item.custom_attributes` (coluna que nenhuma tela mostra) |
|
|
118
124
|
|
|
119
125
|
### KanbanItem (Card)
|
|
120
126
|
Um card individual dentro de uma etapa.
|
|
@@ -130,7 +136,7 @@ Um card individual dentro de uma etapa.
|
|
|
130
136
|
| `origin_conversation_display_id` | Conversa em que o card NASCEU (só preenchida se o vínculo já foi movido). É o que o relatório de origem de lead usa, pra uma venda não mudar de mês nem de anúncio quando o card anda. |
|
|
131
137
|
| `linked_conversations` | jsonb array `[{display_id: 123}, {display_id: 456}]` — múltiplas conversas |
|
|
132
138
|
| `item_details` | jsonb (ver abaixo) |
|
|
133
|
-
| `custom_attributes` | jsonb — campos
|
|
139
|
+
| `custom_attributes` | jsonb (coluna própria) — **NÃO aparece na aba Campos, no filtro do quadro nem na busca**. Os campos visíveis do card moram em `item_details.custom_attributes` (ver abaixo) |
|
|
134
140
|
| `assigned_agents` | jsonb array de agentes responsáveis |
|
|
135
141
|
| `activities` | jsonb array — log de atividades |
|
|
136
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 |
|
|
@@ -172,13 +178,31 @@ Um card individual dentro de uma etapa.
|
|
|
172
178
|
"offers": [
|
|
173
179
|
{"id": 12, "title": "Pro 12 meses", "value": 4800}
|
|
174
180
|
],
|
|
175
|
-
"custom_attributes":
|
|
176
|
-
"
|
|
177
|
-
|
|
181
|
+
"custom_attributes": [
|
|
182
|
+
{"name": "Origem do Lead", "type": "string", "value": "Facebook Ads"}
|
|
183
|
+
]
|
|
178
184
|
}
|
|
179
185
|
```
|
|
180
186
|
|
|
181
|
-
**`value`** é onde fica o valor monetário do negócio (usado em pipelines).
|
|
187
|
+
**`value`** é onde fica o valor monetário do negócio (usado em pipelines). Sempre NÚMERO — texto quebra a
|
|
188
|
+
soma das colunas.
|
|
189
|
+
|
|
190
|
+
**`custom_attributes` é uma LISTA, nunca um objeto `{chave: valor}`** (conferido no código em 18/09/2026).
|
|
191
|
+
Cada item é `{name, type, value}` e só aparece na aba Campos se `name` **e** `type` baterem exatamente com
|
|
192
|
+
um campo de `kanban_config.global_custom_attributes` (leia com `lionchat_kanban_config_list`).
|
|
193
|
+
|
|
194
|
+
Como gravar pelo `lionchat_kanban_items_update` (`kanban_item.item_details`):
|
|
195
|
+
- O `item_details` é MESCLADO só no 1º nível: cada chave enviada **troca a chave inteira** no card. Por isso
|
|
196
|
+
a lista `custom_attributes` enviada **substitui a lista toda** — leia o card com `lionchat_kanban_items_show`
|
|
197
|
+
e reenvie TODOS os campos, com o alterado.
|
|
198
|
+
- Mandar objeto (`{"origem_lead": "Facebook Ads"}`) no lugar da lista **APAGA todos os campos do card**: o
|
|
199
|
+
servidor só aceita itens `{name, type, value}` e o objeto vira vazio.
|
|
200
|
+
- 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, duplicated_from_id, priority, value, currency,
|
|
202
|
+
custom_attributes, offers, closed_offers, closed_offer, deadline_at, scheduling_type, scheduled_at,
|
|
203
|
+
conversation_id, automations, notes.
|
|
204
|
+
- Para mudar UM campo sem reenviar a lista, as ações de automação/macro `update_card_attribute`
|
|
205
|
+
(`[{funnel_id, attribute_key: "<nome do campo>", value}]`) mexem só naquela entrada.
|
|
182
206
|
|
|
183
207
|
### assigned_agents
|
|
184
208
|
|
|
@@ -198,6 +222,10 @@ Um card individual dentro de uma etapa.
|
|
|
198
222
|
|
|
199
223
|
Múltiplos agentes podem ter o mesmo card. `source` pode ser `manual`, `automation`, `inherited_from_conversation`.
|
|
200
224
|
|
|
225
|
+
**Para GRAVAR** (`kanban_items_create`/`_update`, `kanban_item.assigned_agents`) o formato é outro: LISTA de
|
|
226
|
+
NÚMEROS — `[5, 12]`. O sistema completa nome, e-mail e foto. A lista enviada **substitui** a atual (mande
|
|
227
|
+
todos que devem ficar). Objetos `{id, ...}` são ignorados em silêncio e a lista não muda.
|
|
228
|
+
|
|
201
229
|
**Agente do card vira participante das conversas (2026-06):** atribuir um agente a um card do Kanban
|
|
202
230
|
(via `kanban_agents` ou ao vincular uma conversa) agora também o adiciona como PARTICIPANTE de todas
|
|
203
231
|
as conversas do card (a principal `conversation_display_id` + as de `linked_conversations`). É a 4ª
|
|
@@ -332,6 +360,9 @@ Endpoint: `GET /api/v2/kanban/items/counts` retorna contagem + soma por etapa.
|
|
|
332
360
|
Funis agora têm visibilidade por usuário. Um funil é visível pra alguém quando:
|
|
333
361
|
- é admin da conta, OU
|
|
334
362
|
- tem permissão `kanban_view`/`kanban_manage` (custom role), OU
|
|
363
|
+
- tem `funnel_manage` (21/09): quem pode criar/editar/arquivar qualquer funil passou a **enxergar** qualquer funil
|
|
364
|
+
na lista — antes editava pela API um funil restrito que não aparecia em `funnels_list`. Só o FUNIL: os cards do
|
|
365
|
+
funil restrito seguem a régua de card, OU
|
|
335
366
|
- o funil está aberto a todos, OU
|
|
336
367
|
- a pessoa participa do funil (está em `settings.agents`, OU é membro de um TIME em `settings.teams` — novo 2026-07-21, membros resolvidos ao vivo — ou tem card atribuído)
|
|
337
368
|
|
|
@@ -342,6 +373,10 @@ Funis agora têm visibilidade por usuário. Um funil é visível pra alguém qua
|
|
|
342
373
|
`can_edit`, `can_move`, `can_delete`, `can_assign` (booleans)
|
|
343
374
|
- `kanban_items_move` sem permissão → **403** com mensagem traduzida (antes dava 500/sucesso falso)
|
|
344
375
|
- Cards embutidos na tela da conversa também respeitam a visibilidade
|
|
376
|
+
- **Aviso em tempo real do card (21/09):** `kanban_item.created/updated` deixou de ir para a conta inteira — vai só
|
|
377
|
+
para quem VÊ aquele card (mesma régua acima) + administradores. Quem perde a visão (card passou a outro
|
|
378
|
+
responsável, mudou de funil) recebe `kanban_item.deleted` com só `{id, funnel_id}`. Integração que escuta o
|
|
379
|
+
WebSocket com token de usuário restrito recebe menos eventos que antes; com token de administrador, nada muda.
|
|
345
380
|
|
|
346
381
|
**Pro MCP:** antes de tentar mover/editar card, confira os campos `can_*` do show — se `can_move`
|
|
347
382
|
é false, explique ao usuário que ele não tem acesso àquele funil em vez de tentar mesmo assim.
|
|
@@ -534,33 +569,44 @@ Use para: ações cross-cutting que envolvem conversa/contato/label, ou regras c
|
|
|
534
569
|
|
|
535
570
|
Cada card pode receber atributos custom de 3 origens diferentes. **A escolha do lugar muda completamente o resultado:**
|
|
536
571
|
|
|
537
|
-
### 1. `
|
|
572
|
+
### 1. `item_details.custom_attributes` (o VALOR de cada campo, dentro do card)
|
|
538
573
|
|
|
539
574
|
```json
|
|
540
|
-
|
|
541
|
-
"
|
|
542
|
-
"
|
|
543
|
-
|
|
544
|
-
}
|
|
575
|
+
[
|
|
576
|
+
{"name": "Origem do Lead", "type": "string", "value": "Google Ads"},
|
|
577
|
+
{"name": "Score", "type": "number", "value": 85}
|
|
578
|
+
]
|
|
545
579
|
```
|
|
546
580
|
|
|
547
|
-
-
|
|
548
|
-
-
|
|
549
|
-
|
|
550
|
-
-
|
|
581
|
+
- É o que a aba **Campos** do card mostra e edita (e o que o filtro do quadro, a busca e o fluxo leem)
|
|
582
|
+
- LISTA de `{name, type, value}`; `name` + `type` precisam bater com um campo do item 2 abaixo, senão o
|
|
583
|
+
valor fica gravado e **não aparece**
|
|
584
|
+
- Grava via `kanban_items_update` em `kanban_item.item_details.custom_attributes` — a lista enviada
|
|
585
|
+
**substitui a inteira** (leia o card antes e reenvie tudo). Objeto `{chave: valor}` no lugar da lista
|
|
586
|
+
**apaga** os campos do card
|
|
587
|
+
- Um campo só, sem reenviar a lista: ação `update_card_attribute` da automação/macro
|
|
588
|
+
|
|
589
|
+
> **NÃO confundir com a coluna `kanban_item.custom_attributes`** (objeto `{chave: valor}` direto no card):
|
|
590
|
+
> nenhuma tela a mostra — nem a aba Campos, nem o filtro, nem a busca. Só a ação "Alterar atributo do card"
|
|
591
|
+
> do FlowBuilder e a leitura do fluxo a usam. Para o cliente ver o dado, use a lista acima.
|
|
551
592
|
|
|
552
593
|
### 2. `kanban_config.global_custom_attributes` (atributos globais do Kanban)
|
|
553
594
|
|
|
554
595
|
```json
|
|
555
596
|
[
|
|
556
|
-
{"name": "Origem do Lead", "type": "
|
|
597
|
+
{"name": "Origem do Lead", "type": "string", "is_list": true, "list_values": ["Google", "Meta", "Indicação"]},
|
|
557
598
|
{"name": "Score", "type": "number", "is_list": false}
|
|
558
599
|
]
|
|
559
600
|
```
|
|
560
601
|
|
|
561
|
-
- Definido no `kanban_config` da conta
|
|
562
|
-
|
|
563
|
-
-
|
|
602
|
+
- Definido no `kanban_config` da conta (`lionchat_kanban_config_update`) — é a DEFINIÇÃO; o valor de cada
|
|
603
|
+
card mora no item 1
|
|
604
|
+
- Aparece em TODOS os cards de TODOS os funis (aba Campos do card)
|
|
605
|
+
- Tipos que a tela cria: `string` (texto), `number`, `date`, `boolean`; lista de opções = `is_list: true` +
|
|
606
|
+
`list_values`
|
|
607
|
+
- A lista enviada **substitui a inteira** — campo que não vier some da aba de todos os cards. Leia antes com
|
|
608
|
+
`lionchat_kanban_config_list`
|
|
609
|
+
- **Não confundir com `funnel.global_custom_attributes`** (coluna do funil): nenhuma tela lê aquele campo
|
|
564
610
|
- Use para: atributos que TODO card precisa ter
|
|
565
611
|
|
|
566
612
|
### 3. `custom_attribute_definitions` (atributos globais de contato/conversa)
|
|
@@ -607,3 +653,66 @@ Cada card pode receber atributos custom de 3 origens diferentes. **A escolha do
|
|
|
607
653
|
1. Algum card sem `item_details.value`?
|
|
608
654
|
2. Cards arquivados estão sendo contados?
|
|
609
655
|
3. Etapas "ganho"/"perdido" estão incluídas no cálculo?
|
|
656
|
+
|
|
657
|
+
## Conciliação de vendas — "Importar vendas" (2026-09-24)
|
|
658
|
+
|
|
659
|
+
O problema que ela resolve: **vendedor não marca a venda certa no card**. Aí o relatório de faturamento
|
|
660
|
+
mente — ou porque o card ficou aberto, ou porque o valor do card não é o valor que o cliente pagou.
|
|
661
|
+
|
|
662
|
+
A planilha do financeiro (ou de outro sistema) entra e:
|
|
663
|
+
|
|
664
|
+
| Situação do card no funil | O que acontece |
|
|
665
|
+
|---|---|
|
|
666
|
+
| Card **aberto** (mais antigo, se houver vários) | Grava o valor e marca **ganho com a DATA DA VENDA** |
|
|
667
|
+
| Card **já ganho** | Atualiza **só o valor**; a data do ganho dele **não muda** |
|
|
668
|
+
| Card marcado como **perdido** | **Não é tocado** — vai pra conferência humana |
|
|
669
|
+
| **Sem card nenhum** | Cria card já ganho (só se `criar_sem_card: true`) |
|
|
670
|
+
| Linha com telefone sem DDI, valor ilegível ou data no futuro | Vira **erro da linha**, com motivo |
|
|
671
|
+
|
|
672
|
+
### Ferramentas
|
|
673
|
+
|
|
674
|
+
1. `lionchat_kanban_sales_reconciliation_preview` — **confere e não grava nada**. Chame SEMPRE antes.
|
|
675
|
+
2. `lionchat_kanban_sales_reconciliation_apply` — aplica em segundo plano, devolve `run_id`.
|
|
676
|
+
3. `lionchat_kanban_sales_reconciliation_status` — acompanha até `completed`/`failed`.
|
|
677
|
+
|
|
678
|
+
O MCP **não sobe arquivo**: as linhas vão em `rows` (lista de objetos). Se a pessoa anexar uma planilha
|
|
679
|
+
na conversa, LEIA o arquivo, monte as linhas em JSON e chame a ferramenta — não peça pra ela converter.
|
|
680
|
+
Quem tem CSV/Excel e prefere a tela usa Kanban > botão azul **+** > **Importar vendas**, que lê o
|
|
681
|
+
arquivo, aponta as colunas e ainda oferece uma planilha de exemplo pra baixar.
|
|
682
|
+
|
|
683
|
+
### Formato de cada linha de `rows`
|
|
684
|
+
|
|
685
|
+
| Campo | Obrigatório | Como mandar |
|
|
686
|
+
|---|---|---|
|
|
687
|
+
| `phone` | sim | Com o código do país: `5511999887766` |
|
|
688
|
+
| `value` | sim | `1500`, `"1500,00"`, `"R$ 1.500,00"` ou `"1,500.00"` |
|
|
689
|
+
| `sale_date` | sim | `"01/08/2026"` ou `"2026-08-01"` — o dia em que a venda aconteceu |
|
|
690
|
+
| `name` | não | Nome do cliente (usado no título do card novo) |
|
|
691
|
+
| `email` | não | |
|
|
692
|
+
| `agent` | não | Nome ou e-mail do vendedor |
|
|
693
|
+
| `order_id` | não | Número do pedido, guardado no card |
|
|
694
|
+
|
|
695
|
+
### O que você PRECISA saber antes de aplicar
|
|
696
|
+
|
|
697
|
+
- **O telefone tem que vir com o código do país** (`5511999887766`). O sistema **não** completa o 55 —
|
|
698
|
+
linha sem DDI é recusada com motivo. Celular antigo sem o nono dígito é encontrado do mesmo jeito.
|
|
699
|
+
- **A data da venda é o ponto da funcionalidade.** É ela que faz a venda contar no mês certo do
|
|
700
|
+
relatório. Sem data, a linha é recusada — nunca vira "hoje" em silêncio.
|
|
701
|
+
- **A conciliação não dispara conversão por conta própria.** Quem dispara é o caminho normal do ganho
|
|
702
|
+
(Meta/GA4/Google Ads), e só nos funis com o evento de Ganho configurado. Por isso rodar a mesma
|
|
703
|
+
planilha duas vezes não reenvia conversão: o identificador do evento de ganho é estável.
|
|
704
|
+
- **Rodar a mesma planilha duas vezes é seguro**: card já com aquele valor volta como `sem_mudanca` e
|
|
705
|
+
nem é gravado.
|
|
706
|
+
- **`criar_sem_card: true` abre uma CONVERSA nova por card criado**, e conversa nova acorda o que a conta
|
|
707
|
+
tiver em "Conversa criada" (automação, fluxo, notificação). Avise a pessoa antes de ligar isso numa
|
|
708
|
+
planilha grande.
|
|
709
|
+
- **Automação de funil que duplica o card no ganho continua rodando** (é um dos dois motores de
|
|
710
|
+
automação, ver a seção acima). A conferência conta quantos cards de pós-venda vão nascer.
|
|
711
|
+
- **O vendedor da planilha só entra em card SEM responsável** — nunca troca quem já está lá.
|
|
712
|
+
- **Porta:** administrador ou cargo com "importar e exportar cards".
|
|
713
|
+
|
|
714
|
+
### Diagnóstico: "a venda entrou no mês errado"
|
|
715
|
+
|
|
716
|
+
Olhe `item_details.status_changed_at` do card: ele é comparado como **texto** contra a janela do
|
|
717
|
+
relatório, e tem que terminar em `Z`. `2026-08-01T03:00:00Z` é 1º de agosto em Brasília; gravar
|
|
718
|
+
`2026-08-01T00:00:00Z` joga a venda pra julho.
|