KaiCalls API Reference

KaiCalls API

Give your AI agent a phone. Make outbound calls, manage agents, and integrate AI phone assistants into your applications.

Base URL:https://kaicalls.com/api/v1

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_xxxxx

Key Prefixes

  • kc_live_ — Production keys
  • kc_test_ — Sandbox keys (coming soon)

Scopes

Keys are created with scopes that control access. Default scopes are granted automatically.

ParameterTypeDescription
agents:readscopeList and view agents
agents:writescopeCreate and update agents
numbers:readscopeList phone numbers
calls:readscopeList and view call records
calls:writescopeMake outbound calls
*scopeFull access (all scopes)

Agents

GET/api/v1/agentsList all agents

Returns all agents assigned to your businesses. Requires agents:read scope.

Response200
{
  "agents": [
    {
      "id": "uuid-abc123",
      "name": "Kai",
      "business_id": "uuid-biz456",
      "created_at": "2026-01-15T10:00:00Z"
    }
  ]
}
GET/api/v1/agents?id=AGENT_IDGet agent details

Returns detailed info including Vapi assistant ID and assigned phone number.

Response200
{
  "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"
}
POST/api/v1/agentsCreate a new voice agent

Creates 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

ParameterTypeDescription
business_idrequiredstringBusiness to assign the agent to (must be accessible by your API key)
namerequiredstringAgent display name
system_promptrequiredstringThe agent's system prompt / instructions
first_messagestringGreeting message (default: "Hello! How can I help you today?")
voiceobjectVoice configuration: { provider, voiceId } (defaults to Vapi default)
modelobjectModel configuration: { provider, model, temperature } (defaults to OpenAI gpt-4.1 at 0.7)
metadataobjectExtra 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 }
  }'
Response201
{
  "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.

PATCH/api/v1/agentsUpdate an existing agent

Partial 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).

Required scope: agents:write

Parameters

ParameterTypeDescription
idrequiredstringKaiCalls agent ID to update
namestringNew agent display name
system_promptstringNew system prompt / instructions
first_messagestringNew greeting message
voiceobjectNew voice configuration: { provider, voiceId }
modelobjectNew model configuration: { provider, model, temperature }
metadataobjectMetadata to merge with existing values

Example (update system prompt only)

curl -X PATCH https://kaicalls.com/api/v1/agents \
  -H "Authorization: Bearer kc_live_xxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "uuid-agent789",
    "system_prompt": "You are an intake specialist. Collect case details and schedule consultations."
  }'
Response200
{
  "id": "uuid-agent789",
  "name": "Kai Receptionist",
  "business_id": "uuid-biz456",
  "vapi_assistant_id": "vapi-asst-xyz",
  "updated": true
}

Phone Numbers

GET/api/v1/numbersList phone numbers

Returns all phone numbers registered to your businesses. Requires numbers:read scope.

Response200
{
  "numbers": [
    {
      "id": "uuid-num789",
      "phone_number": "+15125551234",
      "agent_id": "uuid-abc123",
      "business_id": "uuid-biz456",
      "created_at": "2026-01-15T10:00:00Z"
    }
  ]
}

Calls

POST/api/v1/callsMake an outbound call

Initiates 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

ParameterTypeDescription
agent_idrequiredstringThe agent to use for this call
torequiredstringPhone number to call (E.164 format, e.g. +15125551234)
namestringCustomer name. The agent greets them by name. Also accepts customer_name.
contextstringFreeform context the agent can reference. Use for task instructions, appointment details, or notes.
firstMessagestringOverride the agent's opening line for this call. Also accepts first_message. If omitted, uses the agent's configured outbound greeting.
lead_idstringLink this call to a lead in your CRM. Enables automatic enrichment with lead score, history, and source.
webhook_urlstringURL to receive a webhook when the call completes
max_durationintegerMaximum 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:

VariableDescription
nameLead's first name (from name param or CRM)
lead_scoreAI-assigned quality score (0-100)
lead_statusCurrent lead status in your pipeline
interaction_countNumber of previous calls with this lead
days_since_first_contactDays since the lead was first created
lead_sourceWhere the lead came from (web form, referral, etc.)
business_nameYour business name
business_phoneYour 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?"
  }'
Response201
{
  "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"
}
GET/api/v1/callsList calls

Returns calls across all your businesses, ordered by most recent. Requires calls:read scope.

Query Parameters

ParameterTypeDescription
limitintegerMax results per page (default: 50, max: 100)
agent_idstringFilter by agent ID
statusstringFilter by call status
afterstringCursor-based pagination. Pass the created_at of the last result to get the next page.
Response200
{
  "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
}
GET/api/v1/calls?id=CALL_IDGet call details

Returns full details for a single call including summary, recording, and quality analysis.

Response200
{
  "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"
}

API Keys

Key management uses session authentication (dashboard login), not API key auth.

GET/api/v1/keysList your API keys
Response200
{
  "keys": [
    {
      "id": "uuid-key123",
      "prefix": "kc_live_abc1",
      "name": "Production Key",
      "scopes": ["agents:read", "calls:read", "calls:write", "numbers:read"],
      "business_id": null,
      "created_at": "2026-01-15T10:00:00Z",
      "last_used_at": "2026-02-15T14:30:00Z",
      "expires_at": null,
      "is_active": true
    }
  ]
}
POST/api/v1/keysCreate a new key

The full key is returned only once — store it securely.

ParameterTypeDescription
namestringHuman-readable name (default: "Untitled Key")
business_idstringScope key to a single business. If omitted, key accesses all your businesses.
scopesstring[]Permission scopes. Defaults to ["agents:read", "numbers:read", "calls:read", "calls:write"].
Response201
{
  "key": "kc_live_abc123def456...",
  "id": "uuid-key123",
  "prefix": "kc_live_abc1",
  "name": "My Integration Key",
  "scopes": ["agents:read", "calls:read", "calls:write", "numbers:read"],
  "business_id": "uuid-biz456",
  "created_at": "2026-02-15T14:30:00Z"
}
DELETE/api/v1/keys?id=KEY_IDRevoke a key

Revokes an API key. The key immediately stops working.

Response200
{ "success": true }

Account

GET/api/v1/balanceGet subscription info

Returns usage and subscription status for each of your businesses.

Response200
{
  "businesses": [
    {
      "business_id": "uuid-biz456",
      "minutes_used": 412,
      "phone_numbers": 2,
      "subscription_status": "active"
    }
  ]
}
GET/api/v1/usageGet API usage log

Returns your API call history.

ParameterTypeDescription
startstringISO 8601 start date filter
endstringISO 8601 end date filter
limitintegerMax results (default: 100, max: 500)
Response200
{
  "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"
  }
}
CodeStatusDescription
unauthorized401Invalid, missing, expired, or revoked API key
forbidden403Key doesn't have the required scope
not_found404Agent, call, or resource not found
invalid_request400Missing required fields or invalid JSON
vapi_error4xx/5xxVapi API call failed (create/update agent)
call_failed500Vapi failed to initiate the call
internal_error500Unexpected server error
rate_limited429Too many requests — slow down

Rate Limits

EndpointLimit
POST /v1/calls60 requests/minute
POST /v1/agents30 requests/minute
PATCH /v1/agents60 requests/minute
All GET endpoints300 requests/minute

SDKs

Python

pip install kaicalls
from 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 an agent
kai.agents.update(id=agent.id, system_prompt="New instructions.")

JavaScript / TypeScript

npm install kaicalls
import { 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 an agent
await kai.agents.update({
  id: agent.id,
  systemPrompt: 'New instructions.',
});
    API Reference | KaiCalls Developer Docs