Getting Started
CXCo is an API-first platform that enables companies to create, deploy, and manage AI-powered voice and WhatsApp agents. Provision a phone number, configure an agent's personality and voice, and go live -- all through a single integration.
Base URL
Authentication
All API requests require an API key passed in the X-API-Key header. There are two types of API keys:
Company Keys
cxco_comp_k_Issued when a company is created. Used for managing users, webhooks, providers, and company settings.
User Keys
cxco_user_k_Generated when a user is created. Used for managing agents, conversations, phone numbers, voices, and usage.
Error Handling
All errors follow a consistent JSON structure:
{
"detail": "Human-readable error message",
"error_type": "validation_error"
}| Code | Meaning |
|---|---|
200 | Success |
201 | Created |
204 | No Content |
400 | Bad request / validation error |
401 | Unauthorized -- missing or invalid API key |
403 | Forbidden -- insufficient permissions (wrong key type) |
404 | Resource not found |
409 | Conflict -- duplicate or constraint violation |
422 | Unprocessable entity |
500 | Internal server error |
Pagination
List endpoints use cursor-based pagination. Pass the cursor query parameter from the previous response to fetch the next page. The default page size is 30 (max 100).
Guides
Step-by-step walkthroughs for common API workflows.
Create and Publish a Voice Agent
Go from zero to a live AI agent answering phone calls in 3 API calls. Browse available voices, create a draft agent, and publish it to get a phone number.
/api/voices/
List voices
Browse the curated catalogue of available AI voices.
{
"id": 1,
"provider_id": 1,
"external_voice_id": "21m00Tcm4TlvDq8ikWAM",
"name": "Rachel",
"gender": "female",
"accent": "american",
"language": "en",
"preview_url": "https://cdn.example.com/voices/rachel_preview.mp3",
"tags": {
"style": "conversational",
"tone": "warm"
},
"status": "active"
}/api/agents/
Create a draft agent
Create a new AI agent in draft status.
{
"name": "Sales Assistant",
"personality": "You are a friendly and professional sales assistant for Acme Corp. You help customers understand our product range and guide them toward the right solution. Be conversational, never pushy.",
"opening_line": "Hi there! Thanks for calling Acme Corp. How can I help you today?",
"voice_id": 1,
"language": "en",
"config": {
"temperature": 0.7,
"max_call_duration_seconds": 600
}
}{
"id": 10,
"company_id": 1,
"name": "Sales Assistant",
"personality": "You are a friendly and professional sales assistant for Acme Corp...",
"opening_line": "Hi there! Thanks for calling Acme Corp. How can I help you today?",
"voice": {
"id": 1,
"name": "Rachel"
},
"language": "en",
"status": "draft",
"voice_enabled": true,
"whatsapp_enabled": false,
"config": {
"temperature": 0.7,
"max_call_duration_seconds": 600
},
"created_at": "2026-03-12T14:30:00Z",
"updated_at": "2026-03-12T14:35:00Z"
}/api/agents/{agent_id}/publish
Publish agent
Publish a draft agent to make it live.
{
"country_code": "ZA"
}{
"id": 10,
"company_id": 1,
"name": "Sales Assistant",
"personality": "You are a friendly and professional sales assistant for Acme Corp...",
"opening_line": "Hi there! Thanks for calling Acme Corp. How can I help you today?",
"voice": {
"id": 1,
"name": "Rachel"
},
"language": "en",
"status": "active",
"voice_enabled": true,
"whatsapp_enabled": false,
"external_agent_id": "el_abc123",
"phone_number": {
"id": 5,
"number": "+27211234567",
"voice_enabled": true,
"whatsapp_enabled": false,
"whatsapp_status": "none"
},
"config": {
"temperature": 0.7,
"max_call_duration_seconds": 600
},
"created_at": "2026-03-12T14:30:00Z",
"updated_at": "2026-03-12T14:35:00Z"
}Enable WhatsAppComing Soon
Add WhatsApp messaging to an existing agent's phone number. The same number handles both voice calls and WhatsApp messages through the same agent personality.
/api/phone-numbers/{phone_number_id}/enable-whatsapp
Enable WhatsApp
Initiate WhatsApp Business verification for a phone number.
{
"id": 5,
"number": "+27211234567",
"provider_slug": "sip_trunk",
"country_code": "ZA",
"status": "assigned",
"company_id": 1,
"agent_id": 10,
"whatsapp_status": "pending",
"created_at": "2026-03-01T00:00:00Z",
"updated_at": "2026-03-12T14:35:00Z"
}/api/phone-numbers/{phone_number_id}/whatsapp-status
Check WhatsApp status
Check the WhatsApp verification status of a phone number.
{
"id": 5,
"number": "+27211234567",
"whatsapp_status": "active"
}Set Up Webhooks
Receive real-time events when conversations complete, agents change status, or WhatsApp verification finishes. Webhooks use HMAC signatures for verification.
/api/webhooks/
Register webhook
Register an HTTPS endpoint to receive real-time events.
{
"url": "https://your-app.com/webhooks/cxco",
"events": [
"conversation.completed",
"agent.status_changed"
],
"secret": "whsec_your_secret_key"
}{
"id": 1,
"company_id": 1,
"url": "https://your-app.com/webhooks/cxco",
"events": [
"conversation.completed",
"agent.status_changed"
],
"status": "active",
"created_at": "2026-03-12T10:00:00Z",
"updated_at": "2026-03-12T10:00:00Z"
}/api/webhooks/
List webhooks
List all webhook registrations for your company.
{
"id": 1,
"company_id": 1,
"url": "https://your-app.com/webhooks/cxco",
"events": [
"conversation.completed",
"agent.status_changed"
],
"status": "active",
"created_at": "2026-03-12T10:00:00Z",
"updated_at": "2026-03-12T10:00:00Z"
}Monitor Usage and Conversations
Track conversation history with full transcripts, and monitor voice minutes and message counts across your agents.
/api/conversations/
List conversations
List conversations with cursor-based pagination.
{
"id": 100,
"agent_id": 10,
"company_id": 1,
"channel": "voice",
"caller_number": "+27821234567",
"direction": "inbound",
"started_at": "2026-03-12T16:05:00Z",
"ended_at": "2026-03-12T16:08:32Z",
"duration_seconds": 212,
"message_count": 14,
"status": "completed",
"call_successful": true,
"transcript_summary": "Customer enquired about Pro plan pricing. Agent provided details and offered to send a follow-up email.",
"source": "elevenlabs",
"external_conversation_id": "el_conv_abc123",
"created_at": "2026-03-12T16:05:00Z"
}/api/conversations/{conversation_id}
Get conversation details
Retrieve the full details of a conversation, including the complete transcript and metadata.
{
"id": 100,
"agent_id": 10,
"company_id": 1,
"channel": "voice",
"caller_number": "+27821234567",
"direction": "inbound",
"started_at": "2026-03-12T16:05:00Z",
"ended_at": "2026-03-12T16:08:32Z",
"duration_seconds": 212,
"message_count": 14,
"status": "completed",
"call_successful": true,
"transcript_summary": "Customer enquired about Pro plan pricing. Agent provided details and offered to send a follow-up email.",
"source": "elevenlabs",
"external_conversation_id": "el_conv_abc123",
"created_at": "2026-03-12T16:05:00Z",
"transcript": [
{
"role": "agent",
"message": "Hi there! Thanks for calling Acme Corp. How can I help you today?",
"timestamp": 0.0
},
{
"role": "user",
"message": "Hi, I was wondering about your pricing for the Pro plan.",
"timestamp": 3.2
},
{
"role": "agent",
"message": "Great question! Our Pro plan starts at R499 per month and includes...",
"timestamp": 5.8
}
],
"metadata_": {
"llm_tokens": 1240
}
}/api/usage/summary
Get usage summary
Get aggregated usage metrics for your company over a date range.
{
"period": {
"start_date": "2026-03-01",
"end_date": "2026-03-12"
},
"voice": {
"total_conversations": 342,
"total_minutes": 1205.7,
"total_sip_refer_minutes": 87.3
},
"whatsapp": {
"total_conversations": 156,
"total_messages": 2840
}
}/api/usage/daily
Get daily usage breakdown
Get usage metrics broken down by day.
{
"date": "2026-03-11",
"voice": {
"total_conversations": 31,
"total_minutes": 112.4,
"total_sip_refer_minutes": 8.2
},
"whatsapp": {
"total_conversations": 18,
"total_messages": 245
}
}API Reference
Complete reference for all CXCo API endpoints.
Companies
A company is the top-level tenant. All agents, phone numbers, users, and usage roll up to a company. Each company has its own credentials and billing scope.
/api/companies/{company_id}
Any Key
Get company details
| Name | In | Type | Required | Description |
|---|---|---|---|---|
company_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
name | string | required | |
status | string | required | |
meta_business_id | string? | optional | |
settings | object? | optional | |
created_at | string | required | |
updated_at | string | required |
{
"id": 1,
"name": "Acme Corp",
"status": "active",
"settings": {
"default_language": "en"
},
"created_at": "2026-03-12T10:00:00Z",
"updated_at": "2026-03-12T10:00:00Z"
}| Status | Description |
|---|---|
404 | The company ID does not match your API key's company. |
422 | Validation Error |
/api/companies/{company_id}
Any Key
Update company
| Name | In | Type | Required | Description |
|---|---|---|---|---|
company_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
name | string? | optional | |
settings | object? | optional |
{
"name": "Acme Corp International",
"settings": {
"default_language": "en",
"timezone": "Africa/Johannesburg"
}
}| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
name | string | required | |
status | string | required | |
meta_business_id | string? | optional | |
settings | object? | optional | |
created_at | string | required | |
updated_at | string | required |
{
"id": 1,
"name": "Acme Corp International",
"status": "active",
"settings": {
"default_language": "en",
"timezone": "Africa/Johannesburg"
},
"created_at": "2026-03-12T10:00:00Z",
"updated_at": "2026-03-12T14:30:00Z"
}| Status | Description |
|---|---|
422 | Validation Error |
/api/companies/{company_id}/usage
Any Key
Get company usage
| Name | In | Type | Required | Description |
|---|---|---|---|---|
company_id | path | integer | required | |
start_date | query | string | optional | |
end_date | query | string | optional |
| Field | Type | Required | Description |
|---|---|---|---|
period | object | required | |
voice | object | required | |
agents_active | integer | optional | Default: 0 |
by_agent | array[AgentUsageBreakdown] | optional | Default: [] |
{
"period": {
"start_date": "2026-03-01",
"end_date": "2026-03-12"
},
"voice": {
"total_conversations": 342,
"total_minutes": 1205.7,
"total_sip_refer_minutes": 87.3,
"average_duration_seconds": 211.5,
"success_rate": 0.94
},
"agents_active": 5,
"by_agent": [
{
"agent_id": 10,
"agent_name": "Support Bot",
"voice_minutes": 620.3,
"total_conversations": 180
}
]
}| Status | Description |
|---|---|
422 | Validation Error |
Users
Users belong to a company and interact with the platform on that company's behalf. Users are created with company credentials and receive their own API keys.
/api/users/
Company Key
Create a user
| Field | Type | Required | Description |
|---|---|---|---|
email | string | required | |
name | string | required | |
role | string | optional | Default: member |
{
"email": "jane@acme.com",
"name": "Jane Smith",
"role": "admin"
}| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
email | string | required | |
name | string | required | |
role | string | required | |
status | string | required | |
created_at | string | required | |
updated_at | string | required | |
api_key | string | required |
{
"id": 42,
"company_id": 1,
"email": "jane@acme.com",
"name": "Jane Smith",
"role": "admin",
"status": "active",
"created_at": "2026-03-12T10:05:00Z",
"updated_at": "2026-03-12T10:05:00Z",
"api_key": "cxco_user_k_a1b2c3d4e5f6..."
}| Status | Description |
|---|---|
409 | A user with this email already exists in the company. |
422 | Validation Error |
/api/users/me
User Key
Get current user
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
email | string | required | |
name | string | required | |
role | string | required | |
status | string | required | |
created_at | string | required | |
updated_at | string | required |
{
"id": 42,
"company_id": 1,
"email": "jane@acme.com",
"name": "Jane Smith",
"role": "admin",
"status": "active",
"created_at": "2026-03-12T10:05:00Z",
"updated_at": "2026-03-12T10:05:00Z"
}/api/users/{user_id}
Company Key
Get user by ID
| Name | In | Type | Required | Description |
|---|---|---|---|---|
user_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
email | string | required | |
name | string | required | |
role | string | required | |
status | string | required | |
created_at | string | required | |
updated_at | string | required |
{
"id": 42,
"company_id": 1,
"email": "jane@acme.com",
"name": "Jane Smith",
"role": "admin",
"status": "active",
"created_at": "2026-03-12T10:05:00Z",
"updated_at": "2026-03-12T10:05:00Z"
}| Status | Description |
|---|---|
404 | The user does not exist or belongs to a different company. |
422 | Validation Error |
/api/users/{user_id}
Company Key
Update user
| Name | In | Type | Required | Description |
|---|---|---|---|---|
user_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
name | string? | optional | |
role | string? | optional |
{
"name": "Jane Smith-Jones",
"role": "owner"
}| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
email | string | required | |
name | string | required | |
role | string | required | |
status | string | required | |
created_at | string | required | |
updated_at | string | required |
{
"id": 42,
"company_id": 1,
"email": "jane@acme.com",
"name": "Jane Smith-Jones",
"role": "owner",
"status": "active",
"created_at": "2026-03-12T10:05:00Z",
"updated_at": "2026-03-12T15:00:00Z"
}| Status | Description |
|---|---|
404 | The user does not exist or belongs to a different company. |
422 | Validation Error |
/api/users/{user_id}
Company Key
Delete user
| Name | In | Type | Required | Description |
|---|---|---|---|---|
user_id | path | integer | required |
"204 No Content"| Status | Description |
|---|---|
404 | The user does not exist or belongs to a different company. |
422 | Validation Error |
Agents
An agent is a configured AI persona with a name, personality, opening line, and voice. Once published, the agent is reachable on its assigned phone number via voice call, WhatsApp, or both.
/api/agents/
User Key
Create a draft agent
draft status. Call POST /api/agents/{id}/publish to go live.| Field | Type | Required | Description |
|---|---|---|---|
name | string | required | |
personality | string | required | |
opening_line | string | required | |
voice_id | integer | required | |
language | string | optional | Default: en |
config | object? | optional |
{
"name": "Sales Assistant",
"personality": "You are a friendly and professional sales assistant for Acme Corp. You help customers understand our product range and guide them toward the right solution. Be conversational, never pushy.",
"opening_line": "Hi there! Thanks for calling Acme Corp. How can I help you today?",
"voice_id": 1,
"language": "en",
"config": {
"temperature": 0.7,
"max_call_duration_seconds": 600
}
}| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
name | string | required | |
personality | string | required | |
opening_line | string | required | |
voice | object | required | |
language | string | required | |
status | string | required | |
voice_enabled | boolean | required | |
whatsapp_enabled | boolean | required | |
external_agent_id | string? | optional | |
phone_number | object? | optional | |
config | object? | optional | |
created_at | string | required | |
updated_at | string | required |
{
"id": 10,
"company_id": 1,
"name": "Sales Assistant",
"personality": "You are a friendly and professional sales assistant for Acme Corp...",
"opening_line": "Hi there! Thanks for calling Acme Corp. How can I help you today?",
"voice": {
"id": 1,
"name": "Rachel"
},
"language": "en",
"status": "draft",
"voice_enabled": true,
"whatsapp_enabled": false,
"config": {
"temperature": 0.7,
"max_call_duration_seconds": 600
},
"created_at": "2026-03-12T14:30:00Z",
"updated_at": "2026-03-12T14:35:00Z"
}| Status | Description |
|---|---|
422 | Validation Error |
/api/agents/
User Key
List agents
| Name | In | Type | Required | Description |
|---|---|---|---|---|
status | query | string | optional | |
limit | query | integer | optional | Default: 30 |
cursor | query | string | optional |
| Field | Type | Required | Description |
|---|---|---|---|
items | array[object] | required | |
has_more | boolean | required | |
next_cursor | string? | optional |
[
{
"id": 10,
"company_id": 1,
"name": "Sales Assistant",
"personality": "You are a friendly and professional sales assistant for Acme Corp...",
"opening_line": "Hi there! Thanks for calling Acme Corp. How can I help you today?",
"voice": {
"id": 1,
"name": "Rachel"
},
"language": "en",
"status": "active",
"voice_enabled": true,
"whatsapp_enabled": false,
"external_agent_id": "el_abc123",
"phone_number": {
"id": 5,
"number": "+27211234567",
"voice_enabled": true,
"whatsapp_enabled": false,
"whatsapp_status": "none"
},
"config": {
"temperature": 0.7,
"max_call_duration_seconds": 600
},
"created_at": "2026-03-12T14:30:00Z",
"updated_at": "2026-03-12T14:35:00Z"
}
]| Status | Description |
|---|---|
422 | Validation Error |
/api/agents/{agent_id}
User Key
Get agent details
| Name | In | Type | Required | Description |
|---|---|---|---|---|
agent_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
name | string | required | |
personality | string | required | |
opening_line | string | required | |
voice | object | required | |
language | string | required | |
status | string | required | |
voice_enabled | boolean | required | |
whatsapp_enabled | boolean | required | |
external_agent_id | string? | optional | |
phone_number | object? | optional | |
config | object? | optional | |
created_at | string | required | |
updated_at | string | required |
{
"id": 10,
"company_id": 1,
"name": "Sales Assistant",
"personality": "You are a friendly and professional sales assistant for Acme Corp...",
"opening_line": "Hi there! Thanks for calling Acme Corp. How can I help you today?",
"voice": {
"id": 1,
"name": "Rachel"
},
"language": "en",
"status": "active",
"voice_enabled": true,
"whatsapp_enabled": false,
"external_agent_id": "el_abc123",
"phone_number": {
"id": 5,
"number": "+27211234567",
"voice_enabled": true,
"whatsapp_enabled": false,
"whatsapp_status": "none"
},
"config": {
"temperature": 0.7,
"max_call_duration_seconds": 600
},
"created_at": "2026-03-12T14:30:00Z",
"updated_at": "2026-03-12T14:35:00Z"
}| Status | Description |
|---|---|
404 | The agent does not exist or belongs to a different company. |
422 | Validation Error |
/api/agents/{agent_id}
User Key
Update agent
| Name | In | Type | Required | Description |
|---|---|---|---|---|
agent_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
name | string? | optional | |
personality | string? | optional | |
opening_line | string? | optional | |
voice_id | integer? | optional | |
language | string? | optional | |
config | object? | optional |
{
"personality": "You are a friendly and professional sales assistant for Acme Corp. Always mention our current promotion: 20% off all Pro plans this month.",
"opening_line": "Hi! Welcome to Acme Corp -- did you know we have 20% off Pro plans right now? How can I help?"
}| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
name | string | required | |
personality | string | required | |
opening_line | string | required | |
voice | object | required | |
language | string | required | |
status | string | required | |
voice_enabled | boolean | required | |
whatsapp_enabled | boolean | required | |
external_agent_id | string? | optional | |
phone_number | object? | optional | |
config | object? | optional | |
created_at | string | required | |
updated_at | string | required |
{
"id": 10,
"company_id": 1,
"name": "Sales Assistant",
"personality": "You are a friendly and professional sales assistant for Acme Corp...",
"opening_line": "Hi there! Thanks for calling Acme Corp. How can I help you today?",
"voice": {
"id": 1,
"name": "Rachel"
},
"language": "en",
"status": "active",
"voice_enabled": true,
"whatsapp_enabled": false,
"external_agent_id": "el_abc123",
"phone_number": {
"id": 5,
"number": "+27211234567",
"voice_enabled": true,
"whatsapp_enabled": false,
"whatsapp_status": "none"
},
"config": {
"temperature": 0.7,
"max_call_duration_seconds": 600
},
"created_at": "2026-03-12T14:30:00Z",
"updated_at": "2026-03-12T14:35:00Z"
}| Status | Description |
|---|---|
404 | The agent does not exist or belongs to a different company. |
422 | Validation Error |
/api/agents/{agent_id}
User Key
Archive agent
pause instead.| Name | In | Type | Required | Description |
|---|---|---|---|---|
agent_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
name | string | required | |
personality | string | required | |
opening_line | string | required | |
voice | object | required | |
language | string | required | |
status | string | required | |
voice_enabled | boolean | required | |
whatsapp_enabled | boolean | required | |
external_agent_id | string? | optional | |
phone_number | object? | optional | |
config | object? | optional | |
created_at | string | required | |
updated_at | string | required |
{
"id": 10,
"company_id": 1,
"name": "Sales Assistant",
"personality": "You are a friendly and professional sales assistant for Acme Corp...",
"opening_line": "Hi there! Thanks for calling Acme Corp. How can I help you today?",
"voice": {
"id": 1,
"name": "Rachel"
},
"language": "en",
"status": "archived",
"voice_enabled": true,
"whatsapp_enabled": false,
"config": {
"temperature": 0.7,
"max_call_duration_seconds": 600
},
"created_at": "2026-03-12T14:30:00Z",
"updated_at": "2026-03-12T14:35:00Z"
}| Status | Description |
|---|---|
404 | The agent does not exist or belongs to a different company. |
422 | Validation Error |
/api/agents/{agent_id}/publish
User Key
Publish agent
| Name | In | Type | Required | Description |
|---|---|---|---|---|
agent_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
country_code | string | optional | Default: ZA |
{
"country_code": "ZA"
}| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
name | string | required | |
personality | string | required | |
opening_line | string | required | |
voice | object | required | |
language | string | required | |
status | string | required | |
voice_enabled | boolean | required | |
whatsapp_enabled | boolean | required | |
external_agent_id | string? | optional | |
phone_number | object? | optional | |
config | object? | optional | |
created_at | string | required | |
updated_at | string | required |
{
"id": 10,
"company_id": 1,
"name": "Sales Assistant",
"personality": "You are a friendly and professional sales assistant for Acme Corp...",
"opening_line": "Hi there! Thanks for calling Acme Corp. How can I help you today?",
"voice": {
"id": 1,
"name": "Rachel"
},
"language": "en",
"status": "active",
"voice_enabled": true,
"whatsapp_enabled": false,
"external_agent_id": "el_abc123",
"phone_number": {
"id": 5,
"number": "+27211234567",
"voice_enabled": true,
"whatsapp_enabled": false,
"whatsapp_status": "none"
},
"config": {
"temperature": 0.7,
"max_call_duration_seconds": 600
},
"created_at": "2026-03-12T14:30:00Z",
"updated_at": "2026-03-12T14:35:00Z"
}| Status | Description |
|---|---|
404 | The agent does not exist or belongs to a different company. |
422 | Validation Error |
/api/agents/{agent_id}/pause
User Key
Pause agent
| Name | In | Type | Required | Description |
|---|---|---|---|---|
agent_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
name | string | required | |
personality | string | required | |
opening_line | string | required | |
voice | object | required | |
language | string | required | |
status | string | required | |
voice_enabled | boolean | required | |
whatsapp_enabled | boolean | required | |
external_agent_id | string? | optional | |
phone_number | object? | optional | |
config | object? | optional | |
created_at | string | required | |
updated_at | string | required |
{
"id": 10,
"company_id": 1,
"name": "Sales Assistant",
"personality": "You are a friendly and professional sales assistant for Acme Corp...",
"opening_line": "Hi there! Thanks for calling Acme Corp. How can I help you today?",
"voice": {
"id": 1,
"name": "Rachel"
},
"language": "en",
"status": "paused",
"voice_enabled": true,
"whatsapp_enabled": false,
"external_agent_id": "el_abc123",
"phone_number": {
"id": 5,
"number": "+27211234567",
"voice_enabled": true,
"whatsapp_enabled": false,
"whatsapp_status": "none"
},
"config": {
"temperature": 0.7,
"max_call_duration_seconds": 600
},
"created_at": "2026-03-12T14:30:00Z",
"updated_at": "2026-03-12T14:35:00Z"
}| Status | Description |
|---|---|
404 | The agent does not exist or belongs to a different company. |
422 | Validation Error |
/api/agents/{agent_id}/resume
User Key
Resume agent
| Name | In | Type | Required | Description |
|---|---|---|---|---|
agent_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
name | string | required | |
personality | string | required | |
opening_line | string | required | |
voice | object | required | |
language | string | required | |
status | string | required | |
voice_enabled | boolean | required | |
whatsapp_enabled | boolean | required | |
external_agent_id | string? | optional | |
phone_number | object? | optional | |
config | object? | optional | |
created_at | string | required | |
updated_at | string | required |
{
"id": 10,
"company_id": 1,
"name": "Sales Assistant",
"personality": "You are a friendly and professional sales assistant for Acme Corp...",
"opening_line": "Hi there! Thanks for calling Acme Corp. How can I help you today?",
"voice": {
"id": 1,
"name": "Rachel"
},
"language": "en",
"status": "active",
"voice_enabled": true,
"whatsapp_enabled": false,
"external_agent_id": "el_abc123",
"phone_number": {
"id": 5,
"number": "+27211234567",
"voice_enabled": true,
"whatsapp_enabled": false,
"whatsapp_status": "none"
},
"config": {
"temperature": 0.7,
"max_call_duration_seconds": 600
},
"created_at": "2026-03-12T14:30:00Z",
"updated_at": "2026-03-12T14:35:00Z"
}| Status | Description |
|---|---|
404 | The agent does not exist or belongs to a different company. |
422 | Validation Error |
/api/agents/{agent_id}/conversations
User Key
List agent conversations
| Name | In | Type | Required | Description |
|---|---|---|---|---|
agent_id | path | integer | required | |
channel | query | string | optional | |
limit | query | integer | optional | Default: 30 |
cursor | query | string | optional |
| Field | Type | Required | Description |
|---|---|---|---|
items | array[object] | required | |
has_more | boolean | required | |
next_cursor | string? | optional |
{
"items": [
{
"id": 100,
"agent_id": 10,
"company_id": 1,
"channel": "voice",
"caller_number": "+27821234567",
"direction": "inbound",
"started_at": "2026-03-12T16:05:00Z",
"ended_at": "2026-03-12T16:08:32Z",
"duration_seconds": 212,
"message_count": 14,
"status": "completed",
"call_successful": true
}
],
"has_more": true,
"next_cursor": "eyJpZCI6IDk5fQ=="
}| Status | Description |
|---|---|
404 | The agent does not exist or belongs to a different company. |
422 | Validation Error |
/api/agents/{agent_id}/usage
User Key
Get agent usage
| Name | In | Type | Required | Description |
|---|---|---|---|---|
agent_id | path | integer | required | |
start_date | query | string | optional | |
end_date | query | string | optional |
{
"agent_id": 10,
"period": {
"start_date": "2026-03-01",
"end_date": "2026-03-12"
},
"voice": {
"total_conversations": 180,
"total_minutes": 620.3,
"total_sip_refer_minutes": 42.1,
"average_duration_seconds": 206.8,
"success_rate": 0.95
}
}| Status | Description |
|---|---|
404 | The agent does not exist or belongs to a different company. |
422 | Validation Error |
Voices
A curated catalogue of AI voices with preview audio samples. Each voice has attributes like gender, accent, and language. Choose a voice when creating an agent.
/api/voices/
Any Key
List voices
| Name | In | Type | Required | Description |
|---|---|---|---|---|
language | query | string | optional | |
gender | query | string | optional | |
accent | query | string | optional |
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
provider_id | integer | required | |
external_voice_id | string | required | |
name | string | required | |
gender | string? | optional | |
accent | string? | optional | |
language | string | required | |
preview_url | string? | optional | |
tags | object? | optional | |
status | string | required |
[
{
"id": 1,
"provider_id": 1,
"external_voice_id": "21m00Tcm4TlvDq8ikWAM",
"name": "Rachel",
"gender": "female",
"accent": "american",
"language": "en",
"preview_url": "https://cdn.example.com/voices/rachel_preview.mp3",
"tags": {
"style": "conversational",
"tone": "warm"
},
"status": "active"
},
{
"id": 2,
"provider_id": 1,
"external_voice_id": "29vD33N1CtxCmqQRPOHJ",
"name": "James",
"gender": "male",
"accent": "british",
"language": "en",
"preview_url": "https://cdn.example.com/voices/james_preview.mp3",
"tags": {
"style": "authoritative",
"tone": "calm"
},
"status": "active"
}
]| Status | Description |
|---|---|
422 | Validation Error |
/api/voices/{voice_id}
Any Key
Get voice details
| Name | In | Type | Required | Description |
|---|---|---|---|---|
voice_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
provider_id | integer | required | |
external_voice_id | string | required | |
name | string | required | |
gender | string? | optional | |
accent | string? | optional | |
language | string | required | |
preview_url | string? | optional | |
tags | object? | optional | |
status | string | required |
{
"id": 1,
"provider_id": 1,
"external_voice_id": "21m00Tcm4TlvDq8ikWAM",
"name": "Rachel",
"gender": "female",
"accent": "american",
"language": "en",
"preview_url": "https://cdn.example.com/voices/rachel_preview.mp3",
"tags": {
"style": "conversational",
"tone": "warm"
},
"status": "active"
}| Status | Description |
|---|---|
404 | No voice exists with the given ID. |
422 | Validation Error |
Phone Numbers
Phone numbers are provisioned from a pool and assigned to agents during publishing. A single number can serve both voice and WhatsApp channels simultaneously.
/api/phone-numbers/available
User Key
List available phone numbers
| Name | In | Type | Required | Description |
|---|---|---|---|---|
country_code | query | string | optional |
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
number | string | required | |
provider_slug | string | required | |
country_code | string | required | |
status | string | required | |
company_id | integer? | required | |
agent_id | integer? | required | |
whatsapp_status | string | required | |
whatsapp_external_id | string? | required | |
created_at | string | required | |
updated_at | string | required |
[
{
"id": 20,
"number": "+27217654321",
"provider_slug": "sip_trunk",
"country_code": "ZA",
"status": "available",
"whatsapp_status": "none",
"created_at": "2026-03-01T00:00:00Z",
"updated_at": "2026-03-12T14:35:00Z"
}
]| Status | Description |
|---|---|
422 | Validation Error |
/api/phone-numbers/
User Key
List company phone numbers
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
number | string | required | |
provider_slug | string | required | |
country_code | string | required | |
status | string | required | |
company_id | integer? | required | |
agent_id | integer? | required | |
whatsapp_status | string | required | |
whatsapp_external_id | string? | required | |
created_at | string | required | |
updated_at | string | required |
[
{
"id": 5,
"number": "+27211234567",
"provider_slug": "sip_trunk",
"country_code": "ZA",
"status": "assigned",
"company_id": 1,
"agent_id": 10,
"whatsapp_status": "none",
"created_at": "2026-03-01T00:00:00Z",
"updated_at": "2026-03-12T14:35:00Z"
}
]/api/phone-numbers/{phone_number_id}/enable-whatsapp
User Key
Enable WhatsApp
| Name | In | Type | Required | Description |
|---|---|---|---|---|
phone_number_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
number | string | required | |
provider_slug | string | required | |
country_code | string | required | |
status | string | required | |
company_id | integer? | required | |
agent_id | integer? | required | |
whatsapp_status | string | required | |
whatsapp_external_id | string? | required | |
created_at | string | required | |
updated_at | string | required |
{
"id": 5,
"number": "+27211234567",
"provider_slug": "sip_trunk",
"country_code": "ZA",
"status": "assigned",
"company_id": 1,
"agent_id": 10,
"whatsapp_status": "pending",
"created_at": "2026-03-01T00:00:00Z",
"updated_at": "2026-03-12T14:35:00Z"
}| Status | Description |
|---|---|
404 | The phone number does not exist or belongs to a different company. |
422 | Validation Error |
/api/phone-numbers/{phone_number_id}/whatsapp-status
User Key
Check WhatsApp status
| Name | In | Type | Required | Description |
|---|---|---|---|---|
phone_number_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
number | string | required | |
whatsapp_status | string | required |
{
"id": 5,
"number": "+27211234567",
"whatsapp_status": "active"
}| Status | Description |
|---|---|
404 | The phone number does not exist or belongs to a different company. |
422 | Validation Error |
Conversations
A conversation is a single interaction session between an end user and an agent -- either a voice call or a WhatsApp chat. Includes duration, transcript, and usage data.
/api/conversations/
User Key
List conversations
| Name | In | Type | Required | Description |
|---|---|---|---|---|
agent_id | query | string | optional | |
channel | query | string | optional | |
limit | query | integer | optional | Default: 30 |
cursor | query | string | optional |
| Field | Type | Required | Description |
|---|---|---|---|
items | array[object] | required | |
has_more | boolean | required | |
next_cursor | string? | optional |
[
{
"id": 100,
"agent_id": 10,
"company_id": 1,
"channel": "voice",
"caller_number": "+27821234567",
"direction": "inbound",
"started_at": "2026-03-12T16:05:00Z",
"ended_at": "2026-03-12T16:08:32Z",
"duration_seconds": 212,
"message_count": 14,
"status": "completed",
"call_successful": true,
"transcript_summary": "Customer enquired about Pro plan pricing. Agent provided details and offered to send a follow-up email.",
"source": "elevenlabs",
"external_conversation_id": "el_conv_abc123",
"created_at": "2026-03-12T16:05:00Z"
}
]| Status | Description |
|---|---|
422 | Validation Error |
/api/conversations/{conversation_id}
User Key
Get conversation details
| Name | In | Type | Required | Description |
|---|---|---|---|---|
conversation_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
agent_id | integer | required | |
company_id | integer | required | |
channel | string | required | |
caller_number | string? | optional | |
direction | string | required | |
started_at | string | required | |
ended_at | string? | optional | |
duration_seconds | integer? | optional | |
message_count | integer? | optional | |
status | string | required | |
call_successful | boolean? | optional | |
sip_refer_destination | string? | optional | |
transcript_summary | string? | optional | |
source | string | required | |
external_conversation_id | string? | optional | |
created_at | string | required | |
transcript | array? | optional | |
metadata_ | object? | optional |
{
"id": 100,
"agent_id": 10,
"company_id": 1,
"channel": "voice",
"caller_number": "+27821234567",
"direction": "inbound",
"started_at": "2026-03-12T16:05:00Z",
"ended_at": "2026-03-12T16:08:32Z",
"duration_seconds": 212,
"message_count": 14,
"status": "completed",
"call_successful": true,
"transcript_summary": "Customer enquired about Pro plan pricing. Agent provided details and offered to send a follow-up email.",
"source": "elevenlabs",
"external_conversation_id": "el_conv_abc123",
"created_at": "2026-03-12T16:05:00Z",
"transcript": [
{
"role": "agent",
"message": "Hi there! Thanks for calling Acme Corp. How can I help you today?",
"timestamp": 0.0
},
{
"role": "user",
"message": "Hi, I was wondering about your pricing for the Pro plan.",
"timestamp": 3.2
},
{
"role": "agent",
"message": "Great question! Our Pro plan starts at R499 per month and includes...",
"timestamp": 5.8
}
],
"metadata_": {
"llm_tokens": 1240
}
}| Status | Description |
|---|---|
404 | The conversation does not exist or belongs to a different company. |
422 | Validation Error |
Usage
Track voice minutes, WhatsApp messages, and SIP refer minutes aggregated by company, agent, and date range.
/api/usage/summary
Any Key
Get usage summary
| Name | In | Type | Required | Description |
|---|---|---|---|---|
start_date | query | string | optional | |
end_date | query | string | optional |
| Field | Type | Required | Description |
|---|---|---|---|
period | object | required | |
voice | object | required | |
agents_active | integer | optional | Default: 0 |
by_agent | array[AgentUsageBreakdown] | optional | Default: [] |
{
"period": {
"start_date": "2026-03-01",
"end_date": "2026-03-12"
},
"voice": {
"total_conversations": 342,
"total_minutes": 1205.7,
"total_sip_refer_minutes": 87.3
},
"whatsapp": {
"total_conversations": 156,
"total_messages": 2840
}
}| Status | Description |
|---|---|
422 | Validation Error |
/api/usage/daily
Any Key
Get daily usage breakdown
| Name | In | Type | Required | Description |
|---|---|---|---|---|
start_date | query | string | required | Start date |
end_date | query | string | required | End date |
agent_id | query | string | optional |
| Field | Type | Required | Description |
|---|---|---|---|
date | string | required | |
voice | object | required |
[
{
"date": "2026-03-11",
"voice": {
"total_conversations": 31,
"total_minutes": 112.4,
"total_sip_refer_minutes": 8.2
},
"whatsapp": {
"total_conversations": 18,
"total_messages": 245
}
},
{
"date": "2026-03-12",
"voice": {
"total_conversations": 47,
"total_minutes": 156.3,
"total_sip_refer_minutes": 12.5
},
"whatsapp": {
"total_conversations": 23,
"total_messages": 312
}
}
]| Status | Description |
|---|---|
422 | Validation Error |
Webhooks
Register HTTPS endpoints to receive real-time events when conversations complete, agents change status, or WhatsApp verification finishes.
/api/webhooks/
Company Key
List webhooks
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
url | string | required | |
events | array[object] | required | |
status | string | required | |
created_at | string | required | |
updated_at | string | required |
[
{
"id": 1,
"company_id": 1,
"url": "https://your-app.com/webhooks/cxco",
"events": [
"conversation.completed",
"agent.status_changed"
],
"status": "active",
"created_at": "2026-03-12T10:00:00Z",
"updated_at": "2026-03-12T10:00:00Z"
}
]/api/webhooks/
Company Key
Register webhook
| Field | Type | Required | Description |
|---|---|---|---|
url | string | required | |
events | array[string] | required | |
secret | string? | optional |
{
"url": "https://your-app.com/webhooks/cxco",
"events": [
"conversation.completed",
"agent.status_changed"
],
"secret": "whsec_your_secret_key"
}| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
url | string | required | |
events | array[object] | required | |
status | string | required | |
created_at | string | required | |
updated_at | string | required |
{
"id": 1,
"company_id": 1,
"url": "https://your-app.com/webhooks/cxco",
"events": [
"conversation.completed",
"agent.status_changed"
],
"status": "active",
"created_at": "2026-03-12T10:00:00Z",
"updated_at": "2026-03-12T10:00:00Z"
}| Status | Description |
|---|---|
422 | Validation Error |
/api/webhooks/{webhook_id}
Company Key
Update webhook
| Name | In | Type | Required | Description |
|---|---|---|---|---|
webhook_id | path | integer | required |
| Field | Type | Required | Description |
|---|---|---|---|
url | string? | optional | |
events | array? | optional | |
status | string? | optional |
{
"url": "https://your-app.com/webhooks/cxco-v2",
"events": [
"conversation.completed",
"conversation.transferred",
"agent.status_changed"
]
}| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
url | string | required | |
events | array[object] | required | |
status | string | required | |
created_at | string | required | |
updated_at | string | required |
{
"id": 1,
"company_id": 1,
"url": "https://your-app.com/webhooks/cxco-v2",
"events": [
"conversation.completed",
"conversation.transferred",
"agent.status_changed"
],
"status": "active",
"created_at": "2026-03-12T10:00:00Z",
"updated_at": "2026-03-13T09:00:00Z"
}| Status | Description |
|---|---|
422 | Validation Error |
/api/webhooks/{webhook_id}
Company Key
Delete webhook
| Name | In | Type | Required | Description |
|---|---|---|---|---|
webhook_id | path | integer | required |
"204 No Content"| Status | Description |
|---|---|
422 | Validation Error |
Providers
View available service providers (voice, SIP, messaging) and securely store your provider credentials. Credentials are encrypted at rest with AES-256.
/api/providers/
Company Key
List providers
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
slug | string | required | |
name | string | required | |
type | string | required | |
status | string | required | |
config | object? | optional |
[
{
"id": 1,
"slug": "elevenlabs",
"name": "ElevenLabs",
"type": "voice_provider",
"status": "active"
},
{
"id": 2,
"slug": "sip_trunk",
"name": "SIP Trunk Provider",
"type": "sip_trunk",
"status": "active"
}
]/api/providers/{slug}/credentials
Company Key
Store provider credentials
| Name | In | Type | Required | Description |
|---|---|---|---|---|
slug | path | string | required |
| Field | Type | Required | Description |
|---|---|---|---|
company_id | integer | required | |
credentials | object | required |
{
"company_id": 1,
"credentials": {
"api_key": "sk-elevenlabs-abc123..."
}
}| Field | Type | Required | Description |
|---|---|---|---|
id | integer | required | |
company_id | integer | required | |
provider_id | integer | required | |
status | string | required | |
created_at | string | required |
{
"id": 1,
"company_id": 1,
"provider_id": 1,
"status": "active",
"created_at": "2026-03-12T10:00:00Z"
}| Status | Description |
|---|---|
409 | Credentials already exist for this company and provider combination. |
422 | Validation Error |