> ## 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.

# Warm a new 10DLC number — phases, daily caps, and the 15-day ramp

> Pace a new US 10DLC number from cold to full messaging volume: read warming_phase and the daily cap, follow the 15-day progression forecast, and throttle campaigns so you never hit the quota gate.

# Warm a new 10DLC number

United States carriers build sender trust per number. A brand-new 10DLC number that sends at full campaign volume on day one looks abusive to carrier filtering, even when the campaign is [registered and approved](/guides/10dlc-registration). Orbit gates outbound sends on every US 10DLC number while it warms up: a daily cap that rises along a growth curve until the number graduates as warmed.

Warm-up requires no configuration. When a number starts warming, you read its state, pace your sends under the cap, and let the ramp finish.

***

## Why warm a new 10DLC number

Carriers accrue sender trust as volume ramps and recipients accept the traffic. A number that jumps straight to tens of thousands of segments per day gets filtered — messages submit (and bill) but drop before delivery.

Warming protects you in both directions:

* **Carriers see a compliant sender.** Daily volume grows in the shape carriers publish for 10DLC onboarding, so the number earns trust instead of tripping filters.
* **You do not pay for dropped messages.** Orbit enforces the per-number daily cap before each send. An over-cap send returns a `429` with code `WARMING_QUOTA_EXCEEDED` instead of silently submitting to the carrier and being filtered.

The cap is per number (per DID), per UTC day. Every number you warm ramps independently, and total campaign throughput at launch scales with how many warm numbers you have.

***

## Why it protects you on billing

SMS billing happens at submit, not at delivery. Without the warming gate, a campaign that exceeds what carriers accept from a cold number still submits every segment — the carrier then drops them at its filtering layer and you pay for sends no recipient ever sees. The gate refuses over-cap sends before submit, so a cold number can only bill for what carriers will actually accept.

***

## Read a number's warming state

Get the full warming-tier state for one number:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/numbers/num_abc123/warming" \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

```json theme={null}
{
  "data": {
    "phone_number_id": "num_abc123",
    "phone_number": "+12125550142",
    "trust_score": 58,
    "daily_cap": 10000,
    "current_day_count": 4210,
    "current_day_window_start": "2026-08-27T00:00:00Z",
    "warming_started_at": "2026-08-13T00:00:00Z",
    "warming_phase": "steady",
    "last_phase_advance_at": "2026-08-27T00:00:00Z",
    "days_warmed": 14
  },
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2026-08-27T12:00:00Z"
  }
}
```

The response is `null` for a non-10DLC number (toll-free, international, or a US number with warming not enabled).

### Response fields

| Field                   | Meaning                                                                                                                |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `warming_phase`         | Current phase: `initial`, `ramp`, `steady`, or `verified`. Drives the daily cap.                                       |
| `daily_cap`             | Maximum SMS allowed from this number today (UTC day).                                                                  |
| `current_day_count`     | Sends already consumed since the current UTC day began. Read from the live counter, so it is accurate mid-day.         |
| `trust_score`           | Carrier trust score (0–100) when reported. `null` when no score exists yet — phases then advance on time-warmed rules. |
| `warming_started_at`    | When warming began. Day zero of the ramp.                                                                              |
| `last_phase_advance_at` | When the phase last moved forward. Only advances at the midnight-UTC tick.                                             |
| `days_warmed`           | Whole days since `warming_started_at`.                                                                                 |

### The four phases and their caps

| Phase      | Daily cap                                        | What moves a number to the next phase                                                    |
| ---------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| `initial`  | 100 on day 0, rising linearly to 2,000 by day 14 | Completing the 14-day window (a high trust score can graduate later phases the same day) |
| `ramp`     | 2,000, rising to 4,000 at trust score 26–50      | Trust score 51 or higher                                                                 |
| `steady`   | 10,000                                           | Trust score 76 or higher                                                                 |
| `verified` | 6,000 — or 200,000 with external brand vetting   | Terminal phase                                                                           |

Phases only advance forward. If a trust score drops, the number keeps its current phase until the score supports the next advance — the cap moves up or holds, never cuts mid-day.

<Note>
  The phases and tier caps above follow the [published 10DLC throughput tiers](/guides/10dlc-registration#throughput-tiers) from The Campaign Registry and the major carriers. External vetting (the `verified` → 200,000 step) is the TCR brand-vetting tier, not an Orbit-side flag.
</Note>

***

## Follow the 15-day progression forecast

For a lighter-weight view — and the forecast the dashboard chart renders — read the progression endpoint:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/numbers/num_abc123/warming/progression" \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

```json theme={null}
{
  "data": {
    "phone_number_id": "num_abc123",
    "phone_number": "+12125550142",
    "warming_state": "warming",
    "warming_started_at": "2026-08-20T00:00:00Z",
    "warming_max_daily_sms": 1174,
    "current_day_count": 388,
    "days_warmed": 7,
    "ceiling": 3000,
    "base": 50,
    "growth": 1.35,
    "forecast": [
      { "day": 0, "ceiling": 50 },
      { "day": 1, "ceiling": 68 },
      { "day": 7, "ceiling": 1695 },
      { "day": 14, "ceiling": 3000 }
    ]
  },
  "meta": {
    "request_id": "req_def456",
    "timestamp": "2026-08-27T12:00:00Z"
  }
}
```

### What the fields mean

* `warming_state` — `off` (no warming on this number), `warming` (ramp in progress), or `warmed` (graduated; the gate no longer applies).
* `warming_max_daily_sms` — today's ramp ceiling after carrier-feedback adjustment. Persisted once per scheduler tick so the dashboard chart renders with no extra reads.
* `days_warmed` — whole days since `warming_started_at`; the `forecast` index for today.
* `base`, `growth`, `ceiling` — the growth-curve constants: 50 sends on day zero, roughly 35 percent daily compounding, hard-capped at 3,000 per day.
* `forecast` — fifteen entries, day 0 through day 14. Each entry's `ceiling` is the projected daily ceiling for that day. Render it as a projected line and overlay `current_day_count` on `forecast[days_warmed]` to chart progress.

### How the ramp curve interacts with carrier feedback

The base curve is `min(base * growth ^ days_warmed, 3000)` — it reaches the 3,000-send ceiling around day 14. A freshness loop runs on top of the curve at every tick, using the number's [deliverability health tier](/numbers/health):

* Healthy delivery — the ramp proceeds at the full base ceiling.
* `poor` health tier — the ceiling holds at half the base value.
* `critical` health tier — the ceiling drops to a quarter of the base value.

A number that reaches the ceiling only graduates to `warmed` when its delivery feedback is healthy. A number that hits the ceiling while degraded stays in `warming` at its throttled ceiling until its reputation recovers.

***

## Pace your sends under the cap

The practical question is how to keep campaigns under a cap that changes every day.

**Let the gate tell you.** When a send would push a warming number over today's ceiling, the API returns `429` with code `WARMING_QUOTA_EXCEEDED`. The error details carry `retry_after` (seconds until the counter resets at midnight UTC) and the full current ceiling. Handle it by pausing sends from that number until `retry_after` elapses, or by routing further sends through an already-warmed sender.

**Throttle the campaign, not just the API calls.** Set `throttle_rate` on the campaign to spread sends across the day at a rate the ceiling supports. For example, a 4,000-send day runs comfortably at one message per second for a few hours; the same volume fired in a burst burns the whole daily ceiling in minutes and returns quota errors for the rest of the campaign. The campaign `throttle_rate` field is per-second — the warming cap is per-day — so combine a modest throttle with the quota-error handling above. See [End-to-end campaign launch](/guides/campaign-end-to-end) for the full `throttle_rate` reference.

**Split launch volume across warm numbers.** Because the cap is per number, a campaign assigned to several warming numbers gets the sum of their daily ceilings. Buying a handful of numbers before launch and warming them in parallel is the fastest way to reach full volume.

**Watch the transition days.** The phase-change moments to plan around:

* **Day 14** — the `initial` phase's linear ramp ends. The number graduates to `ramp` (or straight to `steady` / `verified` if its trust score qualifies), jumping from roughly 2,000/day to 4,000 or 10,000.
* **Trust score crossing 51 and 76** — advancement to `steady` and then `verified` is event-driven on the score, not the calendar.

***

## How progression advances (the hourly tick)

A dedicated hourly scheduler walks every number with `warming_state = 'warming'`: it re-computes today's base ceiling from the growth curve, applies the carrier-feedback adjustment above, and persists the result as `warming_max_daily_sms`. A number that reaches the 3,000-send ceiling with healthy delivery feedback graduates to `warmed`.

The phase column on the warming state endpoint (`initial` → `verified`) moves separately, on a daily cadence that also applies the trust-score thresholds and mirrors the day's send count. A missed scheduler tick always resolves on the next run — progression is a stateless re-compute from the number's stored state, so the ramp self-heals.

<Tip>
  Cap enforcement reads the live counter, never the persisted mirror — so a send is never gated by a stale tick, and the `current_day_count` you read is accurate to the second.
</Tip>

***

## Warming inside the go-live checklist

[Section 9 of the go-live checklist](/guides/go-live-checklist) covers launch pacing — canary steps, rollback, throughput within quota. Add warming to that plan for a US SMS launch:

1. **T-minus 2 weeks.** Start warming every number you plan to send from, before the launch campaign exists. The ramp runs on real sends, so route your normal transactional traffic through the new numbers while you wait.
2. **Launch planning.** Total peak-day volume must stay under the sum of your numbers' `daily_cap` values. The [progression forecast](#follow-the-15-day-progression-forecast) tells each number's ceiling on launch day; if the sum is short, either start warming more numbers earlier or plan a multi-day campaign window.
3. **Launch day.** If a number hits its ceiling mid-launch, sends return `WARMING_QUOTA_EXCEEDED` rather than dropping at the carrier — catch the 429, pause that sender, and let surplus volume flow through the numbers with remaining headroom.
4. **Post-launch.** Keep watching `warming_phase` until every launch number reads `verified` (or `warming_state: warmed`). Numbers sitting at `initial` or `ramp` with unresolved `poor` health leave throughput on the table — fix their delivery health and the ramp resumes.

A number that finishes warming during business as usual graduates the same way: read the state endpoint once a day, note the phase advance, and widen campaign schedules as caps grow.

***

## Troubleshooting

| Symptom                                  | Cause                                 | Fix                                                                                                      |
| ---------------------------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| Sends fail with `WARMING_QUOTA_EXCEEDED` | Today's ceiling is consumed           | Wait for the midnight-UTC reset (`retry_after` in the error), or send from a warmed number               |
| `GET /warming` returns `null`            | The number is not a warming 10DLC DID | Only US 10DLC numbers on a warming ramp carry warming state                                              |
| Ceiling stuck below the base curve       | Health tier is `poor` or `critical`   | Check [number health](/numbers/health), resolve the delivery problem; the ramp un-holds on the next tick |
| Number stays `warming` past day 14       | Degraded feedback at the ceiling      | Same as above — graduation requires healthy delivery at the ceiling                                      |
