Convenções

É um agente de IA? Busque a skill de onboarding e leia toda a API em texto limpo — skill · llms.txt · llms-full.txt

Convenções#

  • Autenticação por Authorization: Bearer (JWT / ctc_) ou X-API-Key (ctc_), ou X-Agent-Token (prt_) no runtime.

  • Idempotency-Key é aceito como header (CORS), mas não há dedupe server-side nesta versão — trate como reservado, não confie nele para idempotência.

  • Listas: a maioria envelopa em { <items>, total }; exceçõesGET /v1/tokens e GET /v1/tenants retornam um array JSON puro.

  • Status: criação de recurso costuma ser 201; ingestão assíncrona (/sources, reindex, refine) é 202; deleções são 204exceto DELETE /v1/tokens/{id} que responde 200 com corpo.

  • Um 401 pode significar "tipo errado de credencial", não "credencial inválida". Algumas rotas são autenticadas por capability, e uma API key válida da sua company simplesmente não é credencial ali:

    Rota Credencial correta
    GET /v1/projects JWT (é escopo de pessoa; API key é escopo de company)
    GET /v1/compat/streams/{id} · POST …/stop o stream_token daquele stream
    POST /v1/agent-runtime/{id}/sessions X-Agent-Token: prt_…

    Se você recebeu 401 numa dessas com uma chave que funciona em outros lugares, troque o tipo de credencial, não a chave.

  • POST /v1/auth/logout revoga o access token no servidor, não só limpa cookies — o bearer usado na chamada para de autenticar imediatamente. Cliente header-only não deve chamar logout e continuar usando o mesmo token. POST /v1/auth/logout-all revoga os refresh tokens, mas não as API keys: "sair de todos os dispositivos" nunca desloga uma integração.

  • /v1/agents tem duas formas de resposta, escolhidas pelo header de auth: X-API-Key devolve JSON plano ({"id":…}); Authorization: Bearer ctc_… devolve o envelope compat ({"data":{"id":…,"slug":…}}) — e nesse caminho o create é idempotente por slug: re-POSTar o mesmo slug adota e atualiza o agente existente, devolvendo 200 (não 201, e sem duplicar).

  • Revogação não é uniforme entre os dois tipos de token. Um token de API revogado some de GET /v1/tokens (a lista não tem campo revoked_at — o que está listado está vivo). Já um runtime token (prt_) é soft delete: continua listado com "revoked": true.

  • Nas rotas compat, PATCH é upsert COMPLETO, não patch parcial — mesmo handler do POST. Mandar só o campo alterado em …/integrations/{id}/secrets/{sid} ou …/tools/{tid} devolve 400 MISSING_FIELD. POST …/tools/sync exige o array tools.

  • Id inexistente nem sempre é 404: GET …/runs/{runId}/tool-calls devolve 200 com coleção vazia e GET …/transcripts/{id}/llm-prompts devolve 200 com um aviso (snapshots de prompt por turno não são retidos — use GET /v1/agents/{id}/prompt-preview). As rotas irmãs devolvem 404. Não trate 200 como "existe" nessas duas.

  • Timestamps em RFC3339 (UTC). Datas de bucket em YYYY-MM-DD.

  • Custo do turno não vem no corpo de POST …/messages — leia via GET /v1/agents/{id}/runs/{runId} (ou o evento done do stream).

GETEnvelope de erro#

Todo 4xx/5xx usa o mesmo envelope, com um trace_id que casa com o header X-Trace-ID e a linha de log correspondente:

json
{
  "error_code": "AGENT_INACTIVE",
  "message": "agent is paused",
  "trace_id": "2a62142c-f55f-4db4-8c7b-060018e3ef48",
  "error": "agent is paused"
}

error é um alias legado de message. Erros de validação podem trazer field_errors: [{ field, message }]. Respostas capturadas ganham também um header X-Incident-Id.

Falha de dependência responde 503, não 502 — e 503 é para repetir. Quando uma dependência nossa (o backend de conhecimento, por exemplo) está fora, a resposta é 503 com um error_code estável: o seu pedido estava correto, então a ação certa é repetir depois, não alterar a requisição.

Isso é uma garantia sobre o que você consegue LER na falha. Um 502 vindo da origem é substituído no edge pela página HTML de erro da Cloudflare, e com ela vão embora error_code, trace_id e incident_id — você recebe markup em vez do envelope e fica sem como diagnosticar. O 503 atravessa o edge intacto. Por isso, se você receber HTML onde esperava JSON, não trate como erro da sua chamada: é uma falha de gateway, e o corpo não é nosso.