Tokens de acesso#
POSTLogin (obter JWT)#
POST /v1/auth/login — corpo { email, password }. Resposta 200: emite os
cookies de refresh/CSRF e o corpo
{ token, company_id, user_id, role, email, name, is_superadmin, email_verified }.
POST /v1/auth/refresh (cookie de refresh) renova; POST /v1/auth/logout
encerra (204). Erros: INVALID_CREDENTIALS (401), ACCOUNT_LOCKED (429).
POSTCriar API key#
POST /v1/tokens (owner + email verificado) — corpo
{ label, role?, allowed_source_ips? } (role default agent;
allowed_source_ips CSV de IPv4/CIDR/IPv6). Resposta 201:
{ token_id, token, label, role, last4, allowed_source_ips, created_at } — o
token (ctc_…) é mostrado uma única vez. GET /v1/tokens lista (array puro de
{ id, label, last4, role, created_at }); DELETE /v1/tokens/{tokenId} revoga
(200 { message, token_id }).
POSTCriar runtime token#
POST /v1/agents/{id}/runtime-tokens (owner) — corpo { label? }. Resposta 201:
{ id, agent_id, label, token, created_at } — o token (prt_…) é mostrado uma
vez. GET .../runtime-tokens lista { tokens, total };
DELETE .../runtime-tokens/{tokenId} revoga (204).
POSTRuntime token por tenant#
Quando os agentes de um cliente final são criados dinamicamente (um painel, uma automação), um token preso a UM agente não serve: o app deployado tem env estática e não pode receber credencial nova a cada agente criado. Peça um token tenant-scoped, que alcança todos-e-somente os agentes daquele tenant:
curl -X POST https://agents-api.catcher.one/v1/compat/runtime-tokens \
-H "Authorization: Bearer $CTC_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"label":"app-acme-prod","tenant_external_id":"acme:prod"}'
{"data":{"id":"…","label":"app-acme-prod","scope":"tenant","tenant_id":42,
"agent_id":"","token":"prt_…","created_at":"2026-07-20T12:00:00Z"}}
O token aparece uma única vez. Confira o scope da resposta, não só o
201: um corpo sem tenant_external_id gera um token company (alcança todos os
agentes da conta). Regras do mint:
agent_idetenant_external_idjuntos →400 RUNTIME_TOKEN_SCOPE_CONFLICT.tenant_external_iddesconhecido →404 TENANT_NOT_FOUND. O mint nunca cria o tenant — crie primeiro (o upsert de agente aceitatenant_external_id), para que um typo falhe alto em vez de emitir credencial sobre um tenant vazio.- Exige uma key de papel
ownerouadmin.
GETConferir um runtime token#
GET /v1/compat/runtime-tokens/{tokenId} responde "a credencial que meu app guarda
ainda está viva?" sem gastar um run:
{"data":{"id":"…","label":"app-acme-prod","scope":"tenant","tenant_id":42,
"agent_id":"","revoked":false,
"created_at":"2026-07-20T12:00:00Z","last_used_at":"2026-07-20T13:31:02Z"}}
A chave é o id devolvido no mint, nunca o valor prt_ — um verify por segredo
colocaria uma credencial viva numa URL que é logada e cacheada no caminho. O segredo
nunca é devolvido. GET /v1/compat/runtime-tokens lista todos (com scope e
tenant_id); DELETE /v1/compat/runtime-tokens/{tokenId} revoga.