Numbers & call routing
IVR
An IVR (auto-attendant) menu plays a greeting and routes the caller by the key they press, with separate behaviour for open hours, closed hours and the case where no key is pressed. In V2 this group is a single operation, PUT /v2/ivr/{id}/menu, which replaces the whole configuration of IVR {id}. Listing, creating and deleting IVRs is still done through V1 (GET /v1/ivr_menu, POST /v1/ivr_menu_new, DELETE /v1/ivr_menu/{id}), and an IVR is attached to a number in the portal under Numbers & Inbound Call Routing.
Workflow (what the portal does)
GET /v1/ivr_menureturns every IVR with itsnameand adataobject in exactly the shape the PUT expects. Edit that object rather than building one from scratch.- Collect the identifiers your actions will point at:
- announcement slots 10–99, uploaded with
POST /v2/announcements/upload-audio(account admin); - extension numbers from
GET /v2/extensions; - queue numbers (not queue ids) from
GET /v2/queues; - SMS template ids from
GET /v2/sms-templatesfor "send a message"; - call tag ids, other IVR ids, or a phone number for "forward".
- announcement slots 10–99, uploaded with
- Build
data:options_msg_enabled: whether digits 0–9 are offered at all.initial.ring_duration(0–30 seconds) andinitial.message(an announcement slot): what happens before the menu.open.message,open.pause(seconds to wait for a key: 0.1, 0.5, 1…20, 25 or 30),open.actions(exactly ten entries, digits 0–9) andopen.fall_through(no key pressed).close.actionsfor out-of-hours calls and, when its first action is "play message" (1),close.on_event_actionsfor a key pressed during that message.- Every action is
{"action_1": {"id", "value"}, "action_2": {"id", "value"}}.valueis always a string of at most 50 characters: an extension number, a queue number, an announcement slot, an IVR id, a phone number, comma-separated tag ids or a template id.
PUT /v2/ivr/{id}/menuwithnameanddata.204means saved, and the change is live for the next call: there is no provisioning step.- Opening hours and holidays live outside this group and take
menu_id= the IVR id: opening hours through V1 (PATCH /v1/opening_hours), public holidays withPATCH /v2/ivr/public_holiday_settingsand custom holidays withPATCH /v2/ivr/custom_holiday_settings.
Actions
- First action (
action_1.id):0hang up,1play message,2dial extension,3join queue,4play prompt then dial the entered number,6voicemail,7repeat the options,8forward to a number,9go to another IVR,13add a call tag,14send a message. - Second action (
action_2.id):0none,1dial extension,2join queue,4dial the entered number,5fall through,6voicemail,8forward,9go to another IVR,14send a message. - Chaining: after
1,3or13any second action is allowed; after4only4or14; after everything elseaction_2.idmust be0. The fall-through slot has no second action5; the closed slot has no first action7.
Call routing
flowchart TD
call["Incoming call"] --> initial["initial.ring_duration + initial.message"]
initial --> hours{"Open hours?"}
hours -- "open" --> menu["open.message, open.pause"]
menu -- "digit 0-9 pressed" --> actions["open.actions[digit]: action_1 (+ chained action_2)"]
menu -- "no key pressed" --> fall["open.fall_through"]
hours -- "closed or holiday" --> close["close.actions"]
close -- "action_1.id 1 (play message)" --> event["close.on_event_actions on keypress"]
actions --> terminal["Terminal action: hang up, dial extension/queue, voicemail, forward, another IVR, add tag, send message"]
fall --> terminal
close --> terminal
event --> terminal
Roles and access
- Account admin only (
403otherwise).
Pitfalls
- Full replacement: leave out
nameand the IVR is renamed to an empty string; a digit whose two actions are both0is removed; withoptions_msg_enabled: falsethe digits 0–9 are left as they were. - Validation checks every
idagainst the allowed list but not the chaining rules: an unchainable pair such as4followed by0fails with500, not422. - References are not checked to exist. A wrong slot, extension, queue number or template id only shows up when a caller reaches it.
open.actionsmust be a list of exactly ten entries for digits 0–9. An object keyed 1–10 passes the size check and then fails.{id}accepts 1–127 and creates the configuration row when it is missing, but IVRs themselves are only created through V1 (ids 1–31). Use ids you got from the list.initial.messageandopen.messageare integers 10–99; an empty string is treated as "no message".