Skip to main content

Assign and reassign numbers

An Orbit number is only “assigned” once it terminates somewhere: an AI agent, an IVR, a queue, a ring group, voicemail, a SIP forward, or a webhook. This guide walks the full assignment workflow — where to assign in the dashboard, when the bulk Assignment Portal beats per-number editing, how tracking pools (DNI) interact with assignments, how per-user PBX/SIP registration fits in, and the fallback order the routing engine runs through. Reads need the numbers:read scope; every assignment or routing mutation needs numbers:write. Route targets live in your org’s tenant schema, and all below endpoints are org-scoped — a sibling subaccount cannot wire a number it doesn’t own.

1. Where to assign: per-number detail vs the bulk portal

Two entry points cover the assignment surface. Per-number detail — open a DID’s page at Numbers → pick a number. The routing card on that page edits the inbound route for this one DID (PUT /numbers/{phone}/routing). Use it when you need a single line’s route changed, or when you’re inspecting what a specific number currently answers with.
Assignment Portal (bulk) — Numbers → Assignment Portal (/numbers/assignments). One screen: unassigned (and optionally assigned) DIDs in the left column, destinations (AI agent, IVR flow, ring group, queue, voicemail, SIP forward, webhook) in the right column. Drag a DID onto a destination, confirm in the sheet, and the portal fires one PUT /numbers/{phone}/routing per dropped DID. Use it when you onboard a block of purchased DIDs or re-wire a whole team’s lines at once — it replaces the multi-menu per-number loop. Route types the portal and the per-number routing surface accept: agent, softphone_user, softphone_register, ivr, queue, ring_group, voicemail, sip_forward, transfer, conference, shared_line, dispatch_to_voicemail_box, webhook, and decline. The full per-type config catalog is in Phone Numbers.

2. Inventory source — where assignable numbers come from

The Assignment Portal reads planned inventory, not a separate pool. A DID shows up in the portal’s left column when it is active on your org and its route is unset (or when you filter the column to include already-assigned DIDs). Inventory enters the portal from three sources:
  • Purchased numbers (Buy and provision numbers, Numbers → Buy) — DIDs bought in the dashboard land here immediately after provisioning completes.
  • Hosted messaging (Hosted messaging, Numbers → Hosted Messaging) — DIDs you keep at another carrier but host on Orbit for SMS keep their inbound routes assignable exactly like a purchased DID.
  • Port-ins (Port numbers, Numbers → Porting) — a completed port appears with no route set; the portal is the fastest way to wire a ported block.
Capabilities travel with the DID: a sms-only inventory unit cannot terminate a voice route, even if the portal lets you drop it onto a queue destination. Check capabilities on GET /numbers/{id} before mapping a destination that expects voice. The bulk operations recipes (batch-buy, release sweeps) are in the Numbers cookbook.

3. Walkthrough — assign inventory to a campaign or flow

Use the portal when the assignment target is a destination you already built — an IVR flow backing a marketing campaign, a queue for the support team, an AI agent pilot.
  1. Open Numbers → Assignment Portal. The left column lists DIDs with no route; toggle it to show assigned DIDs when you want to re-wire.
  2. Filter the inventory by capability (voice / SMS), country, or search string so the block you’re assigning is the block you actually owns.
  3. Pick the destination in the right column — the IVR flow your campaign dials into, the queue, ring group, AI agent, voicemail, SIP forward, or webhook. The right-column destination cards show each destination’s current wiring, so you see exactly what stays untouched.
  4. Drag the DID onto the destination (or activate select mode and pick it). A confirmation sheet lists every pending PUT /numbers/{phone}/routing the portal is about to fire — one per dropped DID.
  5. Confirm. Each row applies as its own write; the sheet reports per-DID success/failure, so a single 422 (a mis-keyed config, a capability mismatch) does not roll back the DIDs that already applied.
Unassigning works the same way in reverse: set the DID’s route to decline, or drop it onto the empty target to clear it. There is no separate “unassign” verb — an assignment is a route value, and clearing the route returns the DID to the portal’s unassigned column.

4. When assignment is reversed — releasing inventory

When a campaign, a seasonal flow, or a ported block stops carrying traffic, you reuse the DIDs rather than abandoning them. Assignment is reversible end to end.
  1. Read the current route first. GET /numbers/{phone}/routing — you want to know whether you’re unwinding a live destination or a stale one.
  2. Clear or repoint the route. To free the DID back into the portal’s unassigned column, PUT a decline (or simply re-assign it to the new destination in one move — the route is single-valued, so one PUT replaces the old target).
  3. Keep or release. A cleared DID stays on your org’s inventory until you release it (Number Lifecycle covers scheduled release + reclaim). Keep it if the next campaign reuses the same sender block; release it to stop the monthly recurring charge.
Tracking pools unwind the other way — the DID’s own route stays as the fallback. Section 5 covers that two-layer model.

5. Assignments vs tracking pools (DNI) — what unwinds

Assignment and attribution are two different layers that operate on the same DID.
  • The inbound route on a DID (/numbers/{phone}/routing) says who answers the call.
  • A tracking pool (Call tracking & DNI) says which marketing source the call attributes to. Pool assignment lives in org settings JSONB; route assignment lives on the per-DID inbound_routes row.
When you wire a tracking DID into a pool, keep its inbound route as a fallback: a visitor whose session doesn’t resolve a pool DID (or when the pool is disabled) still hits the DID’s own route. When a tracking pool DNI session un-winds — swap a DID back out of a pool — the underlying inbound route is untouched. Assignment unwinds one layer; the other survives. If an inbound call appears to ignore its queue and ring a temporary tracking number instead, check the pool first: pools override the displayed DID at the attribution layer, not the routing layer, so the call’s target stays whatever the route says. Scope note: pool membership is an org-level attribute; two sibling subaccounts on the same parent cannot hold the same DID in different pools.

6. Per-user PBX/SIP registration

Route type sip_forward (that’s the type value) forwards inbound calls onto a SIP URI — the general-purpose case for BYO-PBX trunks (your console’s own PBX / Asterisk / FreeSWITCH / 3CX), plus the per-user case where individual extensions answer. The full PBX walkthrough (outgoing-direction trunk, transport UDP/TCP/TLS, registration health) is in Register your PBX on Orbit. The assignment step from this guide is: once the PBX trunk is registering healthy, point each DID at that trunk’s SIP URI via sip_forward. Per-user ring behavior — one DID ringing a specific extension — is a softphone_user or softphone_register route, and a shared-appearance group on a department line is shared_line. A DID’s inbound route is ONE target; mixing PBX trunking with app-side destinations means choosing a route per DID. A common pair is a main-line DID routing to a queue and an overflow/reassigned DID pointing at the PBX.

7. Fail-safe fallback order

When a route target is unhealthy or empty, the routing engine walks a deterministic fallback order instead of dropping the caller:
  1. Queue — try the named queue first. Queue membership + skill routing + queue-level business hours run under this step.
  2. Ring group — if the queue has no agents, no agents within the business-hours gate, or a queue-level failure, the ring group the fallback is configured with rings. Group strategy (simultaneous, sequential, round-robin) applies here.
  3. Voicemail — if the ring group also doesn’t answer, the DID’s voicemail (or dispatch_to_voicemail_box for a shared department mailbox) catches the call.
This is the reason an assignment isn’t just “one DID → one destination.” A queue assignment implicitly names its own fallback chain (que_support → ring_group_x → voicemail). Operators designing assignments should set the queue route on the DID and then verify the queue’s configured ring-group fallback exists; the per-DID voice-queues and voicemail-boxes guides cover the group/mailbox side.

8. Conflict scope — when assignments fight

Two assignment surfaces target the same DID; know which one wins.
  • DNI pool vs direct route: pool assignment wins for attribution; the direct route still decides who answers. Never both a pool-bound tracking DID AND a per-DID route you expect to be the “real” answerer — pools are inbound-only and never override the sip_forward/queue target.
  • Reassign across subaccounts (Number Lifecycle): POST /numbers/{id}/reassign moves ownership to a sibling subaccount. The org-level route (/numbers/{phone}/routing) the target org will see is whatever that org wires up itself after reassignment — ownership move and route move are separate steps.
  • decline: a DID set to decline explicitly silences inbound. It’s a deliberate assignment, not “unassigned.”
  • webhook (Twilio voiceUrl parity): a webhook route takes over the whole call’s call-control — assigning a webhook wins over every in-platform destination by design.

9. Re-assignment examples with a dry-run

Reassignments fall into two flavors:

Move one DID’s route

The same call returns 422 when the sip_forward uri is malformed, the queue config carries no queueId, or the ivr flow id is absent — the strict write schema rejects mis-keyed blobs instead of silently persisting a route the runtime can’t interpret.

Reassign ownership to a sibling subaccount

Constraints: target must be a same-tenant, same-family sibling; the caller must currently own the DID; trial-pool claims and numbers you only borrowed can never be reassigned. See Number Lifecycle.

Dry-run strategy

There is no server-side dry_run: true flag on the routing PUT. The safest pre-flight is:
  1. GET /numbers/{id} — confirm the DID is active and carries the capabilities the route expects (a voice route on a sms-only DID will write but never terminate a call).
  2. GET /numbers/{phone}/routing — read the CURRENT route so you know what you’re replacing.
  3. Software-side: run candidates through the strict schema you’ve already got client-side (queue needs queueId; IVR needs flowId; sip_forward needs a uri) before the PUT.
If a destructive bulk change is on the table, run it through the Assignment Portal first — the portal surfaces the current route per DID in its right-column destination cards, so you see exactly what the pending confirm will overwrite.

10. Troubleshooting

See Also