Telephony API
Endpoints for managing voice calls, campaigns, journals, and integrations. All endpoints require authentication via Bearer token (see REST API → Authentication).
Base URL: https://api.aispinner.io
Calls & Campaigns
Start a Dialer Campaign
POST /telephony/dialer/start
Authorization: Bearer <token>
Content-Type: application/json
{
"workspace_id": 1,
"node_id": "pbx_abc123",
"numbers": ["+15551234567", "+15557654321"],
"agent_node_id": "agent_xyz",
"max_concurrent": 5
}Starts a chunked campaign through the connected ElevenLabs (or Custom Voice) stack. The dialer splits numbers into chunks of max_concurrent and submits each chunk sequentially.
Response:
{ "call_id": "camp_abc123", "status": "running" }Get Resumable Campaigns
GET /telephony/runs/resumable?workspace_id=1
Authorization: Bearer <token>Lists campaigns that were paused and can be resumed. A paused campaign stores its remaining number list; resuming it picks up where it stopped.
List Runs (history)
GET /telephony/runs?workspace_id=1&node_id=pbx_abc123&limit=100
Authorization: Bearer <token>Rename a Campaign
PATCH /telephony/runs/{call_id}/name
Authorization: Bearer <token>
Content-Type: application/json
{ "name": "Q2 outbound — VIP list" }Get Call Events (poll/SSE)
GET /telephony/calls/{call_id}/events
Authorization: Bearer <token>Returns the event stream for a call (status changes, transcript turns, completion). Prefer the Realtime Events WebSocket for push delivery instead of polling this.
Get Call Audio
GET /telephony/calls/{call_id}/audio?token=<token>Returns the MP3 recording of a single call. The token is passed as a query parameter so this URL can be embedded in <audio> players.
Journal
Call history with transcripts, summaries, and audio links — used by the Journal block (ai.journal) and the PBX Monitor block.
All-Nodes Journal
GET /telephony/journal?workspace_id=1&limit=200
Authorization: Bearer <token>Returns all calls across the user's workspaces. Filter by node_id, date_from, date_to, status (comma-separated, e.g. done,failed).
Response shape:
{
"total": 42,
"total_duration_sec": 8431,
"max_id": 12345,
"calls": [
{
"id": 12345,
"call_id": "call_abc",
"status": "done",
"subscriber_phone": "+15551234567",
"duration_sec": 142,
"summary": "Customer agreed to a callback...",
"transcript": [
{"role": "agent", "message": "Hello!", "time_in_call_secs": 0},
{"role": "user", "message": "Hi.", "time_in_call_secs": 1.2}
],
"created_at": "2026-05-04T10:23:45Z",
"conversation_id": "conv_xyz",
"has_audio": true,
"parent_call_id": "camp_parent_id"
}
],
"campaigns": [
{
"call_id": "camp_parent_id",
"name": "VIP outreach",
"status": "completed",
"numbers_count": 50,
"child_count": 50,
"success_count": 38,
"failed_count": 12,
"total_duration_sec": 4200
}
]
}Per-Node Journal
GET /telephony/journal/{node_id}?workspace_id=1&limit=200
Authorization: Bearer <token>Same shape, scoped to one PBX / Phone Number / Agent node.
Delta Pagination
Pass since_id=<max_id> to receive only records newer than that id — the journal is append-mostly, so this is a cheap incremental refresh:
GET /telephony/journal/{node_id}?workspace_id=1&since_id=12345
Authorization: Bearer <token>The frontend Journal block uses this on every WebSocket journal.new event.
Single Call Detail
GET /telephony/journal/call/{call_id}
Authorization: Bearer <token>Returns one call with full transcript and summary. Used by the PBX Monitor block when a row is expanded.
Settings
Get Telephony Settings
GET /telephony/settings
Authorization: Bearer <token>Returns ARI / SIP defaults for Custom Voice mode.
Update Telephony Settings
PUT /telephony/settings
Authorization: Bearer <token>
Content-Type: application/json
{ "settings_json": { "default_provider_id": "ari_main" } }Phone Provider Configuration
Per-node configuration for the inbound/outbound carrier assigned to an ai.phone_number block.
Get Phone Provider
GET /workspaces/{ws_id}/nodes/{node_id}/phone-provider
Authorization: Bearer <token>Update Phone Provider
PUT /workspaces/{ws_id}/nodes/{node_id}/phone-provider
Authorization: Bearer <token>
Content-Type: application/json
{
"provider": "twilio",
"twilio_sid": "ACxxxxxxxx",
"twilio_token": "<your token>",
"twilio_phone": "+15551234567",
"agent_node_id": "agent_abc"
}provider is twilio or sip. SIP fields: sip_server, sip_user, sip_password, sip_port. Sensitive credentials are encrypted at rest (Fernet).
Delete Phone Provider
DELETE /workspaces/{ws_id}/nodes/{node_id}/phone-provider
Authorization: Bearer <token>Import from ElevenLabs
POST /workspaces/{ws_id}/nodes/{node_id}/phone-provider/import
Authorization: Bearer <token>Pulls the existing SIP/Twilio configuration from your linked ElevenLabs account into the AiSpinner node — saves manual re-entry of trunk credentials.
ElevenLabs Integration
List API Keys
GET /integrations/elevenlabs/keys
Authorization: Bearer <token>Add API Key
POST /integrations/elevenlabs/keys
Authorization: Bearer <token>
Content-Type: application/json
{ "title": "My ElevenLabs", "key": "sk_..." }The key is encrypted before storage; only the last 4 characters are returned to clients. Replace it by adding a new key and removing the old one.
Delete API Key
DELETE /integrations/elevenlabs/keys/{id}
Authorization: Bearer <token>List Phone Numbers (SIP + Twilio)
GET /integrations/sip/phone-numbers
Authorization: Bearer <token>Returns every phone number visible in your ElevenLabs account. The Phone Number block uses this for its SIP / Twilio tab.
Agents
List ElevenLabs Agents
GET /agents/elevenlabs/list
Authorization: Bearer <token>Adopt an Existing ElevenLabs Agent
POST /agents/adopt
Authorization: Bearer <token>
Content-Type: application/json
{ "elevenlabs_agent_id": "agent_xyz", "node_id": "agent_node_abc" }Pulls the agent's full configuration (name, voice, prompt, tools, model, voice settings, temperature, max_tokens, platform tools, safety rules, raw config) into a local AiSpinner record without creating a new agent on ElevenLabs side. Use this to bring already-configured agents onto your canvas non-destructively.
Test Agent
POST /integrations/elevenlabs/agents/test
Authorization: Bearer <token>
Content-Type: application/json
{ "elevenlabs_agent_id": "agent_xyz" }WebCall (Browser-side Voice)
In-browser WebRTC bridging to a connected agent. Used by the demo "Try this agent" UI.
GET /webcall/audio/{call_id}.mp3
POST /webcall/answered
POST /webcall/connectedThese are mostly internal to the WebRTC flow — you usually don't call them directly.
Error Responses
Standard format (see REST API → Errors):
{ "detail": "campaign not found" }Telephony-specific status codes:
404— Workspace, node, or call not found409— Conflict (e.g. trying to start a campaign that's already running)422— Invalid number format, missing agent connection429— ElevenLabs rate-limit hit (system retries automatically; if you see this, your account quota is exhausted)