Ciclo de vida
POST /ai/agentscria o agente e o primeiro rascunho. Ele não atende até ser ativado.PUT /ai/agents/{id}altera o rascunho, sempre com a revisão lida. Sem rascunho, o PUT cria um a partir do corpo enviado.POST /ai/agents/{id}/previewtesta uma versão sem efeitos.POST /ai/agents/{id}/publishdiagnostica e publica o rascunho. A versão fica imutável e o agente passa a apontar para ela. Publicar incrementaoperation_revisionmas não ativa o agente.POST /ai/agents/{id}/operationativa ou pausa e escolhe o modo. Antes, libere o canal em Acesso e elegibilidade.
Há duas revisões diferentes, ambas strings decimais:
versions[].revision: do rascunho. Vai emexpected_revisionno PUT e no publish, e emexpected_draft_revisionno restore.agent.operation_revision: da operação. Vai emexpected_revisionem operation e archive, e emexpected_agent_revisionao ativar um membro de roteador.
Estado e atendimento
GET /ai/agents e GET /ai/agents/{id} trazem, em cada agente, o estado real além de paused e archived. Use serving para saber se o agente está respondendo:
| Campo | Tipo e limites | Uso |
|---|---|---|
lifecycle | draft | published | active | paused | archived | Etapa do ciclo de vida, abaixo. |
serving | boolean | true quando o agente é, agora, quem responde no canal da versão publicada. |
serving_via | direct | router | null | direct: vínculo do próprio agente; router: membro do roteador ativo no canal; null quando não atende. |
channel_account_id | UUID | null | Canal da versão publicada; null sem versão publicada. |
Valores de lifecycle:
draft: Nenhuma versão publicada. Não atende.published: Versão publicada, operação ainda não ativada. Não atende.active: Operação ativada. Atende se serving for true.paused: Tem versão publicada, mas a operação está pausada. Não atende.archived: Histórico preservado. Não atende.
serving só é true com lifecycle: active, credencial ativa e validada do provedor da versão, canal não revogado e fora do sandbox, e posse do canal: o vínculo do agente quando não há roteador ativo, ou a participação no roteador ativo do canal. Um agente active pode ter serving: false, por exemplo com a credencial desativada ou com um roteador ativo do qual não participa. No modo assisted, as respostas aguardam aprovação. serving não considera os contatos liberados: quem recebe resposta ainda depende da elegibilidade do canal.
Rotas
GET /ai/agents
Escopo agents:read
Query customer_id, page, per_page. Lista paginada de agentes, ordenada por nome, cada um no formato de agent abaixo, com lifecycle e serving.
POST /ai/agents
Escopo agents:write
| Campo | Tipo e limites | Uso |
|---|---|---|
customer_id | UUID | Cliente dono do agente. |
name | string 1–80 | Nome do agente. |
description | string até 2.000 | Opcional. |
config | objeto | Configuração da versão. Omitida, usa todos os padrões abaixo. |
Este exemplo é validado em teste contra o schema da rota:
{
"customer_id": "11111111-1111-4111-8111-111111111111",
"name": "Atendimento",
"description": "Atendimento e acompanhamento da equipe",
"config": {
"system_prompt": "Atenda usando os materiais autorizados e encaminhe à equipe quando precisar de uma decisão humana.",
"provider": "openai",
"model": "MODELO_VALIDADO_NA_CREDENCIAL",
"credential_id": "22222222-2222-4222-8222-222222222222",
"channel_account_id": "33333333-3333-4333-8333-333333333333",
"tool_ids": [
"conversations.read",
"conversations.note",
"knowledge.search",
"cases.open",
"handoff"
],
"knowledge_source_ids": [
"77777777-7777-4777-8777-777777777777"
],
"skill_ids": [],
"cases_enabled": true,
"handoff_enabled": true
}
}Responde 201 com {agent_id, version_id, revision}.
GET /ai/agents/{id}
Escopo agents:read
Query customer_id. Retorna o agente e todas as versões, cada uma com o config completo.
{
"agent": {
"id": "44444444-4444-4444-8444-444444444444",
"customer_id": "11111111-1111-4111-8111-111111111111",
"name": "Atendimento",
"description": "Atendimento e acompanhamento da equipe",
"operation_mode": "automatic",
"operation_revision": "4",
"paused": false,
"archived": false,
"published_version_id": "55555555-5555-4555-8555-555555555555",
"updated_at": "2026-09-25T13:00:00.000Z",
"lifecycle": "active",
"serving": true,
"serving_via": "direct",
"channel_account_id": "33333333-3333-4333-8333-333333333333"
},
"versions": [
{
"id": "55555555-5555-4555-8555-555555555555",
"agent_id": "44444444-4444-4444-8444-444444444444",
"number": 2,
"revision": "3",
"status": "published",
"config": "{ ... }",
"created_at": "2026-09-24T18:00:00.000Z",
"published_at": "2026-09-25T12:58:00.000Z",
"created_by": null
}
]
}PUT /ai/agents/{id}
Escopo agents:write
Mesmo corpo da criação mais expected_revision. Com rascunho existente, a revisão é obrigatória e precisa ser a atual. Sem rascunho, omita-a: um novo rascunho é criado. Retorna {agent_id, version_id, revision}. O config enviado substitui o anterior inteiro; campos omitidos voltam ao padrão.
POST /ai/agents/{id}/preview
Escopo agents:write
| Campo | Tipo e limites | Uso |
|---|---|---|
version_id | UUID | Rascunho ou versão publicada do agente. |
operation_key | UUID | Repetir a chave com os mesmos dados devolve a mesma execução; com outros dados, 409 idempotency_conflict. |
messages | 1–200 itens {role: user|assistant, content ≤20.000} | A última mensagem precisa ser do usuário. |
{
"customer_id": "11111111-1111-4111-8111-111111111111",
"version_id": "55555555-5555-4555-8555-555555555555",
"operation_key": "66666666-6666-4666-8666-666666666666",
"messages": [
{
"role": "user",
"content": "Qual o prazo de entrega para Manaus?"
}
]
}Retorna uma execução, no mesmo formato de Execuções. Usa o provedor real e consome a sua chave. Só conhecimento, memória e skills são consultados de verdade; as demais ferramentas, inclusive leituras, devolvem uma simulação. Nada é enviado ao contato. Com o operador ligado, operator_execution traz a revisão dele.
POST /ai/agents/{id}/publish
Escopo agents:write
{
"customer_id": "11111111-1111-4111-8111-111111111111",
"version_id": "55555555-5555-4555-8555-555555555555",
"expected_revision": "3"
}Retorna {version_id, number}. Antes de publicar, o servidor roda no rascunho o mesmo diagnóstico do painel. Se alguma verificação bloquear, a publicação é recusada com 422 diagnostic_blocked e error.blockers, a lista de pendências. Veja os requisitos de publicação.
{
"error": {
"code": "diagnostic_blocked",
"message": "O diagnóstico do rascunho tem verificações que impedem a publicação. Resolva as pendências e publique de novo. Pendências: Elegibilidade para atender.",
"blockers": [
{
"id": "eligibility",
"title": "Elegibilidade para atender",
"status": "blocked",
"detail": "Somente números de teste, e nenhum número de teste foi cadastrado em Loja Centro: a IA não responde a ninguém. Cadastre um número de teste ou abra o canal em Acesso da IA."
}
]
}
}POST /ai/agents/{id}/restore
Escopo agents:write
Corpo {customer_id, version_id, expected_draft_revision?}. Copia o config de uma versão para o rascunho. Se já existir rascunho, informe a revisão dele. Não publica nem ativa.
POST /ai/agents/{id}/duplicate
Escopo agents:write
Corpo {customer_id, name}. Cria outro agente com o rascunho (ou a versão publicada) copiado, sem canal e inativo. Retorna {agent_id, version_id, revision}.
POST /ai/agents/{id}/archive
Escopo agents:write
Corpo {customer_id, expected_revision, archived}, com operation_revision. Arquivar pausa o agente, libera o canal e preserva o histórico. Desarquivar não reativa. Retorna {id, revision, archived}.
POST /ai/agents/{id}/operation
Escopo agents:write
| Campo | Tipo e limites | Uso |
|---|---|---|
expected_revision | string | operation_revision atual. |
mode | automatic | assisted | assisted: resposta e ações aguardam aprovação. |
paused | boolean | false ativa; true pausa. |
{
"customer_id": "11111111-1111-4111-8111-111111111111",
"expected_revision": "2",
"mode": "assisted",
"paused": false
}Retorna {revision, paused, mode}. Ativar exige versão publicada, credencial ativa e válida e canal livre: outro agente vinculado ou roteador ativo no canal retorna 409 duplicate_responder. Ativar vincula o agente ao canal da versão publicada. Pausar mantém o vínculo; arquivar o libera.
O campo paused sozinho não diz se o agente atende: um agente recém-criado ou só publicado tem paused: false e ainda não foi ativado. Leia lifecycle e serving em GET /ai/agents.
GET /ai/agents/{id}/capability-usage
Escopo agents:read
Query customer_id e days (1–90, padrão 30). Compara o uso real de cada ferramenta com a versão publicada (ou o rascunho, se nada foi publicado): agent e operator com summary e items (tool, enabled, signal, recommendation, total, failures, unknown, test, last_at). Falha de leitura é 503, nunca zero.
| Status | Código | Quando |
|---|---|---|
| 404 | not_found | Agente ou versão inexistente neste Cliente. |
| 404 | channel_not_found | Canal que não pertence ao Cliente ou não está ativo. |
| 409 | revision_conflict | Revisão do rascunho ou da operação desatualizada. |
| 409 | duplicate_responder | Canal já atendido por outro agente ou roteador. |
| 409 | credential_unavailable | Credencial inativa, não validada ou de outro provedor. |
| 409 | agent_archived | Editar, publicar ou ativar um agente arquivado. |
| 409 | agent_unavailable | Ativar sem versão publicada. |
| 409 | published_version_immutable | Publicar uma versão já publicada. |
| 409 | idempotency_conflict | operation_key repetida com dados diferentes. |
| 409 | stage_scope_invalid · knowledge_scope_invalid · skill_scope_invalid · followup_scope_invalid | ID de etapa, fonte ativa, skill ativa ou fluxo publicado inválido na publicação. |
| 422 | incomplete_configuration | Publicar ou testar sem instruções, modelo, credencial ou canal. |
| 422 | diagnostic_blocked | Publicar com uma verificação do diagnóstico bloqueando. error.blockers lista cada pendência (id, title, status, detail). |
| 422 | invalid | Corpo fora do schema ou ID malformado. |
| 422 | publish_required · incompatible_send_windows | Follow-up ligado com fluxo não publicado ou sem horário em comum. |
Requisitos de publicação
A publicação pelo painel e pela API segue a mesma regra: o rascunho é diagnosticado no servidor e qualquer verificação bloqueante recusa a publicação com diagnostic_blocked. Uma verificação que não pôde ser lida também bloqueia; ela nunca conta como aprovada. A prova de geração é opcional e não bloqueia. Bloqueiam:
system_promptcom ao menos 10 caracteres emodelpreenchido.credential_idativa, validada e do mesmoprovider. Com operador próprio, a credencial dele também.channel_account_idde um canal WhatsApp do Cliente.allowed_stage_ids,knowledge_source_idseskill_idsexistentes e ativos no Cliente; fluxos defollowup.flow_idspublicados, com janela de envio compatível.- Ferramentas que só consultam outros contatos (
contacts.search,radar.read,crm.search) exigemdata_access.other_contacts: true. - Chave validada pelo provedor, com o
modelno catálogo dela e compatível com atendimento. Com operador próprio, a credencial e o modelo dele também. - Canal WhatsApp ativo, do Cliente e fora do sandbox.
- Canal elegível: conta fora de exclusão e canal que aceita IA. Com o canal em
pre_go_livee nenhum número emtest_phone_numbers, a IA não responderia a ninguém, então a publicação é recusada. Cadastre um número de teste ou mude o modo em Acesso e elegibilidade.
Avisos não bloqueiam: outro agente ou roteador ativo no canal, ferramentas sem efeito, regras da empresa ausentes e proteções desligadas.
Schema do config
O schema é estrito: chave desconhecida gera 422. Todo campo tem padrão. Estes são os valores aplicados a um config vazio:
{
"system_prompt": "",
"provider": "openai",
"model": "",
"credential_id": null,
"channel_account_id": null,
"tool_ids": [],
"operator": {
"enabled": false,
"provider": null,
"model": null,
"credential_id": null,
"tool_ids": []
},
"trigger": {
"keywords": [],
"match": "any",
"ignore_groups": true,
"ignore_self": true
},
"time_zone": "America/Sao_Paulo",
"business_hours": null,
"outside_hours": "respond",
"max_steps": 10,
"token_budget": 50000,
"estimated_cost_limit_usd": null,
"history_message_window": 20,
"history_token_window": 8000,
"handoff_keywords": [
"falar com humano",
"atendente",
"pessoa real"
],
"handoff_enabled": true,
"cases_enabled": true,
"split_messages": false,
"split_max_chars": 600,
"crm_scopes": [],
"allowed_stage_ids": [],
"knowledge_source_ids": [],
"skill_ids": [],
"platform_skills": "none",
"memory_enabled": true,
"data_access": {
"other_contacts": false
},
"accountability": {
"enabled": false,
"classification": false
},
"media": {
"images_enabled": true,
"documents_enabled": true,
"video_frames_enabled": false
},
"followup": {
"enabled": false,
"flow_ids": [],
"send_window": null
},
"safety": {
"disclose_ai": true,
"prohibited_claims": [],
"escalation_instructions": "",
"additional_rules": [],
"disclosure_text": "",
"commercial_limits": {
"min_price_brl": null,
"max_discount_percent": null,
"max_installments": null
},
"guard_sensitivity": "standard",
"semantic_evaluator": false
},
"style": {
"tone": "friendly",
"verbosity": "balanced",
"use_emojis": false,
"instructions": ""
}
}| Campo | Tipo e limites | Uso |
|---|---|---|
system_prompt | string até 20.000 | Instruções. Mínimo de 10 caracteres para publicar. |
provider | anthropic, openai, google, openrouter, deepseek, xai | Provedor do modelo de atendimento. |
model | string até 200 | ID do modelo, como listado na credencial. |
credential_id · channel_account_id | UUID ou null | null só no rascunho. |
tool_ids | lista sem repetição | Ferramentas do agente. Veja o catálogo. |
operator | {enabled, provider, model, credential_id, tool_ids} | Operador revisa o turno com ferramentas próprias. provider, model e credential_id vão juntos ou todos null (herda do agente). |
trigger | {keywords ≤40 de até 80, match: any|all, ignore_groups: true, ignore_self: true} | Sem palavras-chave, responde a toda mensagem elegível. |
time_zone | fuso IANA | Padrão America/Sao_Paulo. |
business_hours | {start HH:MM, end HH:MM, weekdays 0–6} ou null | start antes de end; dias sem repetição (0 = domingo). |
outside_hours | respond | wait | handoff | Fora de business_hours: responde, adia até a próxima abertura ou passa para a equipe. |
max_steps | 1–25 | Passos de ferramenta por turno. |
token_budget | 1.000–500.000 | Tokens por turno. |
estimated_cost_limit_usd | maior que 0 e até 100, ou null | Teto estimado por execução, em dólares. |
history_message_window · history_token_window | 0–200 · 0–50.000 | Histórico enviado ao modelo. |
handoff_keywords | até 30 de até 80 | Frases que transferem para a equipe. |
handoff_enabled · cases_enabled | boolean | Liberam a ferramenta handoff e as de casos. |
split_messages · split_max_chars | boolean · 80–4.000 | Divide respostas longas. |
crm_scopes | contacts, opportunities, demands | Vazio = nenhum acesso ao CRM. |
allowed_stage_ids | até 100 UUIDs | Únicas etapas para onde o agente pode mover. |
knowledge_source_ids · skill_ids | até 100 UUIDs cada | Fontes e skills autorizadas. |
platform_skills | none | all | Compõe as skills da plataforma. Veja Skills. |
memory_enabled | boolean | Lê e propõe memória. |
data_access.other_contacts | boolean | Autoriza ler outros contatos e conversas. |
accountability | {enabled, classification} | Fechamento do turno com promessas e sugestão de etapa. Gera uma inferência adicional por turno. |
media | {images_enabled, documents_enabled, video_frames_enabled} | Mídias que o agente interpreta. |
followup | {enabled, flow_ids ≤100, send_window ou null} | Com enabled, ao menos um fluxo. |
safety | ver abaixo | Camada do Cliente acima da política obrigatória da plataforma. |
style | {tone, verbosity, use_emojis, instructions ≤4.000} | tone: professional, friendly, direct. verbosity: concise, balanced, detailed. |
safety
| Campo | Tipo e limites | Uso |
|---|---|---|
disclose_ai | boolean | Informa que é uma IA. |
disclosure_text | string até 300 | Texto do aviso. |
prohibited_claims | até 50 de até 300 | Afirmações que o agente não pode fazer. |
additional_rules | até 30 de até 500 | Regras extras. |
escalation_instructions | string até 4.000 | Quando e como escalar. |
commercial_limits | {min_price_brl, max_discount_percent 0–100, max_installments 1–120} | Tetos conferidos antes do envio; null = sem tabela. |
guard_sensitivity | standard | strict | Sensibilidade do detector de manipulação. |
semantic_evaluator | boolean | Avaliação adicional antes do envio. |
Catálogo de ferramentas
55 valores aceitos em tool_ids e operator.tool_ids. A lista vem do código. O servidor aplica as exigências a cada chamada; uma ferramenta fora delas é recusada no turno, sem efeito.
| tool_id | O que faz | Grupo e risco | Exige |
|---|---|---|---|
contacts.read | Consultar o contato atual | Atender e responder · Só olha | crm_scopes com contacts |
contacts.update | Atualizar o contato atual | Atender e responder · Faz mudanças | crm_scopes com contacts |
conversations.read | Consultar a conversa atual | Atender e responder · Só olha | — |
conversations.note | Adicionar nota interna | Atender e responder · Faz mudanças | — |
crm.opportunities.read | Consultar oportunidades do contato | Vender e mover o funil · Só olha | crm_scopes com opportunities |
crm.opportunities.write | Atualizar oportunidades do contato | Vender e mover o funil · Faz mudanças | crm_scopes com opportunities; mudança de etapa limitada a allowed_stage_ids |
crm.demands.read | Consultar demandas do contato | Vender e mover o funil · Só olha | crm_scopes com demands |
crm.demands.write | Atualizar demandas do contato | Vender e mover o funil · Faz mudanças | crm_scopes com demands; mudança de etapa limitada a allowed_stage_ids |
crm.stages.read | Consultar etapas permitidas | Vender e mover o funil · Só olha | lista só as etapas de allowed_stage_ids |
crm.stages.write | Mover etapa do contato | Vender e mover o funil · Faz mudanças | etapa de destino em allowed_stage_ids |
agenda.availability | Consultar disponibilidade | Não perder o cliente · Só olha | — |
agenda.propose | Propor agendamento (o contato confirma) | Não perder o cliente · Faz mudanças | confirmação do contato |
agenda.appointments.read | Consultar compromissos do contato | Não perder o cliente · Só olha | — |
agenda.appointments.reschedule | Reagendar compromisso do contato | Não perder o cliente · Faz mudanças | — |
agenda.appointments.cancel | Cancelar compromisso do contato | Não perder o cliente · Faz mudanças | — |
knowledge.search | Consultar base de conhecimento | Aprender e evoluir · Só olha | busca só em knowledge_source_ids |
memory.read | Consultar memória | Aprender e evoluir · Só olha | memory_enabled |
memory.propose | Propor memória para revisão | Aprender e evoluir · Faz mudanças | memory_enabled; aprovação humana |
skills.read | Ler habilidades | Aprender e evoluir · Só olha | lê só skill_ids |
followups.enroll | Inscrever em acompanhamento | Não perder o cliente · Faz mudanças | followup.enabled e fluxo em followup.flow_ids |
followups.pause | Pausar acompanhamento | Não perder o cliente · Faz mudanças | followup.enabled |
followups.cancel | Cancelar acompanhamento ou retorno agendado | Não perder o cliente · Faz mudanças | followup.enabled para inscrições; retornos avulsos não exigem |
cases.open | Abrir caso | Passar para uma pessoa · Faz mudanças | cases_enabled; abrir com transferência exige handoff_enabled |
cases.update | Devolver informação a um caso | Passar para uma pessoa · Faz mudanças | cases_enabled |
handoff | Transferir para atendente | Passar para uma pessoa · Só uma pessoa desfaz | handoff_enabled |
alerts.create | Criar alerta | Passar para uma pessoa · Faz mudanças | — |
followups.schedule | Agendar retorno prometido ao contato | Não perder o cliente · Faz mudanças | — |
followups.list | Consultar retornos e acompanhamentos do contato | Não perder o cliente · Só olha | — |
contacts.search | Buscar outros contatos | Atender e responder · Só olha | crm_scopes com contacts; data_access.other_contacts obrigatório para publicar |
contacts.get | Consultar um contato pelo ID | Atender e responder · Só olha | crm_scopes com contacts; outros contatos só com data_access.other_contacts |
contacts.propose_update | Sugerir mudança no cadastro (pessoa confirma) | Atender e responder · Faz mudanças | crm_scopes com contacts; aprovação humana |
conversations.list | Listar conversas | Atender e responder · Só olha | outros contatos só com data_access.other_contacts |
conversations.get | Consultar uma conversa pelo ID | Atender e responder · Só olha | outros contatos só com data_access.other_contacts |
conversations.history | Ler histórico de uma conversa | Atender e responder · Só olha | outros contatos só com data_access.other_contacts |
conversations.assign | Atribuir a conversa atual a uma pessoa | Passar para uma pessoa · Faz mudanças | — |
team.members.read | Consultar equipe | Organizar a operação · Só olha | — |
inbox.queue.read | Consultar fila de atendimento | Organizar a operação · Só olha | — |
tags.read | Consultar marcadores em uso | Organizar a operação · Só olha | — |
tags.manage | Adicionar/remover marcadores do contato | Organizar a operação · Faz mudanças | — |
saved_replies.read | Consultar respostas rápidas | Atender e responder · Só olha | — |
saved_replies.render | Preencher resposta rápida | Atender e responder · Só olha | — |
automations.read | Consultar réguas de automação | Organizar a operação · Só olha | — |
automations.runs.read | Consultar execuções de réguas | Organizar a operação · Só olha | outros contatos só com data_access.other_contacts |
radar.read | Consultar Radar (itens em risco) | Não perder o cliente · Só olha | data_access.other_contacts obrigatório para publicar |
radar.propose_reactivation | Propor retomada de contato (pessoa aprova) | Não perder o cliente · Faz mudanças | aprovação humana |
catalog.products.search | Buscar produtos do catálogo importado | Vender e mover o funil · Só olha | — |
privacy.consent.read | Consultar consentimento do contato | Atender e responder · Só olha | — |
knowledge.sources.read | Consultar fontes e prontidão | Aprender e evoluir · Só olha | — |
proposals.read | Consultar propostas de melhoria | Aprender e evoluir · Só olha | — |
cases.read | Consultar casos | Passar para uma pessoa · Só olha | cases_enabled; outros contatos só com data_access.other_contacts |
crm.search | Buscar oportunidades/demandas do Cliente | Vender e mover o funil · Só olha | data_access.other_contacts obrigatório para publicar |
agenda.schedule.read | Consultar agenda por dia/profissional | Não perder o cliente · Só olha | — |
agenda.appointments.confirm | Registrar presença confirmada pelo contato | Não perder o cliente · Faz mudanças | — |
cases.note | Anotar no caso aberto da conversa | Passar para uma pessoa · Faz mudanças | cases_enabled |
cases.close | Encerrar o caso aberto da conversa | Passar para uma pessoa · Faz mudanças | cases_enabled |
agenda.propose só conclui quando o contato responde com CONFIRMAR XXXXXXXX, usando o código devolvido pela Agenda; o agente não confirma por conta própria. handoff tira a IA da conversa até uma pessoa devolver pelo painel ou por POST /conversations/{id}/agent-control. Enquanto ninguém assume, a conversa aparece na caixa Atendimento humano da Inbox.
Visão geral do Agente de IA · Próxima: Acesso e elegibilidade
