Documentation Index
Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
Use this file to discover all available pages before exploring further.
Programmable Voice DSL Reference
When you point one of your Devotel phone numbers (DIDs) at an
HTTPS answer URL, Orbit turns that DID into a fully programmable
inbound call — the Twilio voiceUrl / Vonage answer_url model. On
every inbound call Orbit performs a server-side HTTP request to your
URL with the call metadata and expects a JSON response describing what
to do with the call. That JSON is a list of verbs — the
programmable-voice DSL documented here.
The runtime contract is implemented by the webhook inbound-route
handler (buildWebhookVerbs in apps/api/src/routes/jambonz/verb-builder.ts)
and pinned as the VoiceDslVerb OpenAPI component
(apps/api/src/lib/openapi-schemas.ts).
Outbound calls always terminate through the Devotel softswitch.
Every dial verb is routed through Devotel’s wholesale softswitch trunk.
You cannot select an arbitrary carrier, Telnyx Call Control, or DIDWW for
the outbound leg — any carrier-selection field you return is ignored.
Quality, STIR/SHAKEN signing, and PSAP routing are owned by Devotel.
The request Orbit POSTs to your answer_url
On each inbound call, Orbit sends an HTTP request to your configured URL.
The default method is POST with a JSON body; if you configured GET,
the same fields arrive as query-string parameters.
{
"callSid": "call_01HZX...",
"from": "+14155550123",
"to": "+442071234567",
"dialedE164": "+442071234567",
"routeId": "route_01HZX...",
"organizationId": "org_01HZX..."
}
| Field | Type | Description |
|---|
callSid | string | Unique per-call identifier. Stable for the life of the call. |
from | string | null | Caller’s E.164 number, or null when withheld. |
to | string | The dialed E.164 number (your DID). Alias of dialedE164. |
dialedE164 | string | The dialed E.164 number (your DID). |
routeId | string | The inbound-route record that pointed this DID at your URL. |
organizationId | string | Your Orbit organization ID. |
The response your answer_url returns
Respond with Content-Type: application/json and either an envelope or a
bare array of verbs:
{
"verbs": [
{ "verb": "say", "text": "Thanks for calling Acme." },
{ "verb": "dial", "target": [{ "type": "phone", "number": "+14155550123" }] }
]
}
A bare array is also accepted:
[
{ "verb": "say", "text": "Thanks for calling Acme." },
{ "verb": "hangup" }
]
The verbs run top-to-bottom. If your URL times out (default 5s, hard cap
10s), returns a non-2xx status, returns non-JSON, or returns an empty /
malformed array, Orbit emits the route’s configured fallback verbs so
the caller never lands on dead air.
Verbs
Each verb object is discriminated by its verb field.
say
Text-to-speech playback to the caller.
{ "verb": "say", "text": "Your call is important to us." }
| Field | Type | Description |
|---|
text | string | The text to synthesize and play. |
play
Play a pre-recorded audio file. The URL must be https:// and is
SSRF-validated at configuration time.
{ "verb": "play", "url": "https://cdn.example.com/greeting.wav" }
| Field | Type | Description |
|---|
url | string (https URI) | The audio file to stream to the caller. |
gather
Collect DTMF and/or speech input from the caller.
{
"verb": "gather",
"input": ["digits"],
"numDigits": 1,
"timeout": 10,
"actionHook": "https://app.example.com/voice/ivr-step"
}
| Field | Type | Description |
|---|
input | string[] | Collection modes: "digits", "speech", or both. |
numDigits | integer | Stop collecting after this many DTMF digits. |
timeout | integer | Seconds to wait for input before falling through. |
actionHook | string (https URI) | URL Orbit POSTs the collected input to; returns the next verb list. |
dial
Bridge the caller to an outbound leg. Routed exclusively through the
Devotel softswitch trunk (invariant #45) — you cannot select a carrier.
{
"verb": "dial",
"callerId": "+442071234567",
"timeout": 30,
"target": [{ "type": "phone", "number": "+14155550123" }]
}
| Field | Type | Description |
|---|
callerId | string | Caller ID presented on the outbound leg (must be a DID you own). |
target | object[] | Destinations to dial. Any carrier-selection field is ignored — termination is Devotel-owned. |
timeout | integer | Seconds to ring before treating the leg as no-answer. |
record
Toggle call recording. Subject to your tenant recording-consent gate.
{ "verb": "record", "record": true }
| Field | Type | Description |
|---|
record | boolean | true to start recording, false to stop. |
enqueue
Park the caller in a named queue (e.g. for ACD / contact-center routing).
{ "verb": "enqueue", "queue": "support" }
| Field | Type | Description |
|---|
queue | string | The queue name to park the caller in. |
transfer
Hand the call off to another inbound route or destination.
{ "verb": "transfer", "destination": "+442071234999" }
| Field | Type | Description |
|---|
destination | string | The route, extension, or E.164 number to transfer to. |
hangup
End the call. Optionally supply a SIP reason surfaced in carrier CDRs.
{ "verb": "hangup", "reason": "Caller served" }
| Field | Type | Description |
|---|
reason | string | Optional human-readable hangup reason. |
Present an IVR menu — a say/play prompt paired with DTMF collection.
Functionally a higher-level gather whose collected digit maps to a
branch handled by your actionHook.
{
"verb": "menu",
"text": "Press 1 for sales, 2 for support.",
"input": ["digits"],
"numDigits": 1,
"actionHook": "https://app.example.com/voice/menu-choice"
}
| Field | Type | Description |
|---|
text | string | The prompt to play (or use url for pre-recorded audio). |
url | string (https URI) | Pre-recorded prompt audio (alternative to text). |
input | string[] | Collection modes (typically ["digits"]). |
numDigits | integer | Number of digits in the menu choice. |
actionHook | string (https URI) | URL Orbit POSTs the choice to for the next verb list. |
Failure handling
Orbit fails soft. If your answer_url is slow, unreachable, returns a
non-2xx, or returns a malformed body, the configured fallback runs
instead — one of:
- safe-default — a short apology prompt then hangup.
- voicemail — defer to the route’s voicemail configuration.
- decline — reject the call with a SIP
603 Decline.
The caller is never left on dead air, and the categorical failure reason
is logged for your route analytics without leaking operator topology.