Skip to content

API reference

Base URL https://<your-app>/api/v1. Authenticate with Authorization: Bearer cv_live_… — keys are per workspace, created in Settings → API keys and shown once. Requests and responses are JSON.

Agents

An agent is one company voice in one role. Its configuration is an AgentSpec — create one from a role template and override what you need.

GET/api/v1/agents

List agents in the workspace.

POST/api/v1/agents

Create an agent from a role template.

request bodyjson
{
  "name": "Front desk",
  "role": "receptionist",
  "company": { "name": "Acme Dental", "description": "Family dental practice in Zurich" },
  "spec": { "voice": { "engine": "auto", "language": "de" } }
}
responsejson
{ "id": "…", "status": "draft", "version": 1 }

GET/api/v1/agents/{id}

Fetch one agent with its AgentSpec.

PATCH/api/v1/agents/{id}

Update name, status (draft | live | paused) or spec. Bumps the version.

Calls

Outbound calls pass the compliance gate first. Outside the callee’s calling hours the call is scheduled, not dialled — the response says when.

POST/api/v1/calls

Place (or schedule) an outbound call.

request bodyjson
{
  "agent_id": "…",
  "to": "+41441234567",
  "contact": { "name": "Anna Keller", "kind": "b2c" },
  "goal": "Confirm Tuesday's appointment",
  "language": "de",
  "consent": { "basis": "existing_customer" },
  "external_ref": "crm-8812",
  "callback_url": "https://example.com/hooks/calls"
}
responsejson
{ "call_id": "…", "status": "dialing" }
// or, outside local hours:
{ "call_id": "…", "status": "scheduled", "scheduled_for": "2026-10-01T07:00:00Z" }
// or, blocked by the gate (HTTP 422):
{ "call_id": "…", "status": "canceled", "reason": "consent_required" }

GET/api/v1/calls

List calls, newest first (filter by agent_id, status, direction).

GET/api/v1/calls/{id}

A call with its transcript, outcome, actions, latency and cost.

responsejson
{
  "id": "…", "direction": "outbound", "status": "completed", "outcome": "booked",
  "duration_seconds": 143, "cost_credits": 406,
  "transcript": [{ "direction": "out", "text": "Just so you know, I'm Alex, an AI assistant…" }],
  "actions": [{ "type": "book_appointment", "starts_at": "2026-10-06T12:30:00Z" }],
  "latency": { "turns": 11, "p50_ms": 760, "p95_ms": 1180 }
}

POST/api/v1/calls/web

Start a browser test call; returns a LiveKit room and participant token.

request bodyjson
{ "agent_id": "…" }
responsejson
{ "call_id": "…", "room": "web-…", "livekit_url": "wss://…", "token": "…" }

Numbers

Buy a local number and route it to an agent. Some countries need an address or company document before a number activates (status needs_documents).

GET/api/v1/numbers

List numbers and the agent each routes to.

GET/api/v1/numbers/available?country=CH&type=local

Numbers you can buy now (type: local | mobile | toll_free; optional contains=digits).

POST/api/v1/numbers

Buy a number (a specific e164 from /available, or the first match) and optionally route it. 409 needs_documents when the country requires a regulatory bundle.

request bodyjson
{ "country": "CH", "e164": "+41…", "type": "local", "agent_id": "…" }

PATCH/api/v1/numbers/{id}

Route a number to another agent (or null to unassign).

request bodyjson
{ "agent_id": "…" }

DELETE/api/v1/numbers/{id}

Release a number: it stops ringing, goes back to the carrier and stops billing.

PATCH/api/v1/telephony

Suspend or reactivate every line in the workspace (owner/admin, dashboard session). Numbers stay yours while suspended.

request bodyjson
{ "status": "suspended" }

Calendar & bookings

The native calendar behind every booking tool. Linked Google or Microsoft calendars contribute their busy times.

GET/api/v1/availability?calendar_id={id}&from={iso}&days=7

Free slots on a calendar.

responsejson
{ "slots": [{ "start": "2026-10-06T12:30:00Z", "end": "2026-10-06T13:00:00Z" }] }

GET/api/v1/bookings

Bookings, newest first (filter by calendar_id, from, to).

Campaigns

An outbound agent over a contact list. The scheduler dials contacts inside their local window, retries per the campaign settings, and skips anyone the gate blocks.

POST/api/v1/campaigns

Create a campaign.

request bodyjson
{ "agent_id": "…", "name": "October follow-ups", "goal": "Book a demo", "contact_ids": ["…"] }

POST/api/v1/campaigns/{id}/start

Queue the campaign’s contacts for dialling.