Developer platform · v2

Voice

View as MarkdownAll docs

Voice sessions

Create a realtime media session#

POST /v2/voice/sessions requires a project key with voice:write:

json
{
  "agent_id": "<project agent uuid>",
  "variables": { "account_name": "Asha" },
  "sample_rate_in": 16000,
  "sample_rate_out": 24000,
  "max_duration_seconds": 300,
  "record": false,
  "store_transcript": false,
  "metadata": { "external_id": "call_42" }
}

Input sample rate is 8000 or 16000 Hz; output is 8000, 16000, or 24000 Hz. Variables are text values and are rendered into the saved agent. Capture options inherit from the agent when omitted and can only tighten its permissions—an explicit true cannot enable capture the agent disabled.

The response contains session, a one-use ws_url, and expires_in_seconds. Connect the media socket before it expires. Admission needs verified provider accounts for every stage (503 otherwise), a free concurrency slot, and a wallet that can cover max_duration_seconds (402 otherwise). Missing or cross-project agents are indistinguishable.

The media socket#

wss://api.developers.dvaarik.com/v2/voice/sessions/{session_id}/stream?token=… is the ws_url. Send raw little-endian PCM16 mono frames at the input rate as binary messages; receive PCM16 at the output rate as binary messages. Text messages are JSON control frames:

DirectionFrameMeaning
server → client`{"type":"transcript","role":"user"\"assistant","text":"…"}`a finished utterance
server → client{"type":"interrupted"}the caller barged in; drop queued playback now
server → client{"type":"turn_complete"}the agent finished speaking
server → client{"type":"error","message":"…"}a recoverable problem
server → client{"type":"session_ended","reason":"…"}the server ended the call
client → server{"type":"stop"}hang up

Close codes name a refusal: 4401 bad token, 4404 unknown session, 4408 configuration expired, 4409 not connectable, 4429 concurrency limit, 4453 provider pipeline unavailable, 1013 service restarting.

Create an outbound BYOL session#

POST /v2/voice/sessions/outbound requires voice:write. Send an Idempotency-Key from your trusted server and use a number on one of your verified carrier connections with outbound enabled:

json
{
  "agent_id": "<project agent uuid>",
  "to": "+12025550111",
  "from": "+12025550100",
  "variables": { "account_name": "Asha" },
  "max_duration_seconds": 300,
  "metadata": { "external_id": "call_43" }
}

The 202 response is { "session": { ... }, "duplicate": false }; a retried key returns the first call with duplicate: true. Carrier account, line ownership, routing, consent, and carrier fees remain yours.

Read sessions#

GET /v2/voice/sessions accepts limit, offset, status (created, active, completed, failed), agent_id, from, and to (ISO date-times); GET /v2/voice/sessions/{session_id} reads one. Both need voice:read. The console equivalents back the Calls page.

A session includes status, direction, agent/version, language, a secret-free frozen pipeline snapshot, project revision, sample rates, duration and connected seconds, media timestamps, end reason, capture flags, metadata, and money fields. rate_nano_usd_per_min, hold_nano_usd, and cost_nano_usd are decimal strings. The currency is USD and money_scale is 1,000,000,000.

Exact USD arithmetic#

The connected-minute rate is 5,000,000 nano-USD ($0.005 — half a cent). Every call rounds up to the next full minute — 61 connected seconds bills as 2 minutes, the same as a 120-second call. Cost is:

ceil(connected_seconds / 60) × 5,000,000

Use an integer or decimal library. JavaScript callers should parse money strings with BigInt; do not use Number, parseFloat, or binary floating-point division. The session freezes provider revisions, project revision, rate, and rate version on admission; settlement is idempotent.

Browser sessions#

POST /console/v2/projects/{project_id}/voice/sessions is the same admission with the account session instead of a key; it is what the Playground uses. Your own product creates sessions from your server with a project key and hands only the ws_url to the client — or, for a public web page with no server in the loop, uses a publishable key and browser calls.

Use one project per boundary

Provider secrets stay encrypted and project API keys stay on your server.