Skip to main content
Every phone number you own has an inbound routing config: the per-DID instruction that decides where an arriving call goes. It is one of the first decisions you make on a new number — before the IVR question, before staffing a queue — and it is a common support point because the route type is a single choice with very different consequences. This guide lays the full set of route types side by side, gives a decision table, and covers the ways to set and verify the choice. Intents, keywords, DNIS patterns, and messaging-side routing are companions to this decision, not replacements for it — see section 5 for how they stack with the per-DID route. Routing here is inbound-only. Changing a number’s routing config never changes how your outbound calls are placed; outbound termination is unaffected by anything on this page.

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 answers 422 instead of breaking mid-call. ivr takes { flowId }; queue takes { queueId }; a department mailbox takes { boxId }; decline takes no config at all.
Optional siblings ride alongside:
  • 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 only agent, softphone_user, softphone_register, voicemail, ivr, queue, and sip_forward have 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, or outbound.
  • sms_route_type + sms_route_config — an independent per-DID SMS termination (webhook, agent, auto_reply, or disabled). 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.
The voice gateway resolves the routing on every inbound call. Writes apply immediately — the next caller to the DID gets the new destination.

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 (like decline) 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
Other accepted body fields: 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_config rule 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_type sibling on this row re-points it after activation, per DID.
Layer them: a DNIS pattern sends your forty-country support pool to one queue; keyword rules pre-answer the easy inbound texts on the same number; the IVR attaches to the specific DID you want to behave differently.

6. Verify with the simulator before you attach

For the ivr 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
The response returns 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 flowId on ivr, missing queueId on queue, missing boxId on dispatch_to_voicemail_box. Strict-shape validation rejects the write with 422 and 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_forward password. Readback returns sipPassword: "***". 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, and sip_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 — a 422 on the types that need a target. Pick the fallback from the supported subset.
  • Putting the ring-group identity in config. ring_group accepts {} — the group id lives in the sibling ring_group_id field on the body, not inside config. A config.ringGroupId key is a strict-mode 422.
  • Two routes for one DID. There is one row per DID — a second PUT replaces the first. If you need two destinations, use fallback_type; if you need a menu in front, put both behind an ivr flow and route inside it.
  • business_hours written 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 answers 422 at 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 bulk sms_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 set auto_reply on 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