CUSTOMAGENTS
Developers

Per-Agent API & MCP

Issue a key bound to a single agent. The /v1/agents/:agentId REST surface, the agent MCP endpoint, the agent scope namespace, the tool catalog, and the isolation guarantee.

What a per-agent key is

A per-agent key (ca_agt_…) is bound server-side to exactly one agent. It can read and (if you grant it) drive that one agent — and nothing else. It cannot enumerate other agents, cannot reach your contacts, billing, inboxes, integrations, or webhooks, and cannot mint keys.

This is ideal for handing a single agent to a third party, an embedded app, or a CI job without exposing the rest of your account.

The binding lives on the hashed key row in our database, not in the URL. Changing the :agentId in a request path does not widen a per-agent key — it just gets a 403.

Where to mint the key

Per-agent keys are minted from the agent's own settings, not the account API-keys page:

  • Dashboard: open the agent → Settings → API & MCPNew key. Copy the secret immediately (shown once).
  • REST: POST /v1/agents/:agentId/api-keys (admin session or account key, depending on your org policy).
curl -X POST https://api.customagents.io/v1/agents/agent_abc123/api-keys \
  -H "Authorization: Bearer ca_acct_YOUR_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Embed: support widget",
    "scopes": ["agent:config:read", "agent:conversations:read"]
  }'
{
  "id": "key_def456",
  "name": "Embed: support widget",
  "keyType": "agent",
  "agentId": "agent_abc123",
  "keyPrefix": "ca_agt_",
  "scopes": ["agent:config:read", "agent:conversations:read"],
  "key": "ca_agt_…",            // shown ONCE
  "createdAt": "2026-06-17T10:30:00Z"
}

The keyType and agentId are forced server-side — you cannot widen a key by passing a different agent, an account scope, *, or write:api_keys. A per-agent key is also denied this route: a key cannot mint another key.

Agent scopes

A per-agent key holds scopes only from the agent: namespace. The default (when scopes are omitted) is read-only.

ScopeGrantsDefault
agent:config:readRead this agent's configuration
agent:conversations:readRead this agent's conversations
agent:activity:readRead this agent's activity
agent:config:writeUpdate this agent's configurationopt-in
agent:triggerTrigger this agent via chat — money-spendingopt-in

agent:trigger is separated from the reads so a read-only key can never spend credits. Grant it only when the key needs to drive the agent.

REST surface

A ca_agt_ key can reach only /v1/agents/<its-own-agentId>/**:

Method & pathRequired scope
GET /v1/agents/:idagent:config:read
PATCH /v1/agents/:idagent:config:write
GET /v1/agents/:id/conversationsagent:conversations:read
GET /v1/agents/:id/activityagent:activity:read
POST /v1/agents/:id/chatagent:trigger
# Read this agent's config
curl https://api.customagents.io/v1/agents/agent_abc123 \
  -H "Authorization: Bearer ca_agt_YOUR_KEY"

# Trigger the agent (requires agent:trigger)
curl -X POST https://api.customagents.io/v1/agents/agent_abc123/chat \
  -H "Authorization: Bearer ca_agt_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "message": "Summarize today's open threads" }'

Per-agent MCP

The agent also exposes a dedicated MCP endpoint so an IDE can work with just that one agent:

Per-agent MCP endpoint:  https://api.customagents.io/v1/agents/<AGENT_ID>/mcp

Authenticate with the ca_agt_ key for that agent. Configuration is identical to the account MCP setup — only the URL and key differ. For Claude Code:

claude mcp add --transport http my-agent \
  https://api.customagents.io/v1/agents/agent_abc123/mcp \
  --header "Authorization: Bearer ca_agt_YOUR_KEY"

Agent tool catalog

The per-agent MCP server registers only agent-scoped tools — there is no list_agents and no cross-agent or account tool. Every query is hard-bound to { organizationId, agentId }. Destructive tools prompt for confirmation in the IDE.

ToolRequired scopeDestructive
get_agent_configagent:config:read
get_agent_conversationsagent:conversations:read
get_agent_activityagent:activity:read
update_agent_configagent:config:writeYes
trigger_agentagent:triggerYes

Isolation guarantee

A per-agent key (ca_agt_…) is structurally confined to its one agent. Concretely, it returns 403 on:

  • The account MCP endpoint POST /v1/mcp.
  • Any other agent: GET /v1/agents/<otherId>/** and /v1/agents/<otherId>/mcp.
  • The agents collection GET/POST /v1/agents.
  • Every account router: contacts, messages, inboxes, domains, webhooks, integrations, subscriptions, payment methods, team, notifications, and api_keys.
  • Bulk endpoints such as account-wide /activity and /drafts.

There is no cross-agent or account tool in the per-agent MCP server, so isolation is structural, not just a permission check. A compromised per-agent key cannot enumerate your other agents or touch contacts, billing, or integrations.

See also