Skip to main content

Outbound send-pacing architecture

Four composable controls shape how fast a campaign sends: the static throttle_rate baseline, the time-based ramp_up easing, the carrier-assigned trust-tier governor ceiling, and closed-loop adaptive_pacing. Each is a campaign-level opt-in, each narrows the send rate from a different plane (your config, the clock, the carrier-assigned tier, and your own delivery receipts), and together they answer the question operators actually ask: “why is my campaign sending slower than the throttle I set, and which control decided that?” This page is the model behind the answer.

Scope and page ownership

This page owns the concept plane of the effective outbound send rate: what each control allows, the fixed order they apply in, the composed-rate rule, the boundary between slowing and stopping, and the reading order that names the control responsible for a slowdown. Configuration recipes live in the guides and are not repeated here: Pacing is also a different plane from admission. Outbound send gating decides whether a message may leave at all (suppression, quiet hours, frequency caps, billing posture); this page models how fast an admitted campaign sends. A send the gates refuse was never a pacing decision, and a paced send still walks every gate at dispatch.

The four-control stack and its ordering

The controls apply in a fixed order, and each one narrows what the previous left:
  1. throttle_rate — the open-loop baseline. The campaign’s nominal send rate in messages per second. A positive value is your explicit ceiling. Zero, absent, or non-finite is not unlimited: the executor paces at the platform’s default carrier-friendly rate, because the absence of an operator-set rate is not a request for unbounded throughput. When a ramp_up profile is configured, a throttle_rate of 0 instead means “no extra hard ceiling on top of the ramp” — the ramp curve defines the rate.
  2. ramp_up — time-based easing. A linear ramp on the baseline: the inter-batch delay starts higher and eases to the nominal rate over the ramp window. Like the throttle it is open-loop; the curve climbs on schedule whether the carrier is accepting the traffic or rejecting half of it.
  3. Trust-tier governor — the hard ceiling. Your brand’s TCR vetting determines a carrier-assigned throughput class: an AT&T per-campaign throughput class in messages per minute (converted to a per-second ceiling) and a T-Mobile per-brand Brand Daily Cap in message parts per rolling 24 hours. The governor derives both ceilings through the same resolver the brand throughput endpoint displays, so what it enforces is what the endpoint shows. Per-field overrides (mpm, daily_cap) may only pin a lower ceiling than the tier grants; a non-positive value on an axis leaves that axis uncapped. The governor clamps whatever the first two controls produced and never speeds a campaign up.
  4. adaptive_pacing — the closed-loop multiplier. The executor periodically re-reads this campaign’s own delivery receipts grouped per carrier (MCCMNC) and folds a pace factor between the configured floor and 1 into the same effective-rate and inter-batch-delay machinery the governor uses. Healthy traffic keeps the factor at 1; a carrier that starts failing or spam-blocking drags it down proportionally.
The composed-rate rule. On every batch, the governor’s and adaptive pacing’s factors multiply into and clamp the rate that throttle_rate + ramp_up produced. The effective send rate is the lowest of what the four controls allow, never higher than any one of them permits. Two consequences follow:
  • Only the governor can stop the campaign. When the next batch would cross the T-Mobile Brand Daily Cap (parts consumed today + batch size > cap), the loop defers the batch and auto-pauses the campaign rather than oversending; the remaining recipients roll into the next rolling-24h window. The other three only slow: adaptive pacing degrades open and keeps a non-zero floor, and the throttle and the ramp only set ceilings. The authorities on a full halt elsewhere — your credit caps, route circuit-breakers, a manual pause — are untouched by this stack.
  • The tightest control wins, per batch. A campaign throttled at 50 MPS under a 20 MPS governor class sends at 20; if adaptive pacing then reports a 0.5 blended factor, the blast sends at 10 until the readings recover.

Adaptive pacing internals

Adaptive pacing scores each destination carrier independently and blends the readings into one campaign factor:
  • Stress scoring. Per MCCMNC over the rolling window_minutes (default 15), stress is (failed + blocked) / terminal, where the spam-block subset counts a second time inside the sum: a carrier actively filtering your traffic costs sender reputation more than transient undeliverable churn.
  • Linear mapping. Stress at or below healthy_failure_rate (default 0.05) yields factor 1; stress at or above max_failure_rate (default 0.3) yields the min_pace_factor floor (default 0.2); between the two the factor interpolates proportionally. Exponential smoothing (smoothing, default 0.5) walks the factor toward each new reading so one noisy window doesn’t slam the rate.
  • The min_sample gate. A carrier with fewer terminal messages than min_sample (default 20) in-window contributes factor 1 — a 1-of-1 failure on a tiny carrier is noise, not signal.
  • Traffic-weighted blend. Each carrier’s factor is weighted by its share of recent terminal traffic, so the destination network carrying most of your volume dominates the blend, and a tiny stressed carrier cannot veto an otherwise healthy blast.
  • Open degradation. When the receipt read returns nothing — no rows yet, a transient read error — the factor is 1. The controller is a reputation optimiser, not a hard stop; a feedback gap never slows a campaign and never halts one.
When the factor drops below 1, the executor emits a log line naming the applied factor, the most-stressed carrier’s MCCMNC and its stress rate, and the number of throttled carriers — the same per-carrier delivery breakdown the campaign dashboards surface through the analytics pipeline. Adaptive pacing reads this campaign’s receipts, so it contributes nothing where that signal can’t exist or shouldn’t drive the rate: journey and drip campaigns (contacts enroll one at a time, so there is no batch volume and no per-window receipt signal), low-volume sends that never reach min_sample on any carrier, and blasts that must finish inside a hard window (pacing widens the inter-batch delay when carriers stress). Those runs are better served by the static throttle_rate plus operator monitoring.

Interaction with adjacent planes

The four-control stack shapes the rate a campaign offers traffic at. Other planes meter the same traffic from their own vantage, and each interacts with the stack in a specific way:
  • Per-number warming caps (sender warming and reputation) meter the sender identity, not the campaign. Exceeding the trust-tier phase ceiling returns DAILY_CAP_EXCEEDED; exceeding the operator-driven growth curve returns WARMING_QUOTA_EXCEEDED with a retry_after. They reject over-cap sends at the number; they do not re-shape the campaign’s rate. The composition runs the other direction: a warming number’s recommended ceiling is an input you fold into throttle_rate or a governor override, not a term the stack derives.
  • Route-quality circuit breakers (outbound route quality) halt rather than slow. An open circuit auto-suspends the degrading carrier route and fails traffic over to your configured channel — a stop-plane control that acts on the route, where pacing acts on the rate. A blast slowed by adaptive pacing and a blast failed over by a breaker are answering different signals (your receipts vs. route health) and can both apply to the same run.
  • Message-priority traffic lanes (message priority and traffic lanes) meter the account. A campaign’s paced offer rate still feeds the marketing lane’s share of the per-account budget; a blast can be correctly paced by the stack and still be shaped by its lane when the account budget is saturated.
  • The cross-campaign allocator (cross-campaign send allocator) plans, the stack reacts. The allocator water-fills each campaign’s volume across the slots of a spread window under your global hourly cap, throttling each campaign’s per-slot share by a sender-reputation pace factor. Once a planned campaign launches, the live four-control stack takes over the rate; the allocator’s schedule is where the run starts, not a ceiling inside the loop.
  • Batch dispatch ceilings. The executor meters each batch against the platform’s per-lane send ceilings, so concurrent lanes never push a provider into 429 backpressure. These ceilings sit around the campaign stack, exactly like the account-level lanes: they can shape a burst the stack cleared, and they report the same 429 + Retry-After posture as every other throughput ceiling.

Operator observability — the “why is my blast slow” reading order

When a run sends slower than the throttle you set, read the planes in this order; each step names one control or rules it out:
  1. The configured baseline. Check throttle_rate and ramp_up first. A zero throttle is the platform default, not unlimited, and a live ramp window means the campaign is still easing toward the nominal rate.
  2. The executor pace log line. If adaptive pacing is engaged and the factor is below 1, the log line names the applied factor, the most-stressed MCCMNC, its stress rate, and the throttled-carrier count. The per-carrier delivery breakdown in the campaign dashboard (via the analytics pipeline) confirms which destination network is dragging the blend.
  3. The governor verdict. The governor logs the resolved ceilings on every run, and an auto-pause names the exact cap and the consumed count in the pause reason — a paused campaign is explainable, not silent. The brand throughput endpoint shows the same ceilings the governor enforces, so the enforced number and the displayed number never disagree.
  4. The adjacent planes, if no step above bound. Warming quota errors (WARMING_QUOTA_EXCEEDED with retry_after, or DAILY_CAP_EXCEEDED) name the per-number ramp; a lane-shaped send reports 429 with traffic_lane: "marketing"; per-service and per-number MPS ceilings report 429 with Retry-After: 1; and a breaker suspension appears in the route-quality state, not in the campaign’s pace at all. The warming dashboard card and GET /api/v1/numbers/:id/warming surface the sender-side meter the same way.
The stack composes downward, so the responsible control is always the tightest one currently binding — the reading order above lists the planes in the order they most commonly bind.

Tenant-ownership posture

Every control on this page is opt-in campaign configuration you own. All four live in the campaign’s variables object — the same self-serve opt-in pattern as the other dispatch governors — and a campaign without the key sees zero behaviour change, including every campaign created before the control shipped. There is no platform mandate here: the stack protects your throughput classes and your sender reputation, and it makes no compliance claim. Your compliance posture (quiet hours, suppression, frequency caps) is a separate tenant-owned plane documented under outbound send gating; the one platform-owned hard guard, the US TCPA federal voice dialing window, belongs to that gating plane, not to pacing.

See also