Hotline APIBeta
A small, safe HTTP API for one account's call flow — the same operations the AI assistant uses. It can read the hotline, create extensions, wire menu keys and routes, set what prompts say, and undo any batch of its own changes. It cannot touch phone numbers, billing, contacts, users, or other accounts, and it never deletes anything it did not create.
Base URL: https://<your-app>/api/v1/hotline
Auth: Authorization: Bearer hl_… (create tokens under Account Settings → Hotline API).
Rate limit: 120 requests / minute per token. All bodies and responses are JSON.
Concepts
- Extension — one building block of a hotline: a menu (
ivr), audio player (library), message box (record), single recording (play), forward (transferToNumber), dial-out (dial), access check (validation), exam, conference, redirect, bookmark, label actions, or custom code (twiml).GET /typeslists each with its prompts, settings and named routes. - Keys — a menu sends callers on by the key they press:
1–9,0,*,#. - Routes — other extensions continue through named routes, e.g. a
recording's
after, an access check'ssuccess/failed, an exam'ssuccess/failed/after(closed). - Prompts — what an extension says. Set them as text; audio is rendered in the background (usually within a minute or two). Until then callers hear the same text spoken by the fallback voice, so the flow is usable immediately. You may also pass an existing audio URL. Note: Yiddish text-to-speech quality is poor — for Yiddish prompts, record audio and pass its URL instead.
- Change sets — every write is recorded in a change set.
POST /change-sets/{id}/undoreverts the whole batch (created things are removed, keys/routes/prompts/settings restored). Passchange_set_idon later writes to add them to an existing batch. - Names are unique per account across all extension types.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /describe?depth=6 |
The hotline as a tree from its entry (phone number / test pin): root menu, keys, routes; plus unreachable extensions. |
| GET | /types |
Catalog of extension types, their prompts, settings and routes. |
| GET | /extensions?type=ivr |
List extensions (optionally one type). |
| GET | /extensions/{type}/{id} |
One extension: prompts, settings, keys (menus), routes, how callers reach it. |
| POST | /extensions |
Create: {type, name, settings?, prompts?, voice?}. |
| PATCH | /extensions/{type}/{id} |
Rename and/or update settings: {name?, settings?}. |
| PUT | /extensions/{type}/{id}/prompts/{slot} |
Set a prompt: {text, voice?} — text may be words or an audio URL; empty clears. |
| PUT | /extensions/{type}/{id}/routes/{slot} |
Set a named route: {target_type, target_id} (nulls clear it). |
| POST | /menus |
Create a menu with keys in one call: {name, greeting?, keys?: {"1": {type, id}}, voice?}. |
| PUT | /menus/{menu}/keys/{key} |
Point a key: {target_type, target_id}. |
| DELETE | /menus/{menu}/keys/{key} |
Clear a key. |
| GET | /change-sets |
Recent batches. |
| GET | /change-sets/{id} |
One batch with its changes. |
| POST | /change-sets/{id}/undo |
Revert the batch. |
| GET | /libraries, /labels |
Helpers for record.recordable_id and label actions. |
Every write response carries change_set: {id, audio_pending}.
Errors are {error: "…"} with 401 (token), 404 (not found), 422 (refused, with a human-readable reason).
Settings per type
| Type | Settings |
|---|---|
ivr |
active |
library |
listening_order (asc/desc), active |
record |
recordable_id (library), conformation (ask to confirm), save_on_hangup, max_length, min_length, active |
transferToNumber |
number (digits with country code, required), caller_id, call_timeout |
dial |
caller_id |
validation |
type (pin / contacts / all_contacts / labels), pin (required for pin), active |
exam |
passing_score, allow_retakes, keep_all_attempts, announce_score, active |
conference |
pin, moderator_pin, max_members |
bookmark |
type (single / multiple) |
addToLabel / removeFromLabel |
label_id (required) |
twiml |
url (required), method, active |
Prompt slots: ivr.greeting, play.audio, record.before|after|confirmation,
library.intro|menu, exam.intro|score_intro|correct|incorrect|closed|already_taken,
validation.pin_prompt|pin_retry|pin_failed|identify_prompt|personal_pin_prompt|identify_failed,
addToLabel.message, removeFromLabel.message. Voices: alloy, echo (default), fable, onyx, nova, shimmer.
Example — build a small hotline
TOKEN=hl_…
H="Authorization: Bearer $TOKEN"
API=https://hotlines.example.com/api/v1/hotline
# 1. A recording and a message box
curl -s -X POST $API/extensions -H "$H" -H 'Content-Type: application/json' \
-d '{"type":"play","name":"Office hours","prompts":{"audio":"We are open Sunday to Thursday, nine to five."}}'
# → data.id = 41, change_set.id = 7
curl -s -X POST $API/extensions -H "$H" -H 'Content-Type: application/json' \
-d '{"type":"record","name":"Leave a message","settings":{"conformation":true},"change_set_id":7}'
# → data.id = 154
# 2. A menu pointing at them (same batch)
curl -s -X POST $API/menus -H "$H" -H 'Content-Type: application/json' \
-d '{"name":"Front desk","greeting":"Welcome. Press 1 for office hours, 2 to leave a message.","keys":{"1":{"type":"play","id":41},"2":{"type":"record","id":154}},"change_set_id":7}'
# 3. Look at it — or undo the whole batch
curl -s $API/describe -H "$H"
curl -s -X POST $API/change-sets/7/undo -H "$H"
Notes for integrators and the assistant
- Reads are free of side effects; make as many as you like before writing.
- Prefer one change set per user intention ("add a Shiurim menu") so undo maps to something a person recognises.
describemarks extensions no caller can reach underunreachable— offer to connect or ignore them, never delete them.- Audio rendering is asynchronous: tell people "the recordings will be ready in a few minutes"; poll
change_set.audio_pendingif you need to know.