> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Route many inbound numbers to one queue with DNIS patterns

> Match a block of inbound DIDs with one E.164 prefix or regex rule, send them to a single queue or IVR, and manage match precedence — from the dashboard or the API.

DNIS pattern routing maps inbound calls by the number the caller dialed (the DNIS). One routing rule matches a whole block of numbers — every DID your organization owns that starts with a given E.164 prefix, or every DID a regex captures — and sends those calls to one destination: a queue, an IVR flow, a voicemail box, or any other inbound target.

Use it when the same destination should answer many numbers: a support queue behind forty country DIDs, a campaign page that buys a new DID each week, a brand whose toll-free pool keeps growing. Without patterns, each new DID needs its own inbound routing entry; with patterns, one rule covers the block and every DID you add later that matches starts working immediately.

Per-number behavior you set in inbound routing is not replaced by this — a specific DID with its own routing entry always beats a pattern. Patterns are the fallback layer under your explicit per-number configuration.

DNIS routing is inbound-only: it decides where a call to your number goes once it arrives. Outbound termination is unaffected — adding, removing, or reordering these rules never changes how your outbound calls are placed.

**Base path:** `/api/v1/voice/dnis-routes`

**Authentication:** Clerk session (`Authorization: Bearer <token>`) or API key (`X-API-Key`).

**Scope:** `voice:write` for create, replace, and delete (owner, admin, or developer role); reads require a signed-in session or API key.

***

## 1. How matching works

Each routing rule is a tuple:

* **`pattern_kind`** — `prefix` or `regex`.
* **`pattern`** — the match expression. For `prefix`, an E.164 prefix such as `+4420` matches every dialed number that starts with it. For `regex`, a regular expression the dialed E.164 number must match in full, e.g. `\+1(800|888|877)\d{7}` for the classic US toll-free ranges. Patterns are stored and evaluated in E.164 form, so include the leading `+`.
* **`name`** — a label for the grid and audit log, e.g. "Support EN toll-free pool".
* **`priority`** — an integer, lower wins. Rules at priority 100 (the default) are considered before rules at priority 500; a priority-10 carve-out beats both.
* **`target_type` + `target_config`** — where a matched call goes. The target types are the same set inbound routing uses: `queue`, `ivr`, `agent`, `voicemail`, `sip_forward`, `transfer`, `conference`, `ring_group`, `shared_line`, `softphone_user`, `softphone_register`, `dispatch_to_voicemail_box`, or `decline`. The config shape is whatever that target type takes — the same JSON body you'd put on a matching inbound route, e.g. `{ "queueName": "Support_EN" }`.
* **`active`** — flip off to disable a rule without deleting it. Inbound calls it would have matched fall through to lower rules or your default handling.

When a call arrives on a DID your organization owns:

1. **A per-number override wins first.** If the dialed DID has its own entry in inbound routing, that entry handles the call — no pattern is consulted. This is how you carve out one special number from a block (see section 5).
2. **Among DNIS rules, the server evaluates your rules in precedence order:** lowest `priority` number first; within the same priority, the most specific pattern (longest pattern string) first; ties broken by the oldest rule. The first rule that matches the dialed number handles the call.
3. **If no rule matches,** the call falls through to your organization's default inbound handling.

Two practical consequences:

* **Specific beats general** only within the same priority. A broad prefix like `+1` at priority 10 still loses to a narrow prefix like `+1800555` at priority 10, but `+1` at priority 10 beats `+1800555` at priority 100. Keep broad catch-alls at a high priority number (e.g. 900) so narrow rules can sit below them.
* **Overlap is rejected, not silently tolerated.** Creating or replacing a rule whose pattern overlaps another active rule at the same priority returns `409` — ambiguous routing is an error, not a coin flip. Layer the rules on different priorities to express "broad fallback, narrow override."

Disabled rules (`active: false`) are never evaluated.

## 2. Manage rules from the dashboard

Open **Voice → DNIS pattern routing** (`/voice/dnis-routes`) in the dashboard. The page is a grid of your rules, already sorted in match-precedence order — the order the server evaluates them in.

**What you see in the grid:** one row per rule with **Name** (your label), **Pattern** (monospaced, with a `prefix` or `regex` badge next to it), **Target** (the target type, e.g. `queue`), **Priority** (the integer), and **Status** (`Active` or `Inactive` badge). The rightmost column carries an edit pencil and a delete button on each row. Above the grid, a filter box narrows the rows by name, pattern, or target — useful once a pool grows past a screen of numbers. When you have no rules yet, the page shows an empty state with a **Create rule** button.

**To create a rule:**

1. Click **Create rule** (top right).
2. In the dialog, set **Name**, **Pattern kind** (`E.164 prefix` or `Regex`), **Priority** (default 100, lower wins), and the **Pattern** itself — prefix example `+1800`, regex example `\+1(800|888|877)\d{7}`.
3. Choose the **Target type** and fill **Target config (JSON)** with that target's settings, e.g. `{ "queueName": "Support_EN" }`. The same shape you'd use on the matching inbound-route type. Leave it `{}` for targets that need no config.
4. Leave **Active** on, click **Create rule**.

The dialog validates as you type: a prefix must be `+` followed by digits, a regex must compile, the config must parse as a JSON object, and priority must be a whole number. Invalid fields show an inline message and block submit — so you fix them before any API round-trip.

**To edit or delete:** use the pencil (opens the same dialog prefilled — a save replaces the rule) or the trash icon (asks for confirmation first, because numbers matched only by that rule fall through to your default handling on delete). Deleting shows the rule's name in the confirmation so you delete the right one.

<Warning>
  A rule change takes effect on the next inbound call. Calls already in progress keep the route they were dispatched with.
</Warning>

## 3. Manage rules over the API

The same CRUD the dashboard uses is public:

| Method   | Path                             | Purpose                                  |
| -------- | -------------------------------- | ---------------------------------------- |
| `GET`    | `/api/v1/voice/dnis-routes/`     | List your rules (match-precedence order) |
| `POST`   | `/api/v1/voice/dnis-routes/`     | Create a rule                            |
| `GET`    | `/api/v1/voice/dnis-routes/{id}` | Fetch one rule                           |
| `PUT`    | `/api/v1/voice/dnis-routes/{id}` | Replace a rule (full update)             |
| `DELETE` | `/api/v1/voice/dnis-routes/{id}` | Delete a rule                            |

Create a rule that sends every UK geographic London number you own to the support queue:

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/voice/dnis-routes/" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "UK London geo pool",
    "pattern_kind": "prefix",
    "pattern": "+4420",
    "priority": 100,
    "target_type": "queue",
    "target_config": { "queueName": "Support_EN" },
    "active": true
  }'
```

**201 Created** returns the created rule with its `id`.

* **`pattern_kind`** — `prefix` or `regex` (required).
* **`pattern`** — E.164-form prefix (leading `+`, digits) or a full-match regular expression (required, max 256 chars).
* **`name`** — operator label shown in the dashboard grid (required, max 128 chars).
* **`priority`** — integer 0–100000, default 100; lower wins at match time.
* **`target_type`** — one of the inbound target types listed in section 1 (required).
* **`target_config`** — the target's settings as a JSON object; `{}` when the target needs none.
* **`active`** — `true` by default; set `false` to stage a rule without enabling it.

`PUT /api/v1/voice/dnis-routes/{id}` sends the same body and replaces the rule in full. `DELETE /api/v1/voice/dnis-routes/{id}` returns `204 No Content`.

**Responses you'll plan for:**

* `422` — a field failed validation (`pattern` empty, `priority` out of range, malformed enum). The `details` object names the offending fields.
* `409` — the pattern overlaps an existing active rule at the same priority. Change the priority to layer the rules, or edit the existing rule instead.
* `404` — the rule id doesn't exist for your organization (wrong id, or another tenant's id).
* `401`/`403` — missing credentials, or the caller lacks an owner/admin/developer role or the `voice:write` scope on a write.

## 4. Test the rule with a sample call

Before pointing a production number block at a rule:

1. Create the rule with `active: false`, or with the real pattern but a harmless target such as `voicemail`.
2. Confirm the match order with `GET /api/v1/voice/dnis-routes/` — your rule should appear where you expect in the precedence ordering (server-sorted: priority ascending, then most specific within the priority).
3. Buy or pick one DID in the block and call it from a PSTN phone. The call should land on the target — the queue rings its members, the IVR plays its opening prompt, or the voicemail greeting answers.
4. If the call hits your default handling instead, check in order: does the DID's pattern actually match (E.164 form, leading `+` included)? Is the rule `active`? Is a higher-priority or more-specific rule matching first? Does the DID itself have a per-number inbound routing entry overriding the pattern?
5. When the sample behaves, flip `active` to `true` (or point the target at the real queue) — every DID in the block now routes the same way.

## 5. Common setups

**One queue behind N country DIDs.** Buy local numbers per region, then one prefix rule per region pointing at the same queue:

```text theme={null}
+4420   → queue Support_EN   (priority 100)
+331    → queue Support_EN   (priority 100)
+4930   → queue Support_DE   (priority 100)
```

A new DID in any of those ranges needs no routing change — the pattern already covers it.

**Carve out one number from a block.** Put the broad rule at a normal priority, then give the special DID its own standard inbound routing entry. The per-number entry always wins over any pattern, so the special VIP line routes to the VIP queue while the rest of the block follows the pattern. No priority juggling needed.

**Campaign DID group.** Buying a tracking DID per campaign (the [call-tracking setup](/guides/call-tracking-dni) pattern) stops needing a routing entry per DID: one regex rule covers the whole campaign block and points it at the campaign's IVR:

```text theme={null}
pattern_kind: "regex"
pattern: "\+1(800|888|877)\d{7}"
priority: 100
target_type: "ivr"
```

Each new toll-free DID you buy for the campaign routes at provisioning time.

**Broad fallback under narrow rules.** A catch-all prefix like `+1` at priority 900 sends every otherwise-unmatched US/Canada DID to a general IVR, while narrower rules at priority 100–500 handle the pools you've actually mapped. The catch-all only ever sees calls no specific rule claimed.

## 6. Troubleshooting

| Symptom                            | Likely cause                                                                                                    |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `409` on create/replace            | Pattern overlaps an active rule at the same priority — layer on a different priority                            |
| `422` on create                    | Field shape: prefix missing the leading `+`, regex that doesn't compile, priority not a whole number            |
| Calls ignore the rule              | Rule is `active: false`, a per-number inbound route overrides it, or a lower-number priority rule matches first |
| A DID you just bought isn't routed | It matches no pattern — widen the prefix/regex or check the DID is E.164-form                                   |
| `404` on update/delete             | Wrong id, or the rule belongs to another organization                                                           |

Next steps: [Build an IVR flow](/guides/build-ivr-flow) for the `ivr` target, [Set up and run voice queues](/guides/voice-queues) for the `queue` target, and [Queue SLA escalation policies](/voice/queue-sla-escalation-policies) for watching what the routed calls do to your SLA.
