Skip to main content

Documentation Index

Fetch the complete documentation index at: https://orbit-docs.devotel.io/llms.txt

Use this file to discover all available pages before exploring further.

Voice API

Build voice applications with Orbit’s Voice API. Make and receive calls, connect AI agents, configure SIP trunks, build IVR menus, host conference calls, and manage voicemail — all through a unified API. Base path: /v1/voice

Calls

Initiate a Call

POST /v1/voice/calls Start an outbound call. Route it to an AI voice agent, an IVR flow, or a raw SIP destination.
to
string
required
Destination phone number in E.164 format
from
string
required
Caller ID — must be a number registered in your Orbit account
agent_id
string
AI agent to handle the call (omit for raw SIP or IVR)
ivr_id
string
IVR flow ID to execute when the call connects
webhook_url
string
URL to receive call status callbacks
record
boolean
default:"false"
Whether to record the call
max_duration
integer
default:"3600"
Maximum call duration in seconds
metadata
object
Arbitrary key-value pairs attached to the call
curl -X POST https://orbit-api.devotel.io/api/v1/voice/calls \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+14155552671",
    "from": "+12025551234",
    "agent_id": "agt_abc123",
    "record": true,
    "webhook_url": "https://example.com/webhooks/calls"
  }'
{
  "data": {
    "id": "call_abc123",
    "to": "+14155552671",
    "from": "+12025551234",
    "agent_id": "agt_abc123",
    "status": "initiating",
    "record": true,
    "created_at": "2026-03-08T12:00:00Z"
  },
  "meta": {
    "request_id": "req_call_001",
    "timestamp": "2026-03-08T12:00:00Z"
  }
}

List Calls

GET /v1/voice/calls Retrieve call logs with cursor-based pagination and optional filters.
cursor
string
Cursor for pagination
limit
integer
default:"20"
Results per page (max 100)
status
string
Filter by status: initiating, ringing, in_progress, completed, failed
from
string
Filter by caller number
to
string
Filter by destination number

Get Call Details

GET /v1/voice/calls/{id} Retrieve full details of a call including status, duration, recording URL, and agent interaction summary.

Hang Up a Call

POST /v1/voice/calls/{id}/hangup Terminate an active call. AI agents receive a graceful shutdown signal before disconnection.

Accept / Decline an Inbound Call

POST /v1/voice/calls/{id}/accept Accept an incoming call before it auto-rings the configured number-handler. Use when the softphone or programmatic handler wants to answer in lieu of the default routing. POST /v1/voice/calls/{id}/decline Reject an incoming call. The carrier receives 486 Busy Here.

Mute / Unmute a Call Leg

POST /v1/voice/calls/{id}/mute POST /v1/voice/calls/{id}/unmute Mute or unmute the operator side of a connected call. Mute is per-leg — the participant on the other side keeps speaking and their audio still records.

Hold / Unhold

POST /v1/voice/calls/{id}/hold POST /v1/voice/calls/{id}/unhold Place the remote party on hold (carrier-side music or silence depending on the trunk’s hold_music configuration). Unhold restores audio in both directions.

Send DTMF Tones

POST /v1/voice/calls/{id}/dtmf
digits
string
required
String of DTMF digits to send (09, *, #, AD). Plays at standard 100ms / 100ms gap.
Use to navigate carrier IVRs from a programmatic outbound call (PIN entry, account confirmations, etc.).

Transfer (Blind)

POST /v1/voice/calls/{id}/transfer Cold-transfer the call to a new destination. Hangs up the original leg the moment the new leg connects.
to
string
required
Destination phone number, agent ID (agt_*), or extension (ext_*).
caller_id
string
Override the From number presented to the destination. Defaults to the original caller’s number.

Warm Transfer

POST /v1/voice/calls/{id}/warm-transfer Start a warm transfer — the calling agent stays connected while a third leg is dialled. The original caller is placed on hold; once the third party answers, the agent has a private “whisper” window with them before completing the handoff.
to
string
required
Destination for the warm-transfer consult leg.
whisper_message
string
Optional TTS message played to the consult party before audio bridges (e.g. “Customer Jane Doe, escalation tier 2”).
POST /v1/voice/calls/{id}/warm-transfer/complete Bridge the original caller into the consult leg and disconnect the original agent. The two non-agent legs are now connected. POST /v1/voice/calls/{id}/warm-transfer/cancel Abort the warm transfer and return the original caller to the agent. The consult leg is hung up.

Recording

Recordings are configured per-call via record: true on POST /v1/voice/calls, or started/stopped mid-call via the endpoints below. Storage is tenant-isolated; URLs expire after 24 hours and require re-fetching via the call detail endpoint.

Start / Stop Mid-Call Recording

POST /v1/voice/calls/{id}/recording/start Begin recording an in-progress call. Idempotent — calling on an already-recording call returns the existing recording id.
dual_channel
boolean
default:"true"
Record agent + caller on separate audio channels (left/right). Single-channel mixes both.
trim
boolean
default:"false"
Trim leading/trailing silence from the saved file.
POST /v1/voice/calls/{id}/recording/stop Stop the in-progress recording and finalise the file. Subsequent reads of GET /v1/voice/calls/{id}/recording will return the fully-encoded URL.

Retrieve a Call Recording

GET /v1/voice/calls/{id}/recording Returns the recording metadata + a 24h-expiring signed URL. If the call is still being recorded, status is in_progress and signed_url is null.
{
  "data": {
    "call_id": "call_abc123",
    "status": "completed",
    "duration_seconds": 312,
    "format": "mp3",
    "channels": 2,
    "size_bytes": 4980000,
    "signed_url": "https://storage.devotel.io/recordings/call_abc123.mp3?Expires=1735689600&Signature=...",
    "signed_url_expires_at": "2026-03-09T12:00:00Z",
    "created_at": "2026-03-08T11:55:48Z"
  },
  "meta": {
    "request_id": "req_rec_001",
    "timestamp": "2026-03-08T12:00:00Z"
  }
}

Conference Recording

POST /v1/voice/conferences/{id}/recording/start POST /v1/voice/conferences/{id}/recording/stop Same semantics as call recording but for conference rooms — captures the mixed audio of every participant.

SIP Trunks

Bring your own carrier by connecting SIP trunks to Orbit. Orbit acts as an SBC (Session Border Controller) with TLS and SRTP encryption.

Create SIP Trunk

POST /v1/voice/sip-trunks
name
string
required
A descriptive name for the trunk
termination_uri
string
required
SIP URI for outbound call routing (e.g., sip:trunk.carrier.com:5060)
origination_uris
string[]
SIP URIs that Orbit should accept inbound calls from
auth_username
string
SIP authentication username
auth_password
string
SIP authentication password
codecs
string[]
default:"[\"PCMU\", \"PCMA\", \"OPUS\"]"
Preferred audio codecs in priority order
encryption
string
default:"tls_srtp"
Transport encryption: tls_srtp, tls, or none
curl -X POST https://orbit-api.devotel.io/api/v1/voice/sip-trunks \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Primary Carrier",
    "termination_uri": "sip:trunk.carrier.com:5060",
    "origination_uris": ["sip:orbit-gw.devotel.io"],
    "auth_username": "orbit_user",
    "auth_password": "secure_password",
    "codecs": ["OPUS", "PCMU"],
    "encryption": "tls_srtp"
  }'
{
  "data": {
    "id": "trunk_abc123",
    "name": "Primary Carrier",
    "termination_uri": "sip:trunk.carrier.com:5060",
    "status": "active",
    "codecs": ["OPUS", "PCMU"],
    "encryption": "tls_srtp",
    "created_at": "2026-03-08T12:00:00Z"
  },
  "meta": {
    "request_id": "req_trunk_001",
    "timestamp": "2026-03-08T12:00:00Z"
  }
}

List SIP Trunks

GET /v1/voice/sip-trunks

Get SIP Trunk

GET /v1/voice/sip-trunks/{id}

Update SIP Trunk

PUT /v1/voice/sip-trunks/{id}

Delete SIP Trunk

DELETE /v1/voice/sip-trunks/{id}

IVR (Interactive Voice Response)

Build programmable voice menus that route callers through options, collect DTMF input, and transfer to agents or queues.

Create IVR Flow

POST /v1/voice/ivr
name
string
required
IVR flow name
greeting
string
required
Text-to-speech greeting played when a caller connects
language
string
default:"en-US"
Language for TTS and speech recognition
menu
object
required
Menu definition with DTMF key-to-action mappings
timeout_seconds
integer
default:"10"
Seconds to wait for DTMF input before replaying the menu
max_retries
integer
default:"3"
Maximum menu replays before fallback action
fallback_action
string
default:"voicemail"
Action when max retries reached: voicemail, transfer_number, hangup
curl -X POST https://orbit-api.devotel.io/api/v1/voice/ivr \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Main Menu",
    "greeting": "Welcome to Acme Corp. Press 1 for sales, 2 for support, or 3 to leave a voicemail.",
    "language": "en-US",
    "menu": {
      "options": [
        { "key": "1", "action": "transfer_agent", "target": "agt_sales" },
        { "key": "2", "action": "transfer_agent", "target": "agt_support" },
        { "key": "3", "action": "voicemail", "target": "vmail_general" }
      ]
    },
    "timeout_seconds": 8,
    "fallback_action": "voicemail"
  }'
{
  "data": {
    "id": "ivr_abc123",
    "name": "Main Menu",
    "status": "active",
    "options_count": 3,
    "created_at": "2026-03-08T12:00:00Z"
  },
  "meta": {
    "request_id": "req_ivr_001",
    "timestamp": "2026-03-08T12:00:00Z"
  }
}

List IVR Flows

GET /v1/voice/ivr

Update IVR Flow

PUT /v1/voice/ivr/{id}

Delete IVR Flow

DELETE /v1/voice/ivr/{id}

Conferences

Host multi-party conference calls with moderation controls, recording, and real-time participant management.

Create Conference

POST /v1/voice/conferences
name
string
required
Conference name
max_participants
integer
default:"50"
Maximum number of participants
record
boolean
default:"false"
Record the conference
mute_on_join
boolean
default:"false"
Mute participants when they join
webhook_url
string
URL for conference event callbacks
curl -X POST https://orbit-api.devotel.io/api/v1/voice/conferences \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Q1 Planning Call",
    "max_participants": 25,
    "record": true,
    "mute_on_join": true
  }'
{
  "data": {
    "id": "conf_abc123",
    "name": "Q1 Planning Call",
    "status": "waiting",
    "pin": "482901",
    "dial_in_number": "+18005559999",
    "max_participants": 25,
    "record": true,
    "created_at": "2026-03-08T12:00:00Z"
  },
  "meta": {
    "request_id": "req_conf_001",
    "timestamp": "2026-03-08T12:00:00Z"
  }
}

Add Participant

POST /v1/voice/conferences/{id}/participants
number
string
required
Phone number to dial into the conference
muted
boolean
default:"false"
Join the participant in muted state

Remove Participant

DELETE /v1/voice/conferences/{id}/participants/{participantId}

End Conference

POST /v1/voice/conferences/{id}/end

Voicemail

Manage voicemail boxes for receiving and transcribing voice messages when calls go unanswered.

Create Voicemail Box

POST /v1/voice/voicemail
name
string
required
Voicemail box name
greeting
string
Custom TTS greeting (default: “Please leave a message after the tone.”)
transcribe
boolean
default:"true"
Automatically transcribe voicemail messages using STT
max_duration
integer
default:"120"
Maximum voicemail recording duration in seconds
notification_email
string
Email to send voicemail notifications to
webhook_url
string
URL for voicemail event callbacks
curl -X POST https://orbit-api.devotel.io/api/v1/voice/voicemail \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "General Inbox",
    "greeting": "You have reached Acme Corp. We are currently unavailable. Please leave a message.",
    "transcribe": true,
    "notification_email": "team@acme.com"
  }'
{
  "data": {
    "id": "vmail_abc123",
    "name": "General Inbox",
    "transcribe": true,
    "max_duration": 120,
    "messages_count": 0,
    "created_at": "2026-03-08T12:00:00Z"
  },
  "meta": {
    "request_id": "req_vmail_001",
    "timestamp": "2026-03-08T12:00:00Z"
  }
}

List Voicemail Messages

GET /v1/voice/voicemails Retrieve voicemail messages across the org with transcriptions, with cursor pagination and filters by direction, status, and unread state. GET /v1/voice/voicemails/{id} Get a single voicemail message including transcription and recording URL. PATCH /v1/voice/voicemails/{id}/read Mark a voicemail as read. DELETE /v1/voice/voicemails/{id} Permanently delete a voicemail message.
{
  "data": [
    {
      "id": "vmsg_001",
      "voicemail_id": "vmail_abc123",
      "caller": "+14155552671",
      "duration_seconds": 35,
      "transcription": "Hi, this is Jane. I wanted to follow up on my order. Please call me back.",
      "recording_url": "https://storage.devotel.io/voicemail/vmsg_001.wav",
      "listened": false,
      "created_at": "2026-03-08T14:30:00Z"
    }
  ],
  "meta": {
    "request_id": "req_vmsg_001",
    "timestamp": "2026-03-08T15:00:00Z",
    "pagination": {
      "cursor": "cur_vmsg_abc",
      "has_more": false,
      "total": 1
    }
  }
}

Conference Operations (advanced)

Beyond Add Participant / Remove Participant, the conference API exposes a complete moderation surface.

Mute / Unmute a Participant

POST /v1/voice/conferences/{id}/participants/{participantId}/mute POST /v1/voice/conferences/{id}/participants/{participantId}/unmute

Mute / Unmute Everyone

POST /v1/voice/conferences/{id}/mute-all POST /v1/voice/conferences/{id}/unmute-all Useful for “all-hands” conferences where the moderator wants to control the floor. Already-muted participants keep their state.

Hold / Unhold a Participant

POST /v1/voice/conferences/{id}/participants/{participantId}/hold POST /v1/voice/conferences/{id}/participants/{participantId}/unhold

Lock / Unlock Conference

POST /v1/voice/conferences/{id}/lock POST /v1/voice/conferences/{id}/unlock When locked, no new participants can join — existing participants stay connected. Use to seal a conference for a confidential discussion.

End / Delete a Conference

POST /v1/voice/conferences/{id}/end End the active conference and disconnect every participant gracefully. The conference row is retained for analytics. DELETE /v1/voice/conferences/{id} Hard-delete the conference row (only allowed when status is ended).

Call Queues

Queue inbound calls by skill / priority and route them to the next available agent. Pairs with the AI agent layer for hybrid human + AI front-desk experiences.

Create a Queue

POST /v1/voice/queues
name
string
required
Queue name (visible to supervisors in the wallboard).
strategy
string
default:"longest_idle"
Distribution strategy: longest_idle, round_robin, least_calls, random.
max_wait_seconds
integer
default:"300"
Maximum hold time before the call falls through to overflow_action.
overflow_action
string
default:"voicemail"
Action when max-wait expires: voicemail, transfer_number, hangup.
hold_music_url
string
Public URL of an MP3 played while waiting.

List / Update / Delete

GET /v1/voice/queues PUT /v1/voice/queues/{id} DELETE /v1/voice/queues/{id}

Enqueue a Call

POST /v1/voice/queues/{id}/enqueue
call_id
string
required
Call ID to add to the queue.
priority
integer
default:"0"
Higher priority routes ahead of lower. VIP customers, escalations.

Queue Stats

GET /v1/voice/queues/{id}/stats Returns live counts: waiting, connected, abandoned_24h, avg_wait_seconds_24h, plus per-agent presence.

Set Agent Status

POST /v1/voice/agents/{id}/status
status
string
required
Agent presence: available, busy, wrap_up, offline.
Drives queue routing — available agents are eligible for the next call.

Ring Groups

A ring group rings multiple users / extensions in parallel or sequence on a single inbound number. Use for “ring all sales reps until someone answers” patterns.

Create / List / Get / Delete

POST /v1/voice/ring-groups
name
string
required
Ring group name.
strategy
string
default:"simultaneous"
Ring strategy: simultaneous, sequential, random.
members
object[]
required
Array of { extension_id?: string, phone_number?: string, ring_seconds?: number } entries. Pass either extension_id (registered SIP extension) or a raw phone_number for PSTN forwards.
timeout_seconds
integer
default:"20"
Per-leg timeout (sequential strategy). Total ring time = members × timeout.
fallback_action
string
default:"voicemail"
Action when no member answers: voicemail, transfer_number, hangup.
GET /v1/voice/ring-groups GET /v1/voice/ring-groups/{id} DELETE /v1/voice/ring-groups/{id}

Extensions

SIP extensions for soft-phone registration. Each extension binds one user to a SIP credential pair (managed via the SIP Credentials endpoints) and can receive direct calls or appear in ring groups. Extensions are managed end-to-end through the dashboard at Voice → Extensions. The underlying call-flow surface (registering, rotating credentials, observing register state) is exposed via the SIP Credentials API at /v1/voice/sip-credentials/* (see SIP Credentials).

Calendars

Per-extension business-hours calendars route inbound calls to voicemail / a fallback number outside of working hours. Calendars carry an IANA timezone and a list of weekday windows.

Create a Calendar

POST /v1/voice/calendars
name
string
required
Calendar name.
timezone
string
required
IANA timezone, e.g. Europe/Istanbul.
weekday_windows
object[]
required
Array of { weekday: 0-6, start: "HH:MM", end: "HH:MM" }. weekday follows ISO-8601 (1=Mon, 7=Sun).
holidays
string[]
Array of ISO-8601 dates (YYYY-MM-DD) treated as off-hours.

List / Get / Delete

GET /v1/voice/calendars GET /v1/voice/calendars/{id} DELETE /v1/voice/calendars/{id}

Monitoring

Live supervisor surface — listen-in, whisper to the agent, or barge into a call for real-time coaching. All operations require the voice:monitor scope.

Start Listening (silent monitoring)

POST /v1/voice/calls/{id}/listen Open a one-way audio bridge to the supervisor — neither call leg hears the supervisor. POST /v1/voice/calls/{id}/unlisten Disconnect the supervisor leg.

Whisper to the Agent

POST /v1/voice/calls/{id}/whisper Audio plays only to the agent leg. The customer cannot hear. Use to coach the agent mid-call.

Barge In

POST /v1/voice/calls/{id}/barge Add the supervisor as a third audible participant. Both call legs hear the supervisor.

Live Monitoring Snapshot

GET /v1/voice/monitoring Returns a denormalised snapshot of every active call, queue, and agent presence — drives the wallboard / Voice → Monitoring page.
{
  "data": {
    "active_calls": 14,
    "queued_calls": 3,
    "available_agents": 7,
    "busy_agents": 5,
    "calls": [
      {
        "id": "call_abc123",
        "from": "+14155552671",
        "to": "+18005551234",
        "agent_id": "agt_support_jane",
        "duration_seconds": 87,
        "queue_id": "queue_support",
        "started_at": "2026-03-08T11:58:33Z"
      }
    ]
  }
}

Real-time Transcripts

GET /v1/voice/calls/{callId}/transcript/stream Server-Sent Events (SSE) stream of live STT transcript chunks for an in-progress call. Each event carries a JSON body of:
{ "speaker": "agent" | "caller", "text": "...", "ts": "ISO-8601" }
Use for live captions, real-time agent assist, or downstream sentiment / intent classification. The stream closes when the call ends. GET /v1/voice/calls/{id}/transcript Final, post-call transcript (one shot, no streaming). Available once the recording has been processed (~30s after hangup). POST /v1/voice/transcribe Submit an arbitrary audio URL for asynchronous transcription. Returns a transcript_id to poll for the result.

AI Call Intelligence

Post-call analysis — sentiment trajectory, key moments, summary, action items, customer effort score. Powered by the agent runtime’s call intelligence model.

Per-Call Intelligence

GET /v1/voice/calls/{id}/intelligence
{
  "data": {
    "call_id": "call_abc123",
    "summary": "Customer called to dispute a duplicate charge dated 2026-03-05 for $89.00. Agent confirmed the charge was a billing system retry artifact, refunded immediately, sent confirmation email.",
    "sentiment": {
      "overall": "neutral_to_positive",
      "trajectory": "improved",
      "agent_score": 0.82,
      "caller_score": 0.65
    },
    "key_moments": [
      { "ts": 12, "type": "intent_detected", "label": "billing_dispute" },
      { "ts": 47, "type": "frustration_peak", "score": 0.78 },
      { "ts": 134, "type": "resolution_offered" },
      { "ts": 189, "type": "satisfaction_signal", "score": 0.85 }
    ],
    "action_items": [
      "Send refund confirmation email by EOD",
      "Flag billing system for duplicate-charge investigation"
    ],
    "customer_effort_score": 2.4,
    "agent_compliance_flags": [],
    "language": "en-US",
    "processed_at": "2026-03-08T12:08:14Z"
  }
}

Run Sentiment On-Demand

POST /v1/voice/calls/{id}/sentiment Forces a re-run of the sentiment analyzer. Used when a call’s transcript has been edited or when the org’s sentiment model has changed.

List Intelligence Records

GET /v1/voice/intelligence/calls List intelligence records for the org with filters by sentiment, agent, date range, and customer-effort threshold. GET /v1/voice/intelligence/trends Aggregated time-series of sentiment + effort score, bucketed by day / week. Drives the Voice → Intelligence → Trends dashboard.
from
string
ISO-8601 start of the trend window. Defaults to 30 days ago.
to
string
ISO-8601 end of the trend window. Defaults to now.
bucket
string
default:"day"
Aggregation bucket: hour, day, week.

Voice Quality (VAQI)

Voice Aggregated Quality Index — a 0–100 score derived from MOS, jitter, packet-loss, and one-way audio detection. Surface for SIP-trunk health and per-call diagnostics.

Aggregates

GET /v1/voice/quality/aggregates Per-period rollup of every active SIP trunk: average MOS, p95 jitter, packet loss percentage, VAQI score. Used by the Voice → Quality dashboard.

Per-Carrier Quality

GET /v1/voice/quality/carriers Same shape as /aggregates but bucketed by upstream carrier. Use to compare provider performance across the same time window.

Worst Calls

GET /v1/voice/quality/worst-calls Top-N calls in the period by lowest VAQI / highest packet loss / highest jitter. Drives the “Investigate” CTA in the dashboard.

VAQI Detail

GET /v1/voice/vaqi Full per-call quality matrix (MOS, jitter, packet loss, RTT, audio gaps) with optional call_id filter for a single-call drill-down.

Softphone Token

POST /v1/voice/softphone/token Mints a short-lived JWT (default 60s expiry) for browser-based softphone clients to register against the LiveKit / Jambonz cluster without exposing a long-lived API key. POST /v1/voice/softphone/dial Server-initiated outbound dial from a softphone session — the softphone client passes the to and Orbit places the call from the bound extension’s caller-ID.

Voice Clones

Custom-trained TTS voices for AI agents. Voices are tenant-scoped and require an upfront audio-sample upload — at least 30 seconds of clean speech from a single speaker, ≥ 16 kHz mono WAV / MP3 / FLAC.

Create / List / Delete

POST /v1/voice/clones GET /v1/voice/clones DELETE /v1/voice/clones/{id} Voice IDs returned by GET /v1/voice/clones can be referenced from agent configuration via tts_voice_id.

Call Statuses

StatusDescription
initiatingCall is being set up
ringingDestination phone is ringing
in_progressCall is connected and active
completedCall ended normally
failedCall could not be connected
busyDestination returned busy signal
no_answerDestination did not answer within timeout
cancelledCall was cancelled before connection

Examples

Node.js

const orbit = new Devotel({ apiKey: 'dv_live_sk_xxxx' })

const call = await orbit.voice.calls.create({
  to: '+14155552671',
  from: '+18005551234',
  agentId: 'agt_support',
  record: true,
})

console.log(call.data.id) // call_abc123

Python

orbit = OrbitClient(api_key="dv_live_sk_xxxx")

call = orbit.voice.calls.create(
    to="+14155552671",
    from_number="+18005551234",
    agent_id="agt_support",
    record=True,
)

print(call.data.id)  # call_abc123