Agentes e versões

Crie o rascunho, teste com o provedor real, publique uma versão imutável e controle quando e como o agente atende.

Ciclo de vida

  1. POST /ai/agents cria o agente e o primeiro rascunho. Ele não atende até ser ativado.
  2. PUT /ai/agents/{id} altera o rascunho, sempre com a revisão lida. Sem rascunho, o PUT cria um a partir do corpo enviado.
  3. POST /ai/agents/{id}/preview testa uma versão sem efeitos.
  4. POST /ai/agents/{id}/publish diagnostica e publica o rascunho. A versão fica imutável e o agente passa a apontar para ela. Publicar incrementa operation_revision mas não ativa o agente.
  5. POST /ai/agents/{id}/operation ativa 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 em expected_revision no PUT e no publish, e em expected_draft_revision no restore.
  • agent.operation_revision: da operação. Vai em expected_revision em operation e archive, e em expected_agent_revision ao 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:

CampoTipo e limitesUso
lifecycledraft | published | active | paused | archivedEtapa do ciclo de vida, abaixo.
servingbooleantrue quando o agente é, agora, quem responde no canal da versão publicada.
serving_viadirect | router | nulldirect: vínculo do próprio agente; router: membro do roteador ativo no canal; null quando não atende.
channel_account_idUUID | nullCanal 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

CampoTipo e limitesUso
customer_idUUIDCliente dono do agente.
namestring 1–80Nome do agente.
descriptionstring até 2.000Opcional.
configobjetoConfiguraçã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

CampoTipo e limitesUso
version_idUUIDRascunho ou versão publicada do agente.
operation_keyUUIDRepetir a chave com os mesmos dados devolve a mesma execução; com outros dados, 409 idempotency_conflict.
messages1–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

CampoTipo e limitesUso
expected_revisionstringoperation_revision atual.
modeautomatic | assistedassisted: resposta e ações aguardam aprovação.
pausedbooleanfalse 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.

StatusCódigoQuando
404not_foundAgente ou versão inexistente neste Cliente.
404channel_not_foundCanal que não pertence ao Cliente ou não está ativo.
409revision_conflictRevisão do rascunho ou da operação desatualizada.
409duplicate_responderCanal já atendido por outro agente ou roteador.
409credential_unavailableCredencial inativa, não validada ou de outro provedor.
409agent_archivedEditar, publicar ou ativar um agente arquivado.
409agent_unavailableAtivar sem versão publicada.
409published_version_immutablePublicar uma versão já publicada.
409idempotency_conflictoperation_key repetida com dados diferentes.
409stage_scope_invalid · knowledge_scope_invalid · skill_scope_invalid · followup_scope_invalidID de etapa, fonte ativa, skill ativa ou fluxo publicado inválido na publicação.
422incomplete_configurationPublicar ou testar sem instruções, modelo, credencial ou canal.
422diagnostic_blockedPublicar com uma verificação do diagnóstico bloqueando. error.blockers lista cada pendência (id, title, status, detail).
422invalidCorpo fora do schema ou ID malformado.
422publish_required · incompatible_send_windowsFollow-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_prompt com ao menos 10 caracteres e model preenchido.
  • credential_id ativa, validada e do mesmo provider. Com operador próprio, a credencial dele também.
  • channel_account_id de um canal WhatsApp do Cliente.
  • allowed_stage_ids, knowledge_source_ids e skill_ids existentes e ativos no Cliente; fluxos de followup.flow_ids publicados, com janela de envio compatível.
  • Ferramentas que só consultam outros contatos (contacts.search, radar.read, crm.search) exigem data_access.other_contacts: true.
  • Chave validada pelo provedor, com o model no 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_live e nenhum número em test_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": ""
  }
}
CampoTipo e limitesUso
system_promptstring até 20.000Instruções. Mínimo de 10 caracteres para publicar.
provideranthropic, openai, google, openrouter, deepseek, xaiProvedor do modelo de atendimento.
modelstring até 200ID do modelo, como listado na credencial.
credential_id · channel_account_idUUID ou nullnull só no rascunho.
tool_idslista sem repetiçãoFerramentas 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_zonefuso IANAPadrão America/Sao_Paulo.
business_hours{start HH:MM, end HH:MM, weekdays 0–6} ou nullstart antes de end; dias sem repetição (0 = domingo).
outside_hoursrespond | wait | handoffFora de business_hours: responde, adia até a próxima abertura ou passa para a equipe.
max_steps1–25Passos de ferramenta por turno.
token_budget1.000–500.000Tokens por turno.
estimated_cost_limit_usdmaior que 0 e até 100, ou nullTeto estimado por execução, em dólares.
history_message_window · history_token_window0–200 · 0–50.000Histórico enviado ao modelo.
handoff_keywordsaté 30 de até 80Frases que transferem para a equipe.
handoff_enabled · cases_enabledbooleanLiberam a ferramenta handoff e as de casos.
split_messages · split_max_charsboolean · 80–4.000Divide respostas longas.
crm_scopescontacts, opportunities, demandsVazio = nenhum acesso ao CRM.
allowed_stage_idsaté 100 UUIDsÚnicas etapas para onde o agente pode mover.
knowledge_source_ids · skill_idsaté 100 UUIDs cadaFontes e skills autorizadas.
platform_skillsnone | allCompõe as skills da plataforma. Veja Skills.
memory_enabledbooleanLê e propõe memória.
data_access.other_contactsbooleanAutoriza 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.
safetyver abaixoCamada 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

CampoTipo e limitesUso
disclose_aibooleanInforma que é uma IA.
disclosure_textstring até 300Texto do aviso.
prohibited_claimsaté 50 de até 300Afirmações que o agente não pode fazer.
additional_rulesaté 30 de até 500Regras extras.
escalation_instructionsstring até 4.000Quando 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_sensitivitystandard | strictSensibilidade do detector de manipulação.
semantic_evaluatorbooleanAvaliaçã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_idO que fazGrupo e riscoExige
contacts.readConsultar o contato atualAtender e responder · Só olhacrm_scopes com contacts
contacts.updateAtualizar o contato atualAtender e responder · Faz mudançascrm_scopes com contacts
conversations.readConsultar a conversa atualAtender e responder · Só olha—
conversations.noteAdicionar nota internaAtender e responder · Faz mudanças—
crm.opportunities.readConsultar oportunidades do contatoVender e mover o funil · Só olhacrm_scopes com opportunities
crm.opportunities.writeAtualizar oportunidades do contatoVender e mover o funil · Faz mudançascrm_scopes com opportunities; mudança de etapa limitada a allowed_stage_ids
crm.demands.readConsultar demandas do contatoVender e mover o funil · Só olhacrm_scopes com demands
crm.demands.writeAtualizar demandas do contatoVender e mover o funil · Faz mudançascrm_scopes com demands; mudança de etapa limitada a allowed_stage_ids
crm.stages.readConsultar etapas permitidasVender e mover o funil · Só olhalista só as etapas de allowed_stage_ids
crm.stages.writeMover etapa do contatoVender e mover o funil · Faz mudançasetapa de destino em allowed_stage_ids
agenda.availabilityConsultar disponibilidadeNão perder o cliente · Só olha—
agenda.proposePropor agendamento (o contato confirma)Não perder o cliente · Faz mudançasconfirmação do contato
agenda.appointments.readConsultar compromissos do contatoNão perder o cliente · Só olha—
agenda.appointments.rescheduleReagendar compromisso do contatoNão perder o cliente · Faz mudanças—
agenda.appointments.cancelCancelar compromisso do contatoNão perder o cliente · Faz mudanças—
knowledge.searchConsultar base de conhecimentoAprender e evoluir · Só olhabusca só em knowledge_source_ids
memory.readConsultar memóriaAprender e evoluir · Só olhamemory_enabled
memory.proposePropor memória para revisãoAprender e evoluir · Faz mudançasmemory_enabled; aprovação humana
skills.readLer habilidadesAprender e evoluir · Só olhalê só skill_ids
followups.enrollInscrever em acompanhamentoNão perder o cliente · Faz mudançasfollowup.enabled e fluxo em followup.flow_ids
followups.pausePausar acompanhamentoNão perder o cliente · Faz mudançasfollowup.enabled
followups.cancelCancelar acompanhamento ou retorno agendadoNão perder o cliente · Faz mudançasfollowup.enabled para inscrições; retornos avulsos não exigem
cases.openAbrir casoPassar para uma pessoa · Faz mudançascases_enabled; abrir com transferência exige handoff_enabled
cases.updateDevolver informação a um casoPassar para uma pessoa · Faz mudançascases_enabled
handoffTransferir para atendentePassar para uma pessoa · Só uma pessoa desfazhandoff_enabled
alerts.createCriar alertaPassar para uma pessoa · Faz mudanças—
followups.scheduleAgendar retorno prometido ao contatoNão perder o cliente · Faz mudanças—
followups.listConsultar retornos e acompanhamentos do contatoNão perder o cliente · Só olha—
contacts.searchBuscar outros contatosAtender e responder · Só olhacrm_scopes com contacts; data_access.other_contacts obrigatório para publicar
contacts.getConsultar um contato pelo IDAtender e responder · Só olhacrm_scopes com contacts; outros contatos só com data_access.other_contacts
contacts.propose_updateSugerir mudança no cadastro (pessoa confirma)Atender e responder · Faz mudançascrm_scopes com contacts; aprovação humana
conversations.listListar conversasAtender e responder · Só olhaoutros contatos só com data_access.other_contacts
conversations.getConsultar uma conversa pelo IDAtender e responder · Só olhaoutros contatos só com data_access.other_contacts
conversations.historyLer histórico de uma conversaAtender e responder · Só olhaoutros contatos só com data_access.other_contacts
conversations.assignAtribuir a conversa atual a uma pessoaPassar para uma pessoa · Faz mudanças—
team.members.readConsultar equipeOrganizar a operação · Só olha—
inbox.queue.readConsultar fila de atendimentoOrganizar a operação · Só olha—
tags.readConsultar marcadores em usoOrganizar a operação · Só olha—
tags.manageAdicionar/remover marcadores do contatoOrganizar a operação · Faz mudanças—
saved_replies.readConsultar respostas rápidasAtender e responder · Só olha—
saved_replies.renderPreencher resposta rápidaAtender e responder · Só olha—
automations.readConsultar réguas de automaçãoOrganizar a operação · Só olha—
automations.runs.readConsultar execuções de réguasOrganizar a operação · Só olhaoutros contatos só com data_access.other_contacts
radar.readConsultar Radar (itens em risco)Não perder o cliente · Só olhadata_access.other_contacts obrigatório para publicar
radar.propose_reactivationPropor retomada de contato (pessoa aprova)Não perder o cliente · Faz mudançasaprovação humana
catalog.products.searchBuscar produtos do catálogo importadoVender e mover o funil · Só olha—
privacy.consent.readConsultar consentimento do contatoAtender e responder · Só olha—
knowledge.sources.readConsultar fontes e prontidãoAprender e evoluir · Só olha—
proposals.readConsultar propostas de melhoriaAprender e evoluir · Só olha—
cases.readConsultar casosPassar para uma pessoa · Só olhacases_enabled; outros contatos só com data_access.other_contacts
crm.searchBuscar oportunidades/demandas do ClienteVender e mover o funil · Só olhadata_access.other_contacts obrigatório para publicar
agenda.schedule.readConsultar agenda por dia/profissionalNão perder o cliente · Só olha—
agenda.appointments.confirmRegistrar presença confirmada pelo contatoNão perder o cliente · Faz mudanças—
cases.noteAnotar no caso aberto da conversaPassar para uma pessoa · Faz mudançascases_enabled
cases.closeEncerrar o caso aberto da conversaPassar para uma pessoa · Faz mudançascases_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