Agents API
The Agents API is split between two surfaces:
- Tenant-admin (dashboard) —
/v1/auth/dashboard/tenants/{slug}/agents/**, session-authenticated, owner-role required for write operations. - End-user —
/v1/users/me/agents, JWT-authenticated, scoped to the caller’s user identity within the resolved tenant.
Cross-tenant access on either surface returns 404, never 403, per project convention.
The canonical machine-readable spec lives in
packages/api/openapi.json(regenerated bypnpm run spec:update). What follows is a human guide; field-level shapes are authoritative in the OpenAPI document.
Tenant-admin surface
Section titled “Tenant-admin surface”Register an agent
Section titled “Register an agent”POST /v1/auth/dashboard/tenants/{slug}/agentsContent-Type: application/json{ "name": "Concierge bot", "description": "Books rooms on behalf of guests", "agent_class": "mcp-server", "scopes": ["read:bookings", "write:bookings"], "grant_types": [ "urn:ietf:params:oauth:grant-type:token-exchange", "urn:openid:params:grant-type:ciba" ], "agent_token_max_ttl_sec": 300, "agent_settings": { "rate_limits": { "api_calls_per_min": 120 }, "max_concurrent_tokens": 50 }}Response 201: { ...AgentResponse, client_secret } — secret revealed
exactly once.
Errors:
400 oauth_client/use_agents_endpoint— sent if you POSTedclient_type: 'agent'to the legacy/oauth-clientsendpoint. Soft-redirect — use the agents endpoint instead.403 agent/tier_unauthorized— Free tier; upgrade to Pro+.422 agent/invalid_grant_type— grant outside the agent allowlist ({token-exchange, ciba, device-code, client-credentials}).422 agent/invalid_field—redirect_urisnon-empty (agents are headless).
List agents
Section titled “List agents”GET /v1/auth/dashboard/tenants/{slug}/agentsGET /v1/auth/dashboard/tenants/{slug}/agents?include_revoked=trueCursor-paginated (default limit=20, max 100). Default selector:
clientType='agent' AND revoked_at IS NULL. Pass include_revoked=true to
see revoked agents.
Get / update / rotate-secret
Section titled “Get / update / rotate-secret”GET /v1/auth/dashboard/tenants/{slug}/agents/{agentId}PATCH /v1/auth/dashboard/tenants/{slug}/agents/{agentId}POST /v1/auth/dashboard/tenants/{slug}/agents/{agentId}/rotate-secretPATCH bumps agent_metadata_version. Rotate-secret reveals the new secret
exactly once.
PATCH and rotate-secret on a revoked agent → 409 agent/already_revoked.
Revoke an agent (immediate, all tokens)
Section titled “Revoke an agent (immediate, all tokens)”DELETE /v1/auth/dashboard/tenants/{slug}/agents/{agentId}Response 200: { id, name, revoked_at, agent_metadata_version }.
The revocation pipeline (atomic):
UPDATE oauth_clients SET revoked_at = now() WHERE id = ? AND revoked_at IS NULL(conditional — second call is a no-op).- Insert an
agent_token_denylistrow valid untilnow() + agent_token_max_ttl_sec. - Emit
agent.revokedaudit (HIGH severity) + webhook. - Notify all tenant owners by email.
Bearer-auth middleware consults the denylist after signature verification
on every request; tokens whose act.sub matches an active denylist row are
rejected with WWW-Authenticate: Bearer error="invalid_token", error_description="agent_revoked" 401.
Idempotent — re-revoking returns 200 with the existing revoked_at and
fires no second audit / webhook.
Activity timeline
Section titled “Activity timeline”GET /v1/auth/dashboard/tenants/{slug}/agents/{agentId}/activity ?cursor=&limit=50&since=&until=&actor_user_id=&action_type=Returns { data: AgentActionResponse[], pagination: { next_cursor, has_more } }.
Default limit=50, max 200. RBAC: only tenant.role === 'owner' may read
other users’ actions.
AgentActionResponse fields: id, action, actor_user_id?,
actor_user_email?, resource?, method_or_event?, jti?,
scope_used?, ip_hash_prefix? (12 chars), user_agent_hash_prefix?,
created_at. Raw IP / UA hashes are never returned.
End-user surface
Section titled “End-user surface”List agents acting on me
Section titled “List agents acting on me”GET /v1/users/me/agentsAuthorization: Bearer <user-jwt>Returns { data: UserAgentResponse[] }, sorted by last_action_at DESC.
UserAgentResponse fields: agent_client_id, agent_name,
agent_logo_url?, agent_class?, last_action_at?, action_count,
revoked_at? (this user revoked), agent_revoked_at? (tenant admin
revoked).
Revoke (GDPR Art. 7(3))
Section titled “Revoke (GDPR Art. 7(3))”DELETE /v1/users/me/agents/{agentClientId}Authorization: Bearer <user-jwt>Inserts a user_agent_revocations row keyed (tenant_id, user_id, agent_client_id)
with reason='gdpr_art_7_withdrawal'. Token-issuance gates in
token-exchange + CIBA reject any future mint where (act.sub, sub) matches.
Important: already-issued tokens remain valid until their TTL expires
(≤900s ceiling). For instant per-token invalidation across all users, the
tenant admin uses DELETE /v1/auth/dashboard/tenants/{slug}/agents/{agentId}.
Response 200: { agent_client_id, revoked_at, reason }. Idempotent.
Rate limits
Section titled “Rate limits”- Writes →
RATE_LIMIT_AUTH_WRITE_MAX. - Reads + activity →
RATE_LIMIT_AUTH_READ_MAX. - Per-agent overrides via
agent_settings.rate_limits:token_exchange_per_min,ciba_initiate_per_min,device_code_per_min,client_credentials_per_min,api_calls_per_min. Hard ceiling:RATE_LIMIT_OAUTH_AGENT_CEILING = 600. - Hits emit
agent.rate_limitedaudit events with the offending scope and the computed limit.
SDK helpers
Section titled “SDK helpers”The Node SDK exposes the end-user surface only (admin endpoints stay in the dashboard’s session-auth realm):
import { RakomiClient } from '@rakomi/node';
const client = new RakomiClient({ apiKey: process.env.RAKOMI_API_KEY! });const userToken = '<end-user-jwt>';
const list = await client.users.me.agents.list({ userToken });if (list.ok) { for (const agent of list.data.data) { console.log(agent.agent_name, agent.action_count); }}
const revoked = await client.users.me.agents.revoke({ userToken, agentClientId: 'agent_abc',});Both helpers return the SDK’s Result shape ({ ok: true, data } | { ok: false, error })
and never throw on expected 4xx responses. Typed errors are exported for
instanceof checks: AgentsUnauthorizedError, AgentNotFoundError,
AgentsRateLimitedError, AgentsNetworkError.