KaiCalls API
Give your AI agent a phone. Make outbound calls, manage agents, and integrate AI phone assistants into your applications.
https://kaicalls.com/api/v1Send Your AI Agent to KaiCalls📞
Your agent signs up, gets a phone number, and starts taking calls — no human setup required.
Send this to your agent
Copy the instruction below
They sign up via the API
Gets API key + phone number
Agent starts making calls
30-day free trial, no card
Click to copy — paste into Claude, ChatGPT, or any AI agent chat
Quick Start
1. Get your API key
Go to Dashboard → Settings → API Keys and generate a key.
2. Make your first call
curl -X POST https://kaicalls.com/api/v1/calls \
-H "Authorization: Bearer kc_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "your-agent-id",
"to": "+15125551234",
"name": "John Smith",
"context": "Confirm appointment for tomorrow at 2pm"
}'3. Check the result
curl "https://kaicalls.com/api/v1/calls?id=CALL_ID" \
-H "Authorization: Bearer kc_live_xxxxx"Authentication
All API requests require a Bearer token in the Authorization header.
Authorization: Bearer kc_live_xxxxxKey Prefixes
kc_live_— Production keyskc_test_— Sandbox keys (coming soon)
Scopes
Keys are created with scopes that control access. Default scopes are granted automatically.
| Parameter | Type | Description |
|---|---|---|
agents:read | scope | List and view agents |
agents:write | scope | Create and update agents |
numbers:read | scope | List phone numbers |
calls:read | scope | List and view call records |
calls:write | scope | Make outbound calls |
sms:read | scope | List and view SMS messages |
sms:write | scope | Send SMS messages |
emails:read | scope | List and view email queue |
emails:write | scope | Send and auto-approve emails |
* | scope | Full access (all scopes) |
Signup
Create a full KaiCalls account via the API — no UI session required. This endpoint provisions a business, generates an API key, creates an AI agent, and assigns a phone number in a single call.
/api/v1/signupCreate a new accountNo authentication required. Provisions a complete account: auth user, business, API key, AI intake agent, and phone number from the available pool. Returns everything needed to start making API calls immediately.
Rate limit: 5 requests/hour per IP
Parameters
| Parameter | Type | Description |
|---|---|---|
business_namerequired | string | Name of the business |
emailrequired | string | Account email address (must be unique) |
business_type | string | Category of business (e.g. "Legal Services", "Healthcare") |
website | string | Business website URL |
phone_forward_to | string | Phone number to forward calls to (sets up ring-first routing — AI answers if no pickup after 20s) |
Example
curl -X POST https://kaicalls.com/api/v1/signup \
-H "Content-Type: application/json" \
-d '{
"business_name": "Smith Law Firm",
"email": "contact@smithlaw.com",
"business_type": "Legal Services",
"website": "https://smithlaw.com",
"phone_forward_to": "+15125551234"
}'Response
{
"api_key": "kc_live_abc123def456...",
"business_id": "uuid-biz456",
"agent_id": "uuid-agent789",
"phone_number": "+15125559876",
"dashboard_url": "https://kaicalls.com/dashboard",
"trial_ends_at": "2026-04-14T00:00:00.000Z"
}Error Responses
| Code | Status | Description |
|---|---|---|
validation_error | 400 | Missing or invalid business_name or email |
email_exists | 409 | An account with this email already exists |
rate_limited | 429 | Too many signups from this IP (5/hour limit) |
payment_required | 402 | x402 payment required (when enabled) |
What Gets Created
- Auth user with auto-confirmed email
- Business with 30-day free trial
- API key with full default scopes
- AI intake agent (ready to take calls)
- Phone number from pool (with Vapi + Twilio)
- Call forwarding (if
phone_forward_toprovided)
Agents
/api/v1/agentsList all agentsReturns all agents assigned to your businesses. Requires agents:read scope.
{
"agents": [
{
"id": "uuid-abc123",
"name": "Kai",
"business_id": "uuid-biz456",
"created_at": "2026-01-15T10:00:00Z"
}
]
}/api/v1/agents?id=AGENT_IDGet agent detailsReturns detailed info including prompts (inbound/outbound/SMS), voice, model, Vapi assistant ID, and phone number. The inbound prompt is fetched live from Vapi.
{
"id": "uuid-abc123",
"name": "Kai",
"business_id": "uuid-biz456",
"vapi_assistant_id": "vapi-asst-789",
"phone_number": "+15125551234",
"created_at": "2026-01-15T10:00:00Z",
"prompts": {
"inbound": {
"prompt": "You are a friendly receptionist for Smith Law...",
"llm": "gpt-4.1"
},
"outbound": {
"prompt": "You are calling {{name}} to follow up...",
"llm": "gpt-4.1",
"first_message": "Hey {{name}}, this is Kai from Smith Law."
},
"sms": {
"prompt": "Respond helpfully to text messages...",
"llm": "gpt-4.1"
}
},
"voice": { "provider": "elevenlabs", "voiceId": "voice-id-123" },
"model": { "provider": "openai", "model": "gpt-4.1", "temperature": 0.7 },
"first_message": "Hello! How can I help you today?"
}/api/v1/agentsCreate a new voice agentCreates a Vapi assistant with lead collection capabilities and registers the agent in the KaiCalls database. If database insertion fails, the Vapi assistant is automatically cleaned up.
Required scope: agents:write
Parameters
| Parameter | Type | Description |
|---|---|---|
business_idrequired | string | Business to assign the agent to (must be accessible by your API key) |
namerequired | string | Agent display name |
system_promptrequired | string | The agent's system prompt / instructions |
first_message | string | Greeting message (default: "Hello! How can I help you today?") |
voice | object | Voice configuration: { provider, voiceId } (defaults to Vapi default) |
model | object | Model configuration: { provider, model, temperature } (defaults to OpenAI gpt-4.1 at 0.7) |
metadata | object | Extra metadata to store with the agent (e.g. description, custom fields) |
Example
curl -X POST https://kaicalls.com/api/v1/agents \
-H "Authorization: Bearer kc_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"business_id": "uuid-biz456",
"name": "Kai Receptionist",
"system_prompt": "You are a friendly receptionist for Smith Law. Answer questions about services and collect caller information.",
"first_message": "Hello! Thanks for calling Smith Law. How can I help you today?",
"voice": { "provider": "elevenlabs", "voiceId": "voice-id-123" },
"model": { "provider": "openai", "model": "gpt-4.1", "temperature": 0.7 }
}'{
"id": "uuid-agent789",
"name": "Kai Receptionist",
"business_id": "uuid-biz456",
"vapi_assistant_id": "vapi-asst-xyz",
"created_at": "2026-03-06T10:00:00Z"
}Automatic Lead Collection
Every agent created via the API automatically includes lead collection capabilities. The agent will extract caller name, email, phone, and intent during conversations without any additional configuration.
/api/v1/agentsUpdate an existing agentPartial updates to agent configuration. Only include the fields you want to change. Changes are synced to both the Vapi assistant and the KaiCalls database. Metadata updates are merged with existing values (not replaced).
Agents have separate prompts per channel: inbound (incoming calls, synced to Vapi), outbound (AI-initiated calls, applied at call time), and SMS (text responses).
Required scope: agents:write
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequired | string | KaiCalls agent ID to update |
name | string | New agent display name |
inbound_prompt | string | System prompt for incoming calls (synced to Vapi + metadata) |
outbound_prompt | string | System prompt for outbound calls (metadata only, applied at call time) |
sms_prompt | string | System prompt for SMS responses (metadata only) |
system_prompt | string | Legacy alias for inbound_prompt (still supported) |
first_message | string | New greeting message for inbound calls |
outbound_first_message | string | Custom opening message for outbound calls |
outbound_llm | string | Override model for outbound calls (e.g. gpt-4.1) |
sms_llm | string | Override model for SMS (e.g. gpt-4.1) |
voice | object | New voice configuration: { provider, voiceId } |
model | object | New model configuration: { provider, model, temperature } |
metadata | object | Metadata to merge with existing values |
vapi_config | object | Direct Vapi assistant config passthrough. Any valid Vapi field is accepted: stopSpeakingPlan, startSpeakingPlan, endCallPhrases, endCallMessage, transcriber, analysisPlan, artifactPlan, backgroundSpeechDenoisingPlan, monitorPlan, silenceTimeoutSeconds, maxDurationSeconds, etc. Sanitized and forwarded to Vapi. |
Example (update inbound prompt)
curl -X PATCH https://kaicalls.com/api/v1/agents \
-H "Authorization: Bearer kc_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"id": "uuid-agent789",
"inbound_prompt": "You are an intake specialist. Collect case details and schedule consultations."
}'Example (update outbound prompt)
curl -X PATCH https://kaicalls.com/api/v1/agents \
-H "Authorization: Bearer kc_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"id": "uuid-agent789",
"outbound_prompt": "You are calling {{name}} about their inquiry. Qualify and book a consultation.",
"outbound_first_message": "Hey {{name}}, this is Kai from Smith Law — do you have a minute?"
}'Example (Vapi config — interruption handling)
curl -X PATCH https://kaicalls.com/api/v1/agents \
-H "Authorization: Bearer kc_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"id": "uuid-agent789",
"vapi_config": {
"stopSpeakingPlan": {
"numWords": 2,
"voiceSeconds": 0.3,
"backoffSeconds": 1,
"interruptionPhrases": ["stop", "wait", "hold on", "shut up", "enough", "no", "actually"],
"acknowledgementPhrases": ["okay", "yeah", "right", "uh-huh", "mm-hmm", "got it"]
},
"endCallPhrases": ["goodbye", "talk to you later", "have a nice day"],
"endCallMessage": "Thanks for calling! Goodbye."
}
}'{
"id": "uuid-agent789",
"name": "Kai Receptionist",
"business_id": "uuid-biz456",
"vapi_assistant_id": "vapi-asst-xyz",
"updated": true,
"updated_fields": ["inbound_prompt"]
}Phone Numbers
/api/v1/numbersList phone numbersReturns all phone numbers registered to your businesses. Requires numbers:read scope.
{
"numbers": [
{
"id": "uuid-num789",
"phone_number": "+15125551234",
"agent_id": "uuid-abc123",
"business_id": "uuid-biz456",
"created_at": "2026-01-15T10:00:00Z"
}
]
}Calls
/api/v1/callsMake an outbound callInitiates an outbound call using your AI agent. The system automatically enriches the call with context from your CRM — the agent will know the caller's name, lead score, interaction history, and business details.
Required scope: calls:write
Parameters
| Parameter | Type | Description |
|---|---|---|
agent_idrequired | string | The agent to use for this call |
torequired | string | Phone number to call (E.164 format, e.g. +15125551234) |
name | string | Customer name. The agent greets them by name. Also accepts customer_name. |
context | string | Freeform context the agent can reference. Use for task instructions, appointment details, or notes. |
firstMessage | string | Override the agent's opening line for this call. Also accepts first_message. If omitted, uses the agent's configured outbound greeting. |
lead_id | string | Link this call to a lead in your CRM. Enables automatic enrichment with lead score, history, and source. |
webhook_url | string | URL to receive a webhook when the call completes |
max_duration | integer | Maximum call duration in seconds (default: 600) |
Automatic Context Enrichment
When you provide a lead_id or the to number matches an existing lead, the agent automatically receives these variables in its prompt:
| Variable | Description |
|---|---|
name | Lead's first name (from name param or CRM) |
lead_score | AI-assigned quality score (0-100) |
lead_status | Current lead status in your pipeline |
interaction_count | Number of previous calls with this lead |
days_since_first_contact | Days since the lead was first created |
lead_source | Where the lead came from (web form, referral, etc.) |
business_name | Your business name |
business_phone | Your office phone number |
time_of_day | "morning", "afternoon", or "evening" |
These are injected automatically — you don't need to pass them.
Minimal Example
curl -X POST https://kaicalls.com/api/v1/calls \
-H "Authorization: Bearer kc_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{"agent_id": "uuid-abc123", "to": "+15125559876"}'Full Example (with context and lead)
curl -X POST https://kaicalls.com/api/v1/calls \
-H "Authorization: Bearer kc_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "uuid-abc123",
"to": "+15125559876",
"name": "John Smith",
"lead_id": "uuid-lead123",
"context": "Following up on car accident case",
"firstMessage": "Hey John, this is Kai from Smith Law — do you have a minute?"
}'{
"id": "uuid-call789",
"conversation_id": "vapi-conv-xyz",
"status": "queued",
"agent_id": "uuid-abc123",
"to": "+15125559876",
"name": "John Smith",
"created_at": "2026-02-15T14:30:00Z"
}/api/v1/callsList callsReturns calls across all your businesses, ordered by most recent. Requires calls:read scope.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
limit | integer | Max results per page (default: 50, max: 100) |
agent_id | string | Filter by agent ID |
status | string | Filter by call status |
after | string | Cursor-based pagination. Pass the created_at of the last result to get the next page. |
{
"calls": [
{
"id": "uuid-call789",
"conversation_id": "vapi-conv-xyz",
"status": "completed",
"duration": 127,
"agent_id": "uuid-abc123",
"agent_name": "Kai",
"created_at": "2026-02-15T14:30:00Z"
}
],
"has_more": true
}/api/v1/calls?id=CALL_IDGet call detailsReturns full details for a single call including summary, recording, and quality analysis.
{
"id": "uuid-call789",
"conversation_id": "vapi-conv-xyz",
"status": "completed",
"direction": "inbound",
"duration": 127,
"agent_id": "uuid-abc123",
"agent_name": "Kai",
"business_id": "uuid-biz456",
"lead_id": "uuid-lead123",
"summary": "Confirmed appointment with John for tomorrow at 2pm.",
"recording_url": "https://storage.example.com/recordings/call_xyz.mp3",
"quality_dimensions": {
"professionalism": 92,
"empathy": 88,
"information_gathering": 95,
"resolution": 90
},
"created_at": "2026-02-15T14:30:00Z"
}Leads
/api/v1/leadsList leadsReturns leads across all your businesses, ordered by most recent. Requires leads:read scope.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: new, contacted, qualified, converted, lost |
source | string | Filter by lead source |
agent_id | string | Filter by agent ID |
phone | string | Filter by exact phone number |
email | string | Filter by exact email address |
limit | integer | Max results per page (default: 50, max: 100) |
after | string | Cursor-based pagination. Pass the created_at of the last result to get the next page. |
Example
curl "https://kaicalls.com/api/v1/leads?status=new&limit=10" \
-H "Authorization: Bearer kc_live_xxxxx"{
"leads": [
{
"id": "uuid-lead123",
"name": "Jane Doe",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com",
"phone": "+15551234567",
"status": "new",
"source": "inbound_call",
"agent_id": "uuid-abc123",
"agent_name": "Reception AI",
"business_id": "uuid-biz456",
"created_at": "2026-03-17T12:00:00Z",
"updated_at": "2026-03-17T12:00:00Z"
}
],
"has_more": false
}/api/v1/leads?id=LEAD_IDGet lead detailsReturns full details for a single lead including address, notes, and event info.
{
"id": "uuid-lead123",
"name": "Jane Doe",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com",
"phone": "+15551234567",
"zip": "90210",
"address": "123 Main St",
"city": "Beverly Hills",
"state": "CA",
"status": "qualified",
"source": "inbound_call",
"source_url": null,
"source_page": null,
"agent_id": "uuid-abc123",
"agent_name": "Reception AI",
"business_id": "uuid-biz456",
"notes": "Interested in premium plan",
"message": null,
"event_date": null,
"event_type": null,
"created_at": "2026-03-17T12:00:00Z",
"updated_at": "2026-03-17T14:30:00Z"
}/api/v1/leadsUpdate a leadUpdate a lead's information. Only provided fields are modified. Requires leads:write scope.
Body Parameters
| Parameter | Type | Description |
|---|---|---|
idrequired | string | Lead ID to update |
name | string | Full name |
first_name | string | First name |
last_name | string | Last name |
email | string | Email address |
phone | string | Phone number |
status | string | new, contacted, qualified, converted, or lost |
source | string | Lead source |
notes | string | Internal notes |
address | string | Street address |
city | string | City |
state | string | State |
zip | string | ZIP code |
Example
curl -X PATCH https://kaicalls.com/api/v1/leads \
-H "Authorization: Bearer kc_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"id": "uuid-lead123",
"status": "qualified",
"notes": "Ready for follow-up call"
}'{
"id": "uuid-lead123",
"name": "Jane Doe",
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com",
"phone": "+15551234567",
"zip": "90210",
"address": "123 Main St",
"city": "Beverly Hills",
"state": "CA",
"status": "qualified",
"source": "inbound_call",
"agent_id": "uuid-abc123",
"agent_name": "Reception AI",
"business_id": "uuid-biz456",
"notes": "Ready for follow-up call",
"created_at": "2026-03-17T12:00:00Z",
"updated_at": "2026-03-17T15:45:00Z"
}SMS
/api/v1/sms/sendSend an outbound SMSSends an SMS via Twilio using the agent's assigned phone number. Includes DNC and consent compliance checks before sending. Messages are logged to the conversation thread.
Required scope: sms:write
Parameters
| Parameter | Type | Description |
|---|---|---|
torequired | string | Recipient phone number (E.164 format, e.g. +15125551234) |
from_agent_idrequired | string | Agent UUID — the agent's Twilio number is used as the sender |
messagerequired | string | Text message content |
lead_id | string | Optional lead UUID to link the message to a conversation thread |
Example
curl -X POST https://kaicalls.com/api/v1/sms/send \
-H "Authorization: Bearer kc_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"to": "+15125559876",
"from_agent_id": "uuid-agent789",
"message": "Hi John, just following up on our call. Let me know if you have any questions!",
"lead_id": "uuid-lead123"
}'{
"success": true,
"message_sid": "SM1234567890abcdef",
"to": "+15125559876",
"from": "+15125551234"
}| Error Code | Status | Description |
|---|---|---|
number_on_dnc | 400 | Recipient is on the Do-Not-Call list |
number_opted_out | 400 | Recipient has not opted in to SMS |
not_found | 404 | Agent not found or has no phone number |
sms_send_failed | 500 | Twilio failed to deliver the message |
/api/v1/sms/update-promptUpdate an agent's SMS promptUpdates the SMS auto-reply prompt for an agent. Useful for AI agents that need to adjust their own follow-up messaging programmatically. Changes are logged to the audit trail.
Required scope: agents:write
Parameters
| Parameter | Type | Description |
|---|---|---|
agent_idrequired | string | Agent UUID to update |
sms_promptrequired | string | New SMS system prompt text |
reason | string | Optional audit reason for the change |
Example
curl -X POST https://kaicalls.com/api/v1/sms/update-prompt \
-H "Authorization: Bearer kc_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "uuid-agent789",
"sms_prompt": "You are a helpful legal assistant. Respond to text messages professionally and help schedule consultations.",
"reason": "Switching to consultation-focused messaging"
}'{
"success": true,
"agent_id": "uuid-agent789",
"message": "SMS prompt updated"
}API Keys
Key management uses session authentication (dashboard login), not API key auth.
/api/v1/keysList your API keys{
"keys": [
{
"id": "uuid-key123",
"prefix": "kc_live_abc1",
"name": "Production Key",
"scopes": ["agents:read", "agents:write", "numbers:read", "calls:read", "calls:write", "sms:read", "sms:write", "emails:read", "emails:write"],
"business_id": null,
"created_at": "2026-01-15T10:00:00Z",
"last_used_at": "2026-02-15T14:30:00Z",
"expires_at": null,
"is_active": true
}
]
}/api/v1/keysCreate a new keyThe full key is returned only once — store it securely.
| Parameter | Type | Description |
|---|---|---|
name | string | Human-readable name (default: "Untitled Key") |
business_id | string | Scope key to a single business. If omitted, key accesses all your businesses. |
scopes | string[] | Permission scopes. Defaults to all standard scopes (agents, numbers, calls, sms, emails). |
{
"key": "kc_live_abc123def456...",
"id": "uuid-key123",
"prefix": "kc_live_abc1",
"name": "My Integration Key",
"scopes": ["agents:read", "agents:write", "numbers:read", "calls:read", "calls:write", "sms:read", "sms:write", "emails:read", "emails:write"],
"business_id": "uuid-biz456",
"created_at": "2026-02-15T14:30:00Z"
}/api/v1/keys?id=KEY_IDRevoke a keyRevokes an API key. The key immediately stops working.
{ "success": true }Analytics
Aggregate analytics endpoints for dashboards, reports, and monitoring. All endpoints auto-scope to the API key's business(es).
/api/v1/analytics/dashboardDashboard summaryComprehensive snapshot: leads, calls, conversion rates, and top agents.
| Parameter | Type | Description |
|---|---|---|
days | integer | Look-back period in days (default: 30, max: 90) |
{
"period": { "days": 30, "since": "2026-02-16T00:00:00Z" },
"leads": {
"total": 142,
"by_status": { "new": 45, "contacted": 38, "qualified": 32, "converted": 18, "lost": 9 },
"conversion_rate": 35.21,
"recent": [{ "id": "uuid-1", "name": "Jane Doe", "status": "new", "source": "website", "created_at": "..." }]
},
"calls": {
"total": 387,
"completed": 351,
"total_duration_seconds": 48200,
"avg_duration_seconds": 125
},
"agents": {
"total": 3,
"top_by_calls": [{ "agent_id": "uuid-a1", "name": "Kai", "count": 215, "total_duration": 28000, "avg_duration": 130 }]
}
}/api/v1/analytics/callsCall analyticsCall volume, outcomes, and avg duration grouped by day or week.
| Parameter | Type | Description |
|---|---|---|
days | integer | Look-back period (default: 30, max: 90) |
group_by | string | "day" (default) or "week" |
agent_id | string | Filter by agent |
{
"period": { "days": 7, "since": "...", "group_by": "day" },
"summary": { "total_calls": 87, "total_duration_seconds": 11200, "avg_duration_seconds": 129 },
"timeline": [
{ "date": "2026-03-12", "total": 14, "completed": 12, "total_duration": 1800, "avg_duration_seconds": 129, "statuses": { "ended": 12, "no-answer": 2 } }
]
}/api/v1/analytics/funnelConversion funnelLead conversion funnel: new → contacted → qualified → converted. Requires leads:read scope.
| Parameter | Type | Description |
|---|---|---|
days | integer | Look-back period (default: 30, max: 90) |
source | string | Filter by lead source |
{
"period": { "days": 30, "since": "..." },
"total_leads": 142,
"lost": 9,
"funnel": [
{ "stage": "new", "count": 133, "rate_from_top": 93.66, "dropoff_rate": 0 },
{ "stage": "contacted", "count": 88, "rate_from_top": 61.97, "dropoff_rate": 33.83 },
{ "stage": "qualified", "count": 50, "rate_from_top": 35.21, "dropoff_rate": 43.18 },
{ "stage": "converted", "count": 18, "rate_from_top": 12.68, "dropoff_rate": 64 }
]
}/api/v1/analytics/agentsAgent performancePer-agent stats: call count, avg duration, lead conversion.
| Parameter | Type | Description |
|---|---|---|
days | integer | Look-back period (default: 30, max: 90) |
agent_id | string | Filter to a single agent |
{
"period": { "days": 30, "since": "..." },
"agents": [
{
"agent_id": "uuid-a1",
"agent_name": "Kai",
"calls": { "total": 215, "completed": 198, "avg_duration_seconds": 130, "total_duration_seconds": 28000 },
"leads": { "total": 89, "converted": 18, "conversion_rate": 20.22 }
}
]
}/api/v1/analytics/weeklyWeekly reportThis week vs. last week comparison with percent changes.
{
"period": {
"this_week": { "start": "2026-03-11T...", "end": "2026-03-18T..." },
"last_week": { "start": "2026-03-04T...", "end": "2026-03-11T..." }
},
"calls": {
"this_week": { "total": 87, "completed": 79, "total_duration_seconds": 11200, "avg_duration_seconds": 129 },
"last_week": { "total": 72, "completed": 65, "total_duration_seconds": 9100, "avg_duration_seconds": 126 },
"change": { "total": 20.83, "completed": 21.54, "avg_duration": 2.38 }
},
"leads": {
"this_week": { "total": 34, "converted": 6, "conversion_rate": 17.65 },
"last_week": { "total": 28, "converted": 4, "conversion_rate": 14.29 },
"change": { "total": 21.43, "converted": 50 }
},
"top_agents": [{ "agent_id": "uuid-a1", "agent_name": "Kai", "total_calls": 52, "total_duration_seconds": 6800 }]
}/api/v1/analytics/businessesBusiness performancePer-business breakdown for multi-tenant accounts.
| Parameter | Type | Description |
|---|---|---|
days | integer | Look-back period (default: 30, max: 90) |
{
"period": { "days": 30, "since": "..." },
"businesses": [
{
"business_id": "uuid-biz1",
"business_name": "Smith Law Firm",
"calls": { "total": 215, "completed": 198, "avg_duration_seconds": 130 },
"leads": { "total": 89, "converted": 18, "conversion_rate": 20.22 }
}
]
}Transcripts
/api/v1/transcriptsGet call transcriptsRecent call transcripts with summaries. Only returns calls that have a transcript.
| Parameter | Type | Description |
|---|---|---|
limit | integer | Max results (default: 20, max: 50) |
agent_id | string | Filter by agent |
after | string | Cursor pagination — created_at of last item |
days | integer | Look-back period (default: 30, max: 90) |
{
"transcripts": [
{
"call_id": "uuid-call1",
"conversation_id": "vapi-conv-123",
"agent_id": "uuid-a1",
"agent_name": "Kai",
"status": "ended",
"duration": 185,
"summary": "Caller inquired about pricing for estate planning services...",
"transcript": "Agent: Hello! How can I help you today?\nCaller: Hi, I'm looking for...",
"created_at": "2026-03-17T14:30:00Z"
}
],
"has_more": true
}Account
/api/v1/balanceGet subscription infoReturns usage and subscription status for each of your businesses.
{
"businesses": [
{
"business_id": "uuid-biz456",
"minutes_used": 412,
"phone_numbers": 2,
"subscription_status": "active"
}
]
}/api/v1/usageGet API usage logReturns your API call history.
| Parameter | Type | Description |
|---|---|---|
start | string | ISO 8601 start date filter |
end | string | ISO 8601 end date filter |
limit | integer | Max results (default: 100, max: 500) |
{
"usage": [
{
"id": "uuid-log123",
"endpoint": "/v1/calls",
"method": "POST",
"status_code": 201,
"call_id": "uuid-call789",
"cost_cents": 15,
"created_at": "2026-02-15T14:30:00Z"
}
],
"has_more": false
}Webhooks
Pass a webhook_url when making a call to receive events when the call completes or fails.
call.completed
{
"event": "call.completed",
"call_id": "uuid-call789",
"status": "completed",
"duration": 127,
"recording_url": "https://...",
"summary": "Confirmed appointment for tomorrow at 2pm.",
"timestamp": "2026-02-15T14:32:12Z"
}call.failed
{
"event": "call.failed",
"call_id": "uuid-call789",
"status": "failed",
"error": "no_answer",
"timestamp": "2026-02-15T14:31:00Z"
}Errors
All errors follow a consistent format:
{
"error": {
"code": "error_code",
"message": "Human-readable description"
}
}| Code | Status | Description |
|---|---|---|
unauthorized | 401 | Invalid, missing, expired, or revoked API key |
forbidden | 403 | Key doesn't have the required scope |
not_found | 404 | Agent, call, or resource not found |
invalid_request | 400 | Missing required fields or invalid JSON |
validation_error | 400 | Field validation failed (e.g. invalid email) |
email_exists | 409 | Email already registered (signup) |
number_on_dnc | 400 | Recipient is on the Do-Not-Call list (SMS) |
number_opted_out | 400 | Recipient has not opted in (SMS) |
sms_send_failed | 500 | Twilio failed to deliver the SMS |
vapi_error | 4xx/5xx | Vapi API call failed (create/update agent) |
call_failed | 500 | Vapi failed to initiate the call |
payment_required | 402 | x402 payment required (signup, when enabled) |
internal_error | 500 | Unexpected server error |
rate_limited | 429 | Too many requests — slow down |
Rate Limits
| Endpoint | Limit |
|---|---|
| POST /v1/calls | 60 requests/minute |
| POST /v1/agents | 30 requests/minute |
| PATCH /v1/agents | 60 requests/minute |
| POST /v1/signup | 5 requests/hour per IP |
| POST /v1/sms/send | 60 requests/minute |
| GET /v1/analytics/* | 120 requests/minute |
| GET /v1/transcripts | 120 requests/minute |
| All other GET endpoints | 300 requests/minute |
SDKs
Python
pip install kaicallsfrom kaicalls import KaiCalls
kai = KaiCalls(api_key="kc_live_xxx")
# Simple call — agent auto-enriches with CRM data
call = kai.calls.create(
agent_id="uuid-abc123",
to="+15125551234",
name="John Smith"
)
# Full call with lead linking and custom opening
call = kai.calls.create(
agent_id="uuid-abc123",
to="+15125551234",
name="John Smith",
lead_id="uuid-lead123",
context="Following up on car accident case",
first_message="Hey John, this is Kai — do you have a minute?"
)
result = kai.calls.wait(call.id)
print(result.summary)
# Create an agent
agent = kai.agents.create(
business_id="uuid-biz456",
name="Kai Receptionist",
system_prompt="You are a friendly receptionist for Smith Law.",
first_message="Hello! How can I help you today?"
)
# Update per-channel prompts
kai.agents.update(
id=agent.id,
inbound_prompt="Updated inbound instructions.",
outbound_prompt="Updated outbound instructions.",
sms_prompt="Updated SMS instructions."
)
# Update Vapi config directly (interruption, end-call, transcriber, etc.)
kai.agents.update(
id=agent.id,
vapi_config={
"stopSpeakingPlan": {
"numWords": 2,
"interruptionPhrases": ["stop", "wait", "hold on", "no"],
"acknowledgementPhrases": ["okay", "yeah", "right"]
},
"endCallPhrases": ["goodbye", "have a nice day"]
}
)
# Send an SMS
kai.sms.send(
to="+15125551234",
from_agent_id="uuid-abc123",
message="Hi John, following up on our call!",
lead_id="uuid-lead123"
)JavaScript / TypeScript
npm install kaicallsimport { KaiCalls } from 'kaicalls';
const kai = new KaiCalls({ apiKey: 'kc_live_xxx' });
// Simple call
const call = await kai.calls.create({
agentId: 'uuid-abc123',
to: '+15125551234',
name: 'John Smith',
});
// Full call with lead linking and custom opening
const call = await kai.calls.create({
agentId: 'uuid-abc123',
to: '+15125551234',
name: 'John Smith',
leadId: 'uuid-lead123',
context: 'Following up on car accident case',
firstMessage: 'Hey John, this is Kai — do you have a minute?',
});
const result = await kai.calls.get(call.id);
console.log(result.summary);
// Create an agent
const agent = await kai.agents.create({
businessId: 'uuid-biz456',
name: 'Kai Receptionist',
systemPrompt: 'You are a friendly receptionist for Smith Law.',
firstMessage: 'Hello! How can I help you today?',
});
// Update per-channel prompts
await kai.agents.update({
id: agent.id,
inboundPrompt: 'Updated inbound instructions.',
outboundPrompt: 'Updated outbound instructions.',
smsPrompt: 'Updated SMS instructions.',
});
// Send an SMS
await kai.sms.send({
to: '+15125551234',
fromAgentId: 'uuid-abc123',
message: 'Hi John, following up on our call!',
leadId: 'uuid-lead123',
});Need help? support@kaicalls.com