1. What the routing config is
One row per DID. The core of it is a(type, config) pair:
type— the routing decision: run an IVR flow, drop into a queue, ring a softphone, take a voicemail, drop the call, and so on. The full enum is in section 2.config— a type-specific object. Each type accepts exactly one shape and validates it at write time, so a wrong-shaped config answers422instead of breaking mid-call.ivrtakes{ flowId };queuetakes{ queueId }; a department mailbox takes{ boxId };declinetakes no config at all.
fallback_type+fallback_config— a depth-1 fallback destination, used when the primary route fails (queue has nobody available, webhook URL times out). The fallback accepts the same type set, but onlyagent,softphone_user,softphone_register,voicemail,ivr,queue, andsip_forwardhave fallback editors in the dashboard.business_hours— a schedule gate in front of the route. Outside the window, the route behaves as if no schedule matched, and the caller follows your primary path (or the fallback when hours complement it).caller_id_filter— allow/block/VIP lists matched on the inbound caller number. A blocked caller short-circuits before the route fires; a VIP always passes.recording_mode— per-route override of the org recording default:off,all,inbound, oroutbound.sms_route_type+sms_route_config— an independent per-DID SMS termination (webhook,agent,auto_reply, ordisabled). Voice and SMS on the same DID are separate settings on the same row; the voice route never blocks the SMS route.active— flip off to deactivate the route without deleting it. An inactive DID falls through to your org default inbound handling.
2. The full route type enum
Thirteen values. Each is reachable from the dashboard picker, the API, and (where it makes sense) the IVR Builder’s attach surface.
The same enum is what DNIS pattern routing accepts per
target_type — the config shape you would send in target_config there is the same body you’d put on config here.
3. The three writing paths
All of them write the same row to the same endpoint; pick the surface you happen to be in. Dashboard — Numbers → number → Routing. The picker grid renders one card per route type with its label and description. Select a type and the config section below it swaps to the matching editor — IVR flows get a flow dropdown, queues get a queue dropdown, SIP forward gets trunk-or-URI fields, and types with no config (likedecline) hide the section. The fallback panel uses the same picker with the fallback-supported subset. Save writes the PUT below.
API — PUT /api/v1/numbers/:e164/routing. Programmatic and CI-friendly. The :e164 path parameter accepts the number with or without the leading + and stores it with one.
cURL
active, caller_id_filter, recording_mode (off | all | inbound | outbound), ring_group_id (required when type is ring_group), holiday_calendar_id, sms_route_type, and sms_route_config. (For the SMS sibling, webhook takes { url, method?, secret?, fallback_url?, fallback_method?, fallback_secret? }, agent takes { agentId }, auto_reply takes { body: string (≤1600 chars) }, and disabled takes {}.)
The shape of (type, config) is strict — a mismatched pair returns 422 with a message naming the expected shape (queue route requires { queueId, ... }), not a saved-and-broken-at-runtime. GET /api/v1/numbers/:e164/routing returns the current value; a sip-forward password comes back as *** and re-sending the redacted sentinel preserves the stored password.
From the IVR Builder. In Voice → IVR Builder the toolbar has an attach action that writes the same row with type: "ivr" and the current flow id — so the authoring screen owns the attach for the IVR case specifically, while the others write through the Numbers page or the API.
Bulk apply exists too: POST /api/v1/numbers/routing/bulk runs the same per-DID validation across a list of numbers and returns per-item outcomes.
4. Decision: which type for which scenario
Answer the question in the table; the overflow / backup column tells you what to set as the fallback while you configure the primary.
When in doubt,
queue with a voicemail fallback beats a bare direct line: it absorbs bursts, gives you queue health metrics, and stays under one DID while the IVR question stays open.
5. Companion routing — patterns, keywords, and messaging
The per-DID route is the top of the inbound chain. Three sibling features route the same traffic at a different layer; pick them alongside the route type, not instead of it.- DNIS pattern routing — one
target_type+target_configrule per a block of DIDs, matching by E.164 prefix or regex. Per-DID routing (this page) always wins: a specific DID with its own entry beats the pattern, so use patterns as the fallback layer under your explicit numbers. - Keyword auto-reply rules — on the SMS/WhatsApp/RCS/Viber side, a rule fires before a human sees the inbox: reply, opt-in/out, hand to an agent, or trigger a flow. Voice routing is untouched by it; message routing picks up where
[sms_route_type](#1-what-the-routing-config-is)terminates. - Hosted messaging — when a DID is provisioned for messaging at hosting, the inbound SMS destination is decided at order time. The
sms_route_typesibling on this row re-points it after activation, per DID.
6. Verify with the simulator before you attach
For theivr type, the simulator (POST /api/v1/voice/ivr-flows/:id/simulate) drives a scripted caller through the graph without burning a live minute. Run it on the published snapshot before the attach step — that is what the routing row actually answers with:
cURL
reached_nodes, emitted_verbs, and termination_reason per turn. source: "published" walks the live snapshot; source: "draft" (the default) walks the unsaved draft — publish first, then simulate published, then attach the routing row. Sending a definition inline simulates a candidate graph without saving.
For the non-IVR types, verification is a real inbound call to the DID, watched in the call log — or a dashboard re-read of the routing tab to confirm the saved (type, config). Attach-time 422s are the guard that catches a shape error before either of those.
7. Common mistakes
- Attaching a draft IVR. The route stores the flow’s id; the gateway resolves the published head at call time. If you wrote the row before you published, the caller hears whatever was last published — sometimes the empty stub, sometimes an older version. Publish, simulate
source: "published", then attach. - Missing
flowIdonivr, missingqueueIdonqueue, missingboxIdondispatch_to_voicemail_box. Strict-shape validation rejects the write with422and a message naming the required field — but the Numbers tab that echoes a saved row with an empty config section wrote it before this validation existed. If an existing DID answers the wrong destination, re-save the route with the config filled in. - Sending the redacted
sip_forwardpassword. Readback returnssipPassword: "***". If you POST that literal***back without retyping the password, the API preserves the stored one — but pasting***into a brand-new route stores a literal***as the password. Retype it on change. - Setting the fallback to a type the dashboard can’t configure. The fallback panel only edits
agent,softphone_user,softphone_register,voicemail,ivr,queue, andsip_forward. Richer primary-only types (transfer,conference,decline,ring_group,dispatch_to_voicemail_box,shared_line,webhook) save an empty config when picked as a fallback from an older dashboard — a422on the types that need a target. Pick the fallback from the supported subset. - Putting the ring-group identity in
config.ring_groupaccepts{}— the group id lives in the siblingring_group_idfield on the body, not insideconfig. Aconfig.ringGroupIdkey is a strict-mode422. - Two routes for one DID. There is one row per DID — a second
PUTreplaces the first. If you need two destinations, usefallback_type; if you need a menu in front, put both behind anivrflow and route inside it. business_hourswritten with the wrong key spelling. The strict schema accepts only{ days, start, end, timezone }(numeric or"mon"..-style day names) or the per-day{ mon: { open, close }, ... }shape. A mis-typed key (startTime,tz) now answers422at write — before this, it silently meant “no schedule”. If a schedule looks inactive, re-check which shape you saved.- Keyword rules vs
auto_reply. A bulksms_route_type: "auto_reply"replies one fixed body to every inbound text on the DID; a keyword rule replies only when its keyword matches. Don’t setauto_replyon a number that also runs keyword rules — the per-DID reply fires before rules evaluate.
See also: DNIS pattern routing · Build an IVR flow · Voice queues · Voicemail boxes · Keyword auto-reply rules · Hosted messaging