Há três objetos diferentes. Fluxos são grafos versionados de espera, condição e envio, em que cada contato entra por uma inscrição. Retornos avulsos (/ai/followups/promises) são um único retorno agendado para um contato. As promessas do turno (GET /ai/promises) são o registro, somente leitura, do que o agente disse que faria; ficam em Acompanhamento.
Para o agente inscrever contatos, ligue followup.enabled na versão, liste os fluxos em followup.flow_ids e habilite as ferramentas followups.*.
Fluxos
Nós: trigger, wait, condition, ai_classify, match_reply, repeat, action, end. O grafo tem 2 a 60 nós e até 120 arestas; cada aresta tem condition always, branch (branch_id), class_match ou cond_result. Esperas vão de 5 minutos a 90 dias. Para começar de um modelo pronto, use from-model e leia o grafo gerado.
GET /ai/followup-flows
Escopo agents:read
Query customer_id. Fluxos com rascunho (graph), settings, status e published_version_id.
POST /ai/followup-flows
Escopo agents:write
| Campo | Tipo e limites | Uso |
|---|---|---|
name | 1–80 | Nome do fluxo. |
graph | {nodes, edges} | Grafo do rascunho. |
settings.trigger | {kind, params?, cancel_on_reply?} | manual, webhook, stage_change {stage_id}, silence {threshold_minutes 5–10.080}, case_opened, appointment_no_show. conversation_end não inicia envios. |
settings.handoff_policy | pause | cancel | allow | O que fazer quando uma pessoa assume a conversa. |
settings.send_start_hour · send_end_hour | 0–23 · 1–24 | Janela de envio; início antes do fim. |
settings.send_days | 1–7 dias, 0 = domingo | Dias de envio. |
settings.timezone | fuso IANA | Fuso da janela. |
settings.purpose · environment | utility|marketing · live|sandbox | Categoria e ambiente do envio. |
settings.trigger_agent_id | UUID ou null, opcional | Agente responsável pelos gatilhos automáticos. |
Exemplo validado em teste contra o schema da rota e a checagem de publicação:
{
"customer_id": "11111111-1111-4111-8111-111111111111",
"name": "Retomada em 4 horas",
"graph": {
"nodes": [
{
"id": "inicio",
"type": "trigger",
"label": "Início",
"position": {
"x": 0,
"y": 0
},
"config": {}
},
{
"id": "espera",
"type": "wait",
"label": "Esperar 4 horas",
"position": {
"x": 240,
"y": 0
},
"config": {
"mode": "fixed",
"duration_ms": 14400000
}
},
{
"id": "lembrete",
"type": "action",
"label": "Lembrete",
"position": {
"x": 480,
"y": 0
},
"config": {
"mode": "text",
"body": "Oi! Conseguiu ver a proposta que enviamos?"
}
},
{
"id": "fim",
"type": "end",
"label": "Fim",
"position": {
"x": 720,
"y": 0
},
"config": {
"outcome": "exhausted"
}
}
],
"edges": [
{
"id": "e1",
"source": "inicio",
"target": "espera",
"condition": {
"type": "always"
}
},
{
"id": "e2",
"source": "espera",
"target": "lembrete",
"condition": {
"type": "always"
}
},
{
"id": "e3",
"source": "lembrete",
"target": "fim",
"condition": {
"type": "always"
}
}
]
},
"settings": {
"trigger": {
"kind": "manual",
"cancel_on_reply": true
},
"handoff_policy": "pause",
"send_start_hour": 9,
"send_end_hour": 20,
"send_days": [
1,
2,
3,
4,
5
],
"timezone": "America/Sao_Paulo",
"purpose": "utility",
"environment": "live"
}
}Responde 201 com o fluxo em rascunho.
GET /ai/followup-flows/from-model
Escopo agents:read
Modelos prontos: id, name, summary, journey, trigger_description, requires_stage e max_messages.
POST /ai/followup-flows/from-model
Escopo agents:write
Corpo {customer_id, model_id, name?, stage_id?}. stage_id é obrigatório nos modelos com requires_stage (422 stage_required). Responde 201 com o fluxo criado.
GET /ai/followup-flows/{id}
Escopo agents:read
Query customer_id.
PUT /ai/followup-flows/{id}
Escopo agents:write
Corpo {customer_id, expected_revision, name, graph, settings}. Salva o rascunho; a versão publicada não muda.
PATCH /ai/followup-flows/{id}
Escopo agents:write
Corpo {customer_id, expected_revision, status} com active, paused ou archived. Ativar exige versão publicada (422 publish_required).
POST /ai/followup-flows/{id}/publish
Escopo agents:write
Corpo {customer_id, expected_revision}. Valida alcance, caminhos até o fim, saídas cobertas, ciclos sem espera, templates e janela dos agentes que usam o fluxo. Com erro, responde 422 invalid_graph e validation_errors (node_id, code, message, branch_id).
GET /ai/followup-flows/{id}/versions
Escopo agents:read
Query customer_id. Versões publicadas, da mais nova à mais antiga.
POST /ai/followup-flows/{id}/rollback
Escopo agents:write
Corpo {customer_id, expected_revision, version_id}. Publica de novo uma versão anterior, com as mesmas validações.
Inscrições
GET /ai/followups/enrollments
Escopo agents:read
Query customer_id, flow_id, contact_id, status e limit (1–200, padrão 100). Status: active, waiting_reply, dormente, paused_handoff, paused_manual, completed, cancelled, dead.
POST /ai/followups/enrollments
Escopo agents:write
{
"customer_id": "11111111-1111-4111-8111-111111111111",
"flow_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
"contact_id": "88888888-8888-4888-8888-888888888888",
"conversation_id": "99999999-9999-4999-8999-999999999999",
"operation_key": "66666666-6666-4666-8666-666666666666",
"agent_id": "44444444-4444-4444-8444-444444444444"
}agent_id e appointment_id são opcionais. Repetir a operation_key devolve a mesma inscrição. Responde 201.
GET /ai/followups/enrollments/{id}
Escopo agents:read
Query customer_id. enrollment, events e effects (envios, classificações e planos de horário, com status, texto, template e consumo).
POST /ai/followups/enrollments/{id}/control
Escopo agents:write
| Campo | Tipo e limites | Uso |
|---|---|---|
action | pause | resume | postpone | skip | cancel | Ação sobre a inscrição. |
due_at | ISO com fuso | Nova data em postpone. |
branch_id | até 64 | Saída a seguir em skip, quando o nó tem mais de uma. |
note | até 1.000 | Registro opcional. |
Corpo com customer_id e expected_revision da inscrição. Envio em andamento ou incerto bloqueia a alteração (409 dispatch_busy).
Efeitos
POST /ai/followups/effects/{id}/decision
Escopo agents:write · chave criada por um Administrador
Corpo {customer_id, approve}. Aprova ou recusa um envio que aguarda decisão. Retorna {ok, id, status}. Pela API, a chave precisa ter sido criada por um Administrador (senão 403 forbidden); no painel, qualquer membro da conta (Operador ou Administrador) decide. A aprovação perde o efeito se, antes do envio, quem aprovou sair da conta ou a chave for revogada: o envio fica rejected com approval_revoked.
POST /ai/followups/effects/{id}/resolve
Escopo agents:write · chave criada por um Administrador
Concilia um envio com resultado incerto. outcome: sent, rejected ou cancelled; note com a evidência (10–2.000); wamid opcional. Retorna {resolved: true}. Pela API, a chave precisa ter sido criada por um Administrador (senão 403 forbidden); no painel, qualquer membro da conta (Operador ou Administrador) concilia.
{
"customer_id": "11111111-1111-4111-8111-111111111111",
"outcome": "sent",
"note": "Mensagem conferida no WhatsApp Manager às 10h12.",
"wamid": "wamid.HBgNNTUxMTk5OTk5ODg4OBUCABIYIDNBMEY"
}Retornos avulsos
Um retorno avulso agenda uma única retomada do contato pelo agente. Na hora marcada, dentro da janela de 24 horas, o agente retoma a conversa. Fora dela, outside_window decide: alert avisa a equipe e template envia um template aprovado.
GET /ai/followups/promises
Escopo agents:read
Query customer_id, status, q (até 100), contact_id, cursor e limit (1–100, padrão 30). Paginação por cursor: a resposta é {data: {data: [...], next_cursor}}.
POST /ai/followups/promises
Escopo agents:write · chave criada por um Administrador
| Campo | Tipo e limites | Uso |
|---|---|---|
contact_id · conversation_id · agent_id | UUID | O agente precisa estar publicado, ativo e responder pelo canal da conversa. |
operation_key | UUID | Repetir devolve o mesmo retorno com 200. |
reason | 1–500 | Por que retornar. |
promise | 1–1.000 | O que foi prometido. |
context_snapshot | até 4.000, opcional | Contexto para o agente. |
promised_at | ISO com fuso | Entre 5 minutos e 180 dias. Ajustado à janela do agente. |
outside_window | alert | template, padrão alert | Fora da janela de 24 horas. |
template_id · template_variables | obrigatório com template | Template aprovado no número da conversa e valores de todas as variáveis. |
{
"customer_id": "11111111-1111-4111-8111-111111111111",
"contact_id": "88888888-8888-4888-8888-888888888888",
"conversation_id": "99999999-9999-4999-8999-999999999999",
"agent_id": "44444444-4444-4444-8444-444444444444",
"operation_key": "66666666-6666-4666-8666-666666666666",
"reason": "Cliente pediu retorno após falar com o sócio",
"promise": "Retomar a proposta da cadeira ergonômica",
"promised_at": "2026-10-02T10:00:00-03:00",
"outside_window": "alert"
}Responde 201 com o retorno (due_at é o horário efetivo). Um contato tem no máximo um retorno pendente: outro retorna 409 already_pending.
GET /ai/followups/promises/{id}
Escopo agents:read
Query customer_id. O retorno com contact, agent, run (turno disparado, com skip_reason) e alert.
POST /ai/followups/promises/{id}/cancel
Escopo agents:write · chave criada por um Administrador
Corpo {customer_id, reason?}. Repetir é idempotente. Retorno já disparado: 409 already_terminal.
POST /ai/followups/promises/{id}/resolve
Escopo agents:write · chave criada por um Administrador
Concilia o template de um retorno com status unknown. Corpo {customer_id, outcome: sent|rejected, note (10–2.000), wamid?}. Mesma regra de papel da conciliação de efeitos: chave criada por Administrador pela API; qualquer membro no painel.
Status de retorno: scheduled, turn_enqueued, template_pending, template_dispatching, alerted, completed, skipped, failed, unknown, cancelled.
Fila
GET /ai/followups/queue
Escopo agents:read
Inscrições e retornos numa lista só. Query customer_id, kind (enrollment ou promise), flow_id, status, q, contact_id, cursor e limit (1–100, padrão 30). Diferente das demais listas de IA, usa cursor, não page/per_page:
{
"data": {
"data": [
{
"kind": "promise",
"id": "13131313-1313-4131-8131-131313131313",
"contact_id": "88888888-8888-4888-8888-888888888888",
"contact_name": "Ana",
"contact_phone": "+5592988887777",
"conversation_id": "99999999-9999-4999-8999-999999999999",
"flow_id": null,
"flow_name": null,
"agent_id": "44444444-4444-4444-8444-444444444444",
"agent_name": "Atendimento",
"status": "scheduled",
"node_id": null,
"next_fire_at": "2026-10-02T13:00:00.000Z",
"reason": "Cliente pediu retorno após falar com o sócio",
"updated_at": "2026-09-25T13:00:00.000Z",
"created_at": "2026-09-25T13:00:00.000Z",
"last_error": null
}
],
"next_cursor": "eyJiIjoxLCJrIjoi..."
}
}Cursor inválido ou antigo: 422 invalid_cursor; recomece sem cursor.
| Status | Código | Quando |
|---|---|---|
| 409 | revision_conflict | Fluxo ou inscrição alterados. |
| 409 | dispatch_busy | Há envio em andamento ou incerto. |
| 409 | already_pending · already_terminal | Retorno duplicado ou já encerrado. |
| 409 | idempotency_conflict | operation_key reutilizada com outros dados. |
| 409 | promise_not_unknown | Conciliação de retorno que não está incerto. |
| 422 | invalid_graph | Grafo inválido; veja validation_errors. |
| 422 | promised_at_in_past · promised_at_out_of_window · no_send_window | Horário do retorno inválido. |
| 422 | agent_unavailable · channel_owner_changed · conversation_closed | Agente ou conversa não podem receber o retorno. |
| 422 | template_required · template_unavailable · invalid_template_values | Template ausente, não aprovado ou incompleto. |
| 422 | incompatible_send_windows | Fluxo e agente sem horário em comum. |
Visão geral do Agente de IA · Próxima: Acompanhamento
