> ## 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 up alphanumeric and international sender IDs with the warm-up meter

> Alphanumeric sender IDs and international long codes were never covered by per-number warming because they are not provisioned numbers. Read each sender's graduated daily ceiling and DLR-driven reputation score from the sender warm-up endpoints, and pace campaigns in regulated corridors before you launch.

# Warm up alphanumeric and international sender IDs

Orbit's number-warming engine paces new US 10DLC numbers along a daily cap until carriers trust them. But in EMEA and MENA regulated corridors, most traffic originates from alphanumeric sender IDs ("ACME", "OTP") and international long codes, and those identities are not provisioned numbers in your Orbit number inventory. The per-number engine had nothing to key on, so a brand sender could jump straight to full volume on a fresh corridor with no ramp at all.

The sender warm-up endpoints close that gap. They compute a warm-up meter for every alphanumeric sender ID and international long code you send from: a recommended daily send ceiling on a graduated ramp, plus a DLR-driven reputation score. Everything derives from your own message history, so there is nothing to configure. The meter starts reporting as soon as a sender has outbound traffic.

***

## Why sender IDs warm differently from DIDs

Carriers build sender trust per origination identity, whether that identity is a number or a sender ID. A brand-new alphanumeric sender that fires a full campaign on day one looks abusive to carrier anti-spam scoring, exactly like a cold 10DLC number: messages submit (and bill) but drop before delivery.

The two estates differ in how Orbit can see them:

* **A 10DLC number is provisioned in your account**, so the [number-warming engine](/guides/number-warming) tracks it per number and enforces a hard daily cap at send time.
* **A sender ID is a free-form origination identity**, not a provisioned number. The per-number engine cannot see it. The sender warm-up endpoints aggregate your outbound SMS and MMS traffic per `from` value instead, and surface the ramp as a meter you pace against.

Two scopes are warmable here: `alphanumeric` (any sender containing letters) and `international_long_code` (a non-NANP numeric sender). US and Canadian 10DLC numbers are excluded because the number-warming engine already owns them, and short codes are excluded because they are pre-vetted for high throughput from day one.

<Note>
  The meter is advisory: it publishes a recommended daily ceiling and a reputation trend rather than refusing sends. The hard `429` quota gate applies to US 10DLC numbers under the number-warming engine. For sender IDs, the carrier is the enforcement layer, which is exactly why pacing under the recommendation matters (see the [operation runbook](#operation-runbook)).
</Note>

***

## The graduated ramp

Each sender's recommended daily ceiling grows along a geometric curve keyed to `days_active`, the whole UTC days since the sender's first outbound send:

```
ceiling = min(200 × 1.3 ^ days_active, 100000)
```

| Day | Recommended daily ceiling |
| - | - |
| 0 | 200 |
| 1 | 260 |
| 7 | 1,254 |
| 14 | 7,874 |
| 24+ | 100,000 (ramp complete) |

That is roughly 30 percent compounding per day from a day-0 allowance of 200, reaching the 100,000-per-day ceiling around day 24. The curve is tuned for the steady-state volume a corridor-wide brand sender carries, well above the per-number curve.

The meter is computed from your tenant's own `messages` records: outbound SMS and MMS over a 60-day history window set `days_active` and the volume totals, while the reputation signals use the most recent 30 days. There is no setup step and no per-sender configuration; a sender that has never sent simply has no meter yet.

The list endpoint returns the curve constants in a `ramp` object (`base_daily`, `growth_factor`, `max_daily`, `ramp_days`), so you can reproduce today's ceiling for any sender in your own tooling.

Reputation feedback adjusts the curve downward when carrier feedback degrades (see [the reputation score](#the-reputation-score)): `recommended_daily_ceiling` is always at or below the raw curve value in `base_daily_ceiling`, never above it.

***

## Read your whole fleet

`GET /api/v1/messages/senders/warmup` returns a meter for every warmable sender in your account, busiest first:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/messages/senders/warmup?limit=50" \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

```js theme={null}
const res = await fetch(
  "https://api.orbit.devotel.io/api/v1/messages/senders/warmup?limit=50",
  { headers: { "X-API-Key": process.env.DEVOTEL_API_KEY } },
);
const { data } = await res.json();

for (const s of data.senders) {
  console.log(
    `${s.sender} [${s.scope}] day ${s.days_active}: ` +
      `ceiling ${s.recommended_daily_ceiling}/${s.base_daily_ceiling}, ` +
      `state ${s.ramp_state}, tier ${s.reputation.tier}`,
  );
}
```

```json theme={null}
{
  "data": {
    "senders": [
      {
        "sender": "ACME",
        "scope": "alphanumeric",
        "warmable": true,
        "days_active": 9,
        "warmup_complete": false,
        "base_daily_ceiling": 2120,
        "recommended_daily_ceiling": 2120,
        "ramp_state": "ramping",
        "ramp_factor": 1,
        "ramp_reason": "reputation 'good' is healthy — full ramp",
        "total_sends": 18240,
        "first_sent_at": "2026-10-07T08:12:00Z",
        "last_sent_at": "2026-10-16T09:41:00Z",
        "reputation": {
          "score": 88.5,
          "tier": "good"
        },
        "reputation_window_days": 30,
        "min_sample_size": 50
      },
      {
        "sender": "+9715551234567",
        "scope": "international_long_code",
        "warmable": true,
        "days_active": 3,
        "warmup_complete": false,
        "base_daily_ceiling": 439,
        "recommended_daily_ceiling": 219,
        "ramp_state": "holding",
        "ramp_factor": 0.5,
        "ramp_reason": "reputation 'poor' (score 41.2) — holding ramp at 50% of curve",
        "total_sends": 1310,
        "first_sent_at": "2026-10-13T05:55:00Z",
        "last_sent_at": "2026-10-16T08:03:00Z",
        "reputation": {
          "score": 41.2,
          "tier": "poor"
        },
        "reputation_window_days": 30,
        "min_sample_size": 50
      }
    ],
    "reputation_window_days": 30,
    "history_window_days": 60,
    "ramp": {
      "base_daily": 200,
      "growth_factor": 1.3,
      "max_daily": 100000,
      "ramp_days": 24
    }
  },
  "meta": {
    "request_id": "req_snd1",
    "timestamp": "2026-10-16T10:00:00Z"
  }
}
```

### Reading a sender's meter

| Field | Meaning |
| - | - |
| `sender` | The exact origination identity (`from` value) this meter tracks. |
| `scope` | `alphanumeric` or `international_long_code`. US/CA 10DLC numbers and short codes never appear here. |
| `days_active` | Whole UTC days since this sender's first outbound send. The ramp index for today. |
| `base_daily_ceiling` | Today's ceiling on the raw geometric curve. |
| `recommended_daily_ceiling` | The ceiling after reputation feedback. Pace today's sends under this value. |
| `ramp_state` | `ramping` (full curve), `holding` (held at 50% on a `poor` tier), or `throttled` (25% on a `critical` tier). |
| `warmup_complete` | True once the curve has reached the 100,000-per-day ceiling. The sender has graduated from the ramp. |
| `total_sends` | Outbound SMS/MMS sends from this sender over the 60-day history window. The list sorts by this, busiest first. |
| `reputation.score` / `reputation.tier` | The DLR-driven reputation reading over the last 30 days. `score` is `null` with tier `unknown` until the sender has 50 sends in the window. |

`limit` (1 to 500, default 100) caps how many senders the list returns; the busiest always make the cut.

***

## Forecast one sender

`GET /api/v1/messages/senders/warmup/lookup?sender=<exact from value>` returns one sender's meter plus the day-by-day forecast of the curve, the same data the dashboard warm-up chart renders:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/messages/senders/warmup/lookup?sender=ACME" \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

```json theme={null}
{
  "data": {
    "sender": "ACME",
    "scope": "alphanumeric",
    "warmable": true,
    "days_active": 9,
    "warmup_complete": false,
    "base_daily_ceiling": 2120,
    "recommended_daily_ceiling": 2120,
    "ramp_state": "ramping",
    "ramp_factor": 1,
    "ramp_reason": "reputation 'good' is healthy — full ramp",
    "total_sends": 18240,
    "first_sent_at": "2026-10-07T08:12:00Z",
    "last_sent_at": "2026-10-16T09:41:00Z",
    "reputation": {
      "score": 88.5,
      "tier": "good"
    },
    "forecast": [
      { "day": 0, "ceiling": 200 },
      { "day": 1, "ceiling": 260 },
      { "day": 9, "ceiling": 2120 },
      { "day": 14, "ceiling": 7874 },
      { "day": 24, "ceiling": 100000 }
    ]
  },
  "meta": {
    "request_id": "req_snd2",
    "timestamp": "2026-10-16T10:00:00Z"
  }
}
```

Field by field:

* `days_active: 9` — the sender first sent 9 UTC days ago, so today's raw curve value is `forecast[9]`.
* `base_daily_ceiling: 2120` — `min(200 × 1.3^9, 100000)`, the unadjusted curve for today.
* `recommended_daily_ceiling: 2120` — equal to the base here because the reputation tier is healthy. When feedback degrades, this is the value that drops while `base_daily_ceiling` keeps climbing.
* `forecast` — 25 entries, day 0 through day 24. Render it as the projected line and overlay today's send count on `forecast[days_active]` to chart progress, the same way the 10DLC guide charts the [progression forecast](/guides/number-warming#follow-the-15-day-progression-forecast).

The response is `null` when the sender has no outbound SMS/MMS traffic in the history window, or when it is not a warmable scope (a US 10DLC number, a short code, or an unknown sender).

***

## The reputation score

Each meter's `reputation` is computed with the same kernel as the per-number health surface, over the same 30-day DLR window. A sender's score is therefore directly comparable to a number's score: 88 on a sender ID means the same delivery quality as 88 on a 10DLC number.

The score (0 to 100) blends three DLR-driven signals from your recent sends:

* **Delivery rate** — confirmed deliveries over sends. High delivery keeps the score up.
* **Failure rate** — hard failures pull it down.
* **Complaint-coded failures** — carrier error codes that indicate the recipient filtered or blocked the message. These weigh heaviest, because they are the strongest filtering signal carriers emit.

The score appears once the sender has at least 50 sends in the window (`min_sample_size`); below that you get `score: null` and tier `unknown`, and the ramp runs at the full curve on benefit of the doubt.

| Tier | Score band | Effect on the ramp |
| - | - | - |
| `excellent` / `good` / `fair` | 55 and up | `ramping` — full curve |
| `unknown` | not yet scored | `ramping` — full curve |
| `poor` | 35 to 54 | `holding` — recommended ceiling held at 50% of the curve |
| `critical` | below 35 | `throttled` — recommended ceiling cut to 25% of the curve |

`ramp_reason` states the decision in plain text, for example `reputation 'poor' (score 41.2) — holding ramp at 50% of curve`.

**Read it before a campaign.** If the sender you plan to push shows `holding` or `throttled`, fix the deliverability problem first (opt-in quality, list hygiene, template content) and let the tier recover. Pushing full volume into a held sender burns ceiling on traffic the carriers are already filtering, and keeps the score down.

***

## Operation runbook

**Pace campaign volume under the per-day ceiling.** Before a launch, read each sender's `recommended_daily_ceiling` and plan the day's volume at or under it. A 2,000-send ceiling runs comfortably at a modest [campaign `throttle_rate`](/guides/campaign-end-to-end) spread across the day; the same volume fired in a burst lands on carriers all at once and reads like a spam wave. The ceiling is per sender, per UTC day, so splitting a launch across several warmed sender IDs gives you the sum of their ceilings, the same way it does for numbers.

**Know what happens when you exceed it.** The sender meter is advisory: Orbit does not return a quota error when an alphanumeric sender goes over its recommended ceiling, because the regulated corridors these senders serve are exactly where you want visibility rather than a hard stop. The carrier is the enforcement layer, and SMS bills at submit, not at delivery, so over-ceiling volume that gets filtered still bills. That is the cost the ramp exists to avoid. US 10DLC numbers are different: the number-warming engine enforces the cap with `429 WARMING_QUOTA_EXCEEDED` before submit (see [Warm a new 10DLC number](/guides/number-warming#pace-your-sends-under-the-cap)). Run both estates through the [send-gates preflight checklist](/guides/send-gates-preflight-checklist) before launch.

**Correlate warming state with deliverability insights.** When a sender reads `holding` or `throttled`, open the [deliverability reading](/guides/insights-deliverability-reading) for the same window: the failure and complaint rates there are the same signals feeding `reputation.breakdown`. A `critical` tier with a complaint-rate spike usually traces to one bad list or template; fix that and the tier recovers on the next 30-day window of traffic.

**Watch the transition days.** Day 24 is when the curve reaches the 100,000 ceiling and `warmup_complete` flips true. Graduation is time-driven, but a sender that reaches the ceiling while degraded keeps its throttled recommendation until the reputation recovers. Keep reading the meter after graduation: a mature sender whose tier drops to `poor` still gets held at half its (now full) ceiling.

***

## When to use which guide

| You are sending from | Use |
| - | - |
| US/CA 10DLC numbers | [Warm a new 10DLC number](/guides/number-warming) — hard daily caps, phases, and the quota gate |
| Alphanumeric sender IDs or international long codes | This guide — the advisory warm-up meter and reputation score |
| Short codes | No warm-up needed; pre-vetted for full throughput |
| SIP or voice route health | [Route quality circuit-breaker runbook](/guides/route-quality-circuit-breaker-runbook) |

***

## Required scopes

Both endpoints are read-only and accept either `messages:read` or `messages:write`. A key without one of the two receives a `403`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.