Reference
Error responses
All endpoints return a standard error shape:
{ "detail": "<human-readable message>" }
| Status | Meaning | Example |
|---|---|---|
400 Bad Request | Invalid input | "phone must be in E.164 format" |
401 Unauthorized | Missing or invalid token | "Invalid or expired token" |
403 Forbidden | Valid token, missing scope | "Insufficient permissions. Required scopes: voice:calls:write" |
404 Not Found | Resource does not exist | "Contact not found" |
409 Conflict | State conflict | "Call is not currently active" |
429 Too Many Requests | Rate limit exceeded | "Rate limit exceeded: 10/minute" |
503 Service Unavailable | Downstream unavailable | "No agents available in target queue" |
Rate limits
| Endpoint | Limit |
|---|---|
| All endpoints (default) | 100/minute per API key |
POST /v1/calls | 30/minute |
POST /v1/campaigns/{id}/launch | 5/minute |
POST /v1/campaigns/{id}/stop | 5/minute |
POST /v1/contacts | 60/minute |
PATCH /v1/contacts/{id} | 60/minute |
POST /v1/contacts/bulk | 10/minute |
POST /v1/webhooks | 20/minute |
POST /api/voice/customers/import | 5/minute |
POST /api/voice/models/speakers | 5/minute |
POST /api/voice/models/speakers/{name}/deploy | 5/minute |
POST /api/voice/models/speakers/{name}/dataset/sample | 30/minute |
POST /api/voice/calls/{uuid}/transfer | 10/minute |
POST /api/voice/calls/{uuid}/end | 10/minute |
GET /api/voice/calls/agent-availability | 30/minute |
POST /api/voice/calls/{uuid}/metadata | 30/minute |
POST /api/voice/agents | 20/minute |
POST /api/voice/flows | 20/minute |
Exceeding a limit returns 429 Too Many Requests. Limits are per API key, not per IP.
Workflow integration pattern
The platform is workflow-agnostic. The config field on a Campaign and the metadata field on a Contact carry all client-specific data. Your workflow service owns the business logic; the platform owns the telephony and transcript infrastructure.
Standard post-call flow:
1. POST /v1/contacts/bulk ← push daily lead list from your CRM
2. POST /v1/campaigns/{id}/launch ← start campaign
3. webhook: call.ended ← receive transcript on every call end
4. [Workflow] run LLM extraction ← process transcript
5. POST /api/voice/calls/{id}/metadata ← write structured payload back
6. [Workflow] write to your CRM ← push extracted data
7. [Workflow] trigger messaging ← fire WhatsApp, email, or callback queue
Warm transfer flow:
3b. webhook: call.started ← detect live call
4b. GET /api/voice/calls/agent-availability ← check queue
5b. POST /api/voice/calls/{id}/transfer ← bridge if agent available
↳ falls back to async handoff if queue is empty