Low DID inventory alerts and the auto-replenishment loop
A sender pool, a geo-matched dialer, a 10DLC rotator: each is a stock of DIDs under a (country, area code) corridor, and each is only as resilient as its available count. Orbit ships two complementary controls for that stock: a daily low-stock sweep that warns you when a pool runs low, and a replenishment policy that previews and places replacement orders to top the pool back up. This page explains how the two connect.The delivery cliff
Pools exist to spread outbound traffic across many DIDs so no single number carries enough volume to attract carrier throttling. When a pool’s available stock silently exhausts (numbers scheduled for release, parked, or held in compliance), the same traffic concentrates on the survivors. Carriers rate spam and complaints per MSISDN, so the first visible symptom is a deliverability cliff on the one or two remaining senders, not an empty inventory list. The cliff is silent because nothing in the send path fails. Messages keep going out, from fewer and fewer DIDs, until per-number rates trip. Catching it early means watching each pool’s available count, which is exactly what the low-stock sweep does. For how pools feed routing, see Sender pool selection model, Sender and routing, and Least-cost routing.The daily low-stock sweep
Once a day at 04:30 UTC, Orbit reads your active numbers, groups them by (country code, area code prefix), and counts the available DIDs in each group. For NANP numbers the prefix is the 3-digit area code; other numbering plans use a derived prefix. A number counts as available when it is active, its release is not pending or failed, and it is not held atpending_compliance.
When a group’s available count drops below your threshold, the sweep raises a low-stock alert for that group. The threshold is set per organization at organizations.settings.numbers.tn_low_stock_threshold, an integer from 1 to 1000. When the setting is absent or invalid, the platform default of 3 applies.
The sweep is strictly read-only. It counts inventory and raises alerts; it never modifies a number and never places an order. Restocking is a separate, explicit action, described below.
The two alert surfaces
The sweep publishes the same alert on two surfaces:- Webhook. One
number.inventory.lowevent per depleted group, delivered to your active webhook endpoints. The payload carriescountry_code,area_code_prefix,available_count,threshold, andraised_at, so an integration can act per corridor without parsing a multi-bucket payload. See Webhook events for the event contract. - Dashboard banner. The same computation backs
GET /api/v1/numbers/inventory-alerts, the read endpoint the dashboard uses to render the low-stock banner.
Wiring the alert to replenishment
An alert tells you a pool dropped; the replenishment endpoints decide what to do about it. They live under/api/v1/numbers and persist their policy at organizations.settings.numbers.replenishment.
Preview first: GET /numbers/replenishment-plan
The plan endpoint computes, against your saved policy and your live available counts, what a replenishment run would order right now. It is read-only and safe to call from automation on every alert:
available, target_available, order_count, and whether the order was capped by the per-run limit, plus a summary with pools_to_replenish and total_to_order.
Declare the policy: PUT /numbers/replenishment-policy
A policy is a master auto_order switch plus a list of rules. Each rule names a pool and a floor:
countryis an ISO alpha-2 code, normalized to upper case.area_codescopes the rule to one corridor; omit it to pool every area code under the country.number_typeislocal,mobile, ortoll_free(defaultlocal).reorder_belowis the floor: a run orders for the rule when available stock is below it.target_availableis the level the order refills up to, and must be at leastreorder_below.max_per_runcaps one run’s orders for the rule.GET /numbers/replenishment-policyreturns your saved policy together with the platform defaults and ceilings, so you can validate values before saving. An invalid policy returns422with field-level details.auto_order(defaultfalse) is the master switch for unattended ordering. With it false you can still preview the plan and execute an explicit run; no background actor orders on your behalf.
Execute: POST /numbers/replenishment/run
A run computes the same plan and executes it, ordering each pool’s replacement DIDs through the same reservation and purchase lifecycle as a manual bulk purchase, including the wallet check. Each rule is bounded by its per-run cap; if the wallet cannot cover an order, the run releases the hold, halts, and reports halted: true.
status of ordered, partial, no_inventory, order_failed, or halted.
A recommended reaction flow for webhook-driven automation: on number.inventory.low, either call GET /numbers/replenishment-plan to preview what would order now and page a human, or submit POST /numbers/replenishment/run directly when the saved policy is itself your approval.
The loop end to end
Worked example: a 3-DID pool comes back
- A geo-matched pool holds three active DIDs in (US, 415). Two leave the available count: one scheduled for release, one held at
pending_compliance. Available count: 1. - The next 04:30 UTC sweep groups the pool as (US, 415), counts 1 available against the default threshold of 3, and fires
number.inventory.lowwithavailable_count: 1. - Your automation receives the event and saves a policy rule for the corridor:
target_available: 3,reorder_below: 2,max_per_run: 5. - It calls
GET /numbers/replenishment-plan. The plan shows one item: available 1, target 3,order_count2. - Your approval step passes and the automation calls
POST /numbers/replenishment/run. The result reportsstatus: "ordered", 2 succeeded. - The two replacement DIDs land active in the pool. The next sweep counts 3 available, above both the alert threshold and the reorder floor, so no alert fires.
Boundaries
- The sweep is read-only. It never releases, suspends, or purchases a number; its only side effect is publishing alerts.
- Replenishment never orders on ambient traffic. Orders happen only inside
POST /numbers/replenishment/run, or an unattended actor you explicitly enable withauto_order: true, always against a saved policy. - A failed availability read aborts a plan or run before any order is placed, rather than guessing at zero stock.
- Replacement DIDs follow the standard purchase path, wallet and audit included. See Number bulk reservation model.