Agents
Every voice + SMS agent in your tenant has a stable identity. Address agents by human-readable slug or UUID; renames preserve old slugs as aliases for ~12 months so existing integrations don't break.
agent_id (slug or UUID) to any endpoint that accepts it; the API resolves through the agent_aliases table so old slugs keep working after renames.Identity model#
iduuidslugstringkindenumpurposestring?labelsstring[]stateenumclient_iduuidorg_iduuidAddressing agents#
Every endpoint that takes {idOrSlug} accepts both forms. We recommend slugs in code you write — they're readable, debuggable, and survive UUID lookup latency.
curl https://agency.gary.club/api/public/v1/agents/agent_3kf9ab \
-H "Authorization: Bearer gc_live_EXAMPLE_AbCdEfGhIj0123456789"agent_id explicitly. We do NOT pick a default agent for you, even when the client has only one — it's better to fail loud than silently route to the wrong agent if the client adds a second one later.Exception: API keys minted with
key_kind="agent" auto-narrow to their bound agent. The same call without agent_id works because the key already encodes scope.List agents#
List agents in your tenant scope
/v1/agentsQuery parameters
client_iduuidkind"inbound_voice" | "outbound_voice" | "sms" | "hybrid_voice_sms"purposestringlabelstringstate"active" | "paused" | "archived"qstringlimitintegerdefault: 50page_tokenstringcurl "https://agency.gary.club/api/public/v1/agents?kind=inbound_voice&state=active" \
-H "Authorization: Bearer gc_live_EXAMPLE_AbCdEfGhIj0123456789"Get agent detail#
Read full agent config
/v1/agents/{idOrSlug}Path parameters
idOrSlugstringrequiredcurl https://agency.gary.club/api/public/v1/agents/agent_3kf9ab \
-H "Authorization: Bearer gc_live_EXAMPLE_AbCdEfGhIj0123456789"Update an agent#
Update purpose, labels, state, slug, name, greeting, voice
/v1/agents/{idOrSlug}Body parameters
namestringslugstringpurposestring | nulllabelsstring[]state"active" | "paused" | "archived"location_labelstring | nullgreetingstringvoice_idstringcurl -X PATCH https://agency.gary.club/api/public/v1/agents/agent_3kf9ab \
-H "Authorization: Bearer gc_live_EXAMPLE_AbCdEfGhIj0123456789" \
-H "Content-Type: application/json" \
-d '{
"purpose": "After-hours overflow",
"labels": ["english", "vip"],
"state": "active"
}'Filter other endpoints by agent#
Pass agent_id (slug or UUID) as a query param to scope these endpoints to a specific agent:
GET /v1/calls?agent_id=GET /v1/sms/conversations?agent_id=curl "https://agency.gary.club/api/public/v1/calls?agent_id=agent_3kf9ab&limit=20" \
-H "Authorization: Bearer gc_live_EXAMPLE_AbCdEfGhIj0123456789"Per-agent webhooks#
Subscribe to events from one specific agent by passing agent_id when creating the subscription. Org-wide and client-wide subscriptions still receive that agent's events; agent-scoped subscriptions ONLY receive events from the bound agent.
Every event payload now includes an agent block:
{
"event": "call.completed",
"agent": {
"id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"slug": "agent_3kf9ab",
"kind": "inbound_voice"
},
"data": {
"call_id": "...",
"duration_seconds": 124,
"outcome": "booked"
}
}API key + agent narrowing#
There's no per-agent API key any more — the per-agent tab was retired. Use the client's cl_live_ key and pass ?agent_id=… on requests where you want to narrow to one agent. The key still scopes the tenancy; agent_id is just a filter inside it.
- Agency (gc_live_): all clients + all agents in the org.
- Client (cl_live_): one client, all of its agents.
- Per-agent narrowing: add
?agent_id=…on requests that support it (calls, sms, sms-broadcasts, contacts).
Slug renames + aliases#
When you rename an agent's slug, the previous slug is automatically inserted into agent_aliases and resolves to the same agent for the next 12 months. Requests that hit an alias receive an X-Gary-Deprecation response header pointing to the canonical slug — update your code at your leisure.

