Agendo · Documentação

Agent API & MCP

Leitura + Escrita (F1a) · no arMCP disponívelv1

Introdução

A Agendo Agent API é uma API HTTP para uma IA ou dev consultar partes do Agendo (times, funis, leads, pixels) — e agora também criar/editar rascunhos de funil com escrita controlada — usando um token escopado, sem navegador e sem cookie de sessão.

Há dois jeitos de consumir: HTTP direto (POST nas tools da Agent API) ou MCP (servidor remoto que seu agente de IA conecta). Os dois usam o mesmo token e as mesmas tools: 8 de leitura + 2 de escrita (funis — funnels:write, com dry-run + confirmação).

Autenticação

Toda chamada usa um Personal Access Token (PAT) escopado, no header. O token cru aparece UMA vez (na geração); o servidor guarda só o hash.

Authorization: Bearer cal_agent_...

Sem token, ou token inválido/expirado/revogado → 401 unauthorized.

Gerar PAT

O PAT é gerado dentro do app (com escopo e times definidos por você). Ao gerar, você escolhe:

  • Scopes — leitura (ex.: agent:read, leads:read) e/ou escrita de funil (funnels:write, com dry-run + confirmação).
  • Times (allowedTeamIds) — quais times o PAT enxerga.
  • Validade — expira por padrão; pode ser revogado a qualquer momento.

Guarde o token com cuidado — ele dá acesso de leitura ao escopo concedido. Em caso de vazamento, revogue e gere outro.

Conectar MCP

Para usar via agente de IA, adicione o servidor MCP remoto e autentique com o PAT. Passo a passo completo na página de mcp.useagendo.com.

# Claude Code
claude mcp add --transport http agendo \
  https://mcp.useagendo.com/mcp \
  --header "Authorization: Bearer cal_agent_..."

Primeiro teste (get_me)

Confirme que o token funciona pedindo a própria identidade:

curl -s -X POST "https://api.useagendo.com/agent/v1/getMe" \
  -H "Authorization: Bearer cal_agent_..." \
  -H "Content-Type: application/json" -d '{}'

Resposta de exemplo (valores fictícios):

{
  "ok": true,
  "tool": "getMe",
  "mode": "read",
  "data": {
    "userId": 42,
    "name": "Você",
    "email": "voce@exemplo.com",
    "username": "voce",
    "locale": "pt-BR",
    "timeZone": "America/Sao_Paulo",
    "allowedTeamIds": [12],
    "scopes": ["agent:read", "leads:read"]
  }
}

Base URL

Base recomendada:

https://api.useagendo.com/agent/v1

Compatibilidade (rota original, segue funcionando):

https://app.useagendo.com/api/agent/v1

Status público: GET https://api.useagendo.com/ {"name":"Agendo Agent API","status":"ok","version":"v1"}

Autenticação (Agent API)

Todas as tools são POST em {base}/{tool} com o header Authorization e corpo JSON. Resposta sempre JSON.

// sucesso
{ "ok": true, "tool": "...", "mode": "read", "data": { ... } }

// erro
{ "ok": false, "tool": "...", "error": { "code": "...", "message": "...", "retryable": false } }

Scopes

ScopeTools
agent:readBase — exigido por toda tool de leitura (get_me, list_teams).
funnels:readlist_funnels, get_funnel.
pixels:readlist_pixels, get_pixel_health.
leads:readlist_leads, get_lead.
funnels:writeESCRITA (F1a) — create_funnel_draft, update_funnel_draft. Exige dryRun + confirmationToken.

Além do scope, o PAT só enxerga os times do seu allowedTeamIds (2ª camada, independente do acesso do usuário).

Erros

codeHTTPQuando
unauthorized401PAT ausente, inválido, expirado ou revogado.
forbidden_scope403Falta um scope exigido pela tool (ex.: write sem funnels:write).
forbidden_team403teamId fora do allowedTeamIds do PAT.
not_found404Recurso inexistente OU sem acesso (anti-enumeração).
validation_error400Input inválido (ex.: get_funnel sem funnelId/funnelUid).
rate_limited429Acima do limite por PAT. Tem header Retry-After.
internal500Erro inesperado (mensagem genérica, sem stack).
confirmation_required400Escrita com dryRun=false SEM confirmationToken (rode dryRun=true antes).
confirmation_invalid403confirmationToken inválido, payload trocado, ou já usado (replay bloqueado).
confirmation_expired400confirmationToken expirou (5 min). Rode dryRun de novo.
idempotency_conflict409Idempotency-Key reutilizada com payload diferente.
conflict409Conflito de estado (ex.: slug de funil já existe no escopo).

Escrita (F1a)

Além de ler, a Agent API permite criar e editar rascunhos de funil com escrita controlada. Exige o scope funnels:write e segue um fluxo dry-run-first + confirmação: nada é gravado sem você confirmar.

Atenção: Escrita por MCP existe HOJE só para FUNIS (create_funnel_draft, update_funnel_draft — scope funnels:write). Leads, Webhook e Pixel continuam SOMENTE LEITURA — não há leads:write / webhooks:write / pixels:write por MCP ainda.

Tools de escrita (MCP → Agent API):

  • create_funnel_draft createFunnelDraftCria um rascunho de funil/formulário. Exige funnels:write. SEMPRE chame com dryRun=true primeiro.
  • update_funnel_draft updateFunnelDraftEdita um funil/formulário existente (informe id). Exige funnels:write. SEMPRE dryRun=true primeiro.

Fluxo obrigatório:

  1. 1. dryRun=trueValida o payload + permissões + cobrança e monta um PREVIEW do que mudaria. NÃO grava nada. Retorna um confirmationToken.
  2. 2. Revisar o previewConfira o que SERIA criado/alterado antes de executar.
  3. 3. dryRun=false + confirmationTokenReenvie o MESMO payload com o confirmationToken do passo 1. Só aí grava. Payload diferente → recusado.
TOKEN="cal_agent_..."   # PAT COM funnels:write
BASE="https://api.useagendo.com/agent/v1"

# 1) dry-run — NÃO grava; retorna preview + confirmationToken
curl -s -X POST "$BASE/createFunnelDraft" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Funil Black Friday","dryRun":true}'

# 2) executar — MESMO payload + dryRun:false + confirmationToken do passo 1.
#    (Opcional) header Idempotency-Key pra evitar duplicar em retries.
curl -s -X POST "$BASE/createFunnelDraft" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 9f1c-criar-bf" \
  -d '{"name":"Funil Black Friday","dryRun":false,"confirmationToken":"<token-do-passo-1>"}'

Garantias:

  • Dry-run obrigatórioToda escrita começa com dryRun=true. Sem ele você não tem confirmationToken pra executar.
  • confirmationToken travadoCurto (expira em ~5 min) e preso ao SEU token + à tool + ao payload exato. Mudou o payload → confirmation_invalid.
  • Não reutilizável (anti-replay)Cada confirmationToken executa UMA vez. Reenviar o mesmo → confirmation_invalid.
  • IdempotênciaHeader Idempotency-Key: mesma key + mesmo payload devolve a resposta anterior (não duplica); key + payload diferente → idempotency_conflict.
  • Token read-only não escreveSem o scope funnels:write a tool retorna forbidden_scope.
  • AuditoriadryRun E exec viram um AgentRequest — sem payload cru/PII (só hash) e resposta sanitizada.

Exemplos (curl)

TOKEN="cal_agent_..."
BASE="https://api.useagendo.com/agent/v1"

# getMe
curl -s -X POST "$BASE/getMe" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" -d '{}'

# listLeads (PII vem mascarada)
curl -s -X POST "$BASE/listLeads" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"teamId": 12, "limit": 20}'

# getFunnel
curl -s -X POST "$BASE/getFunnel" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"funnelId": 8}'

URL do MCP

Servidor MCP remoto — Streamable HTTP stateless (JSON-RPC via POST):

https://mcp.useagendo.com/mcp

Mesma autenticação da Agent API: o PAT no header Authorization: Bearer cal_agent_…. O MCP só traduz as tools → chamadas da Agent API (leitura + escrita F1a); auth, escopo, máscara de PII, dry-run/ confirmação e auditoria ficam no núcleo.

Como conectar (MCP)

Genérico (clientes que leem config MCP — Cursor, Windsurf, etc.):

{
  "mcpServers": {
    "agendo": {
      "url": "https://mcp.useagendo.com/mcp",
      "headers": { "Authorization": "Bearer cal_agent_..." }
    }
  }
}

Codex:

[mcp_servers.agendo]
url = "https://mcp.useagendo.com/mcp"
headers = { Authorization = "Bearer cal_agent_..." }

Tools (MCP)

As 10 tools MCP (8 de leitura + 2 de escrita) mapeiam 1:1 para as tools da Agent API (camelCase):

Tool MCPAgent APIDescrição
get_megetMeIdentidade do dono do PAT: usuário, scopes e times permitidos.
list_teamslistTeamsTimes visíveis pelo PAT (restritos ao allowedTeamIds).
list_funnelslistFunnelsLista funis do escopo. Sem teamId (ou null) = funis pessoais.
get_funnelgetFunnelDetalhe de 1 funil + resumo das etapas. Informe funnelId OU funnelUid.
list_pixelslistPixelsPixels Meta (CAPI) do escopo. Só hasToken — o token de acesso nunca sai.
get_pixel_healthgetPixelHealthSaúde de 1 pixel (último teste local). A entrega real é o Events Manager da Meta.
list_leadslistLeadsLista leads do escopo. PII vem mascarada. Filtros opcionais e paginação.
get_leadgetLeadDetalhe de 1 lead (PII mascarada). Informe leadId OU leadUid.
create_funnel_draftcreateFunnelDraftCria um rascunho de funil/formulário. Exige funnels:write. SEMPRE chame com dryRun=true primeiro.
update_funnel_draftupdateFunnelDraftEdita um funil/formulário existente (informe id). Exige funnels:write. SEMPRE dryRun=true primeiro.

Detalhe de input/output/exemplo de cada uma na Referência das tools.

Troubleshooting (MCP)

  • GET /mcp405: o servidor é stateless; use POST (JSON-RPC). Não é erro.
  • Erro de auth na tool → revise o PAT (ver Suporte).
  • Cliente não conecta → confirme que ele suporta MCP remoto / Streamable HTTP e aceita header Authorization.

Referência das tools

8 tools de leitura + 2 de escrita (F1a). Cada uma: endpoint da Agent API, scopes, input, output e um exemplo. As de escrita exigem funnels:write e o fluxo dry-run + confirmação (ver Escrita (F1a)).

get_me·Agent API: getMe

Identidade do dono do PAT: usuário, scopes e times permitidos.

Endpoint
POST https://api.useagendo.com/agent/v1/getMe
Scopes
agent:read
Input
Sem parâmetros.
Output
userId, name, email, username, locale, timeZone, allowedTeamIds, scopes

Exemplo

curl -s -X POST "https://api.useagendo.com/agent/v1/getMe" \
  -H "Authorization: Bearer cal_agent_..." \
  -H "Content-Type: application/json" \
  -d '{}'
list_teams·Agent API: listTeams

Times visíveis pelo PAT (restritos ao allowedTeamIds).

Endpoint
POST https://api.useagendo.com/agent/v1/listTeams
Scopes
agent:read
Input
Sem parâmetros.
Output
teams[]: teamId, name, slug, role

Exemplo

curl -s -X POST "https://api.useagendo.com/agent/v1/listTeams" \
  -H "Authorization: Bearer cal_agent_..." \
  -H "Content-Type: application/json" \
  -d '{}'
list_funnels·Agent API: listFunnels

Lista funis do escopo. Sem teamId (ou null) = funis pessoais.

Endpoint
POST https://api.useagendo.com/agent/v1/listFunnels
Scopes
agent:read + funnels:read
Input
teamId? (número | null)
Output
funnels[]: id, uid, name, teamId, enabled, pixelEnabled, leadsEnabled, stepCount

Exemplo

curl -s -X POST "https://api.useagendo.com/agent/v1/listFunnels" \
  -H "Authorization: Bearer cal_agent_..." \
  -H "Content-Type: application/json" \
  -d '{ "teamId": 12 }'
get_funnel·Agent API: getFunnel

Detalhe de 1 funil + resumo das etapas. Informe funnelId OU funnelUid.

Endpoint
POST https://api.useagendo.com/agent/v1/getFunnel
Scopes
agent:read + funnels:read
Input
funnelId? (número) | funnelUid? (texto) — um obrigatório
Output
id, uid, name, slug, teamId, enabled, pixelEnabled, leadsEnabled, hasCustomDomain, headline, subhead, eventTypeId, stepCount, hasQualification, hasSchedule, closingKind, steps

Exemplo

curl -s -X POST "https://api.useagendo.com/agent/v1/getFunnel" \
  -H "Authorization: Bearer cal_agent_..." \
  -H "Content-Type: application/json" \
  -d '{ "funnelId": 8 }'
list_pixels·Agent API: listPixels

Pixels Meta (CAPI) do escopo. Só hasToken — o token de acesso nunca sai.

Endpoint
POST https://api.useagendo.com/agent/v1/listPixels
Scopes
agent:read + pixels:read
Input
teamId? (número | null)
Output
pixels[]: id, teamId, name, pixelId, enabled, sendScope, statusEventMap, leadEventSource, lastTestStatus, hasToken

Exemplo

curl -s -X POST "https://api.useagendo.com/agent/v1/listPixels" \
  -H "Authorization: Bearer cal_agent_..." \
  -H "Content-Type: application/json" \
  -d '{ "teamId": 12 }'
get_pixel_health·Agent API: getPixelHealth

Saúde de 1 pixel (último teste local). A entrega real é o Events Manager da Meta.

Endpoint
POST https://api.useagendo.com/agent/v1/getPixelHealth
Scopes
agent:read + pixels:read
Input
pixelId (número, obrigatório)
Output
id, teamId, name, pixelId, enabled, sendScope, hasToken, lastTestedAt, lastTestStatus, note

Exemplo

curl -s -X POST "https://api.useagendo.com/agent/v1/getPixelHealth" \
  -H "Authorization: Bearer cal_agent_..." \
  -H "Content-Type: application/json" \
  -d '{ "pixelId": 5 }'
list_leads·Agent API: listLeads

Lista leads do escopo. PII vem mascarada. Filtros opcionais e paginação.

Endpoint
POST https://api.useagendo.com/agent/v1/listLeads
Scopes
agent:read + leads:read
Input
teamId? · search? · status? · source? · limit (1–100, padrão 50) · offset (padrão 0)
Output
total, limit, offset, items[]: id, uid, name, emailMasked, phoneMasked, status, source, value, teamId, createdAt

Exemplo

curl -s -X POST "https://api.useagendo.com/agent/v1/listLeads" \
  -H "Authorization: Bearer cal_agent_..." \
  -H "Content-Type: application/json" \
  -d '{ "teamId": 12, "limit": 20 }'
get_lead·Agent API: getLead

Detalhe de 1 lead (PII mascarada). Informe leadId OU leadUid.

Endpoint
POST https://api.useagendo.com/agent/v1/getLead
Scopes
agent:read + leads:read
Input
leadId? (número) | leadUid? (texto) — um obrigatório
Output
id, uid, name, emailMasked, phoneMasked, cpfMasked, status, source, value, teamId, qualification, createdAt

Exemplo

curl -s -X POST "https://api.useagendo.com/agent/v1/getLead" \
  -H "Authorization: Bearer cal_agent_..." \
  -H "Content-Type: application/json" \
  -d '{ "leadId": 4567 }'
create_funnel_draft·Agent API: createFunnelDraft

Cria um rascunho de funil/formulário. Exige funnels:write. SEMPRE chame com dryRun=true primeiro.

Endpoint
POST https://api.useagendo.com/agent/v1/createFunnelDraft
Scopes
funnels:write
Input
name (obrigatório) · teamId? (null = pessoal) · slug? · enabled? · headline? · subhead? · steps? · pixelEnabled? · leadsEnabled? · dryRun (padrão true) · confirmationToken (no exec)
Output
dryRun → { dryRun:true, preview:{action,targetId,wouldChange}, confirmationToken, expiresAt } · exec → { dryRun:false, action, resource:{id,uid,name,slug,enabled,teamId} }

Exemplo

curl -s -X POST "https://api.useagendo.com/agent/v1/createFunnelDraft" \
  -H "Authorization: Bearer cal_agent_..." \
  -H "Content-Type: application/json" \
  -d '{ "name": "Funil Black Friday", "dryRun": true }'
update_funnel_draft·Agent API: updateFunnelDraft

Edita um funil/formulário existente (informe id). Exige funnels:write. SEMPRE dryRun=true primeiro.

Endpoint
POST https://api.useagendo.com/agent/v1/updateFunnelDraft
Scopes
funnels:write
Input
id (obrigatório) · name (obrigatório) · teamId? · slug? · enabled? · steps? · pixelEnabled? · leadsEnabled? · dryRun (padrão true) · confirmationToken (no exec)
Output
igual a create_funnel_draft (action = "updated").

Exemplo

curl -s -X POST "https://api.useagendo.com/agent/v1/updateFunnelDraft" \
  -H "Authorization: Bearer cal_agent_..." \
  -H "Content-Type: application/json" \
  -d '{ "id": 8, "name": "Funil Black Friday 2", "enabled": false, "dryRun": true }'

Segurança

  • PII mascarada — leads voltam emailMasked/phoneMasked/cpfMasked; nunca o valor cru.
  • Token CAPI oculto — pixels expõem só hasToken (bool). O access token da Meta nunca sai.
  • Auditoria — cada chamada registra um AgentRequest (tool, status; sem corpo/PII).
  • Rate-limit — 120 req/min por PAT (429 rate_limited com Retry-After).
  • Permissões por time — o PAT só acessa os times do allowedTeamIds.
  • Escrita com guarda — só funis (funnels:write): dry-run obrigatório + confirmationToken (payload-locked, uso único/anti-replay) + idempotência opcional. Leads, Webhook e Pixel seguem somente leitura.

Suporte

Dúvidas ou problemas de integração? O ponto de partida é o app: https://app.useagendo.com.

  • Recebeu 401 unauthorized → revise o PAT (ausente, expirado ou revogado) e o header Authorization.
  • Recebeu 403 forbidden_scope → o PAT não tem o scope exigido pela tool; gere um com o scope certo.
  • Recebeu 403 forbidden_team → o teamId está fora do allowedTeamIds do PAT.
  • Recebeu 404 not_found → recurso inexistente ou sem acesso (a API não distingue, por segurança).