Troubleshooting: SMS destination and spending blocks
A pre-send destination block rejects an outbound SMS before it is routed to any carrier — no sender, route, or provider change will clear it, and a blind retry replays the same check. The reject comes in one of four codes, and each one belongs to a specific guard layer. This page maps every code to its layer and the fix you own. It is the messaging mirror of Troubleshooting: voice destination and emergency blocks — same triage shape, different gates: where voice guards the caller-id you present, SMS guards the destination prefix, the velocity, and the daily spend.Decision matrix — which layer fired
Find the error code first, then jump to its section below. Each layer takes one control you own — the tenant blocklist, the send pacing, or a scoped test campaign — so triage ends in a small set of places.
If your reject is
FRAUD_SHIELD_BLOCKED (403) instead, that is your own
tenant-configured Fraud Shield, not these platform baselines — decode it
on Troubleshoot FRAUD_SHIELD_BLOCKED.
Destination prefix blocked
422 SMS_BLOCKED_DESTINATION fires when the destination matches a
prefix on the platform destination blocklist — the premium-rate and
pumped-route prefixes that account for the most expensive SMS abuse — or
on your own organization’s prefix blocklist. The same code also fires
when the destination is a NANP +1 555-NXX number: carriers silently
accept submissions to that reserved fictional range but never deliver,
so the platform rejects it at send time instead of paying for an attempt
with no delivery receipt.
The 422 body names what matched — details.prefix for a blocklist
match, details.reason: "nanp_555_test_range" for the fictional range —
so branch on it before you touch anything.
Fix it by changing the destination, not by working around the gate:
- Read
detailson the 422 body. For a prefix match, compare the prefix against the segment of the destination you sent. - Fictional test range. If
reasonisnanp_555_test_range, replace the placeholder with a real subscriber number — or use the sandbox magic numbers (+1 500 555 000X), which pass in test mode because no real carrier attempt exists. - Platform blocklist prefix. If the block came from the platform list, the route class is premium-rate or pumping-prone; the gate exists to stop that spend. Reroute to the subscriber’s real number or accept the destination as unsendable — there is no tenant-level toggle that re-opens a platform-blocked prefix.
- Your organization’s prefix blocklist. If your own organization added the prefix (an operator throttling a hot route for one tenant, or an automated SMS-pumping scorer marking it), remove that prefix from the organization’s fraud settings to re-open it. Until you do, the block applies to every sender in the organization.
Tenant self-service blocklist
422 CHANNEL_BLOCKED_DESTINATION with details.reason: "tenant_blocklist"
means the exact destination is on your own outbound blocklist —
the operator-managed list at Messages → Blocklist in the dashboard
(or the POST /api/v1/messages/blocklist API). The match is verbatim,
not a prefix, so the listed number is blocked exactly as entered. This
check runs before the prefix layers, so your entry takes precedence over
the broader rules — and it applies to every channel at once, not just
SMS.
Fix it at the blocklist:
- Check Messages → Blocklist for the destination; if it is listed, remove the entry and the destination becomes send-eligible immediately.
- If the entry is intentional (an abuse case, a bad-actor number), stop targeting that destination — the block is doing exactly what it was written to do.
- Audit who blocked it and why: every entry carries a free-text reason and removals are soft, so the history answers “when was this destination un-blocked.”
Per-minute rate window
429 SMS_RATE_LIMITED fires when your account’s outbound SMS exceeds
the per-minute cap over a sliding 60-second window. The guard weights
the current minute and the tail of the previous minute, so a burst
concentrated at a minute rollover trips it even when each single send
looked fine.
The 429 body names the limit, e.g.
{ "limit": 60, "window": "1m" }.
Fix it by smoothing the send, not by retrying harder:
- The window slides rather than hard-blocks, so pacing the bulk send clears it without any configuration change.
- A campaign that holds the cap pinned re-trips on every attempt — distribute the batch over minutes instead of firing it in one burst.
- Where your organization runs a custom per-minute override, the lower value wins; an active automatic anti-fraud throttle can also clamp the cap down for a limited window, and it reverts on its own.
Daily spend ceiling
429 SMS_DAILY_SPEND_CAP fires when the day’s estimated SMS spend
reaches the daily ceiling. The estimate is computed from the number of
segments sent at a conservative per-segment price — deliberately
pessimistic so the cap engages before real spend does — and it resets at
the day boundary.
The 429 body names both sides of the check, e.g.
{ "estimated_spent_cents": 5000, "cap_cents": 5000 }.
Fix it by scoping the campaign:
- Pace or stop today’s sends and retry after the day rolls over — the counter resets.
- If the reject surprised you, review which campaign consumed the day’s spend; a compromised API key pumping premium destinations is exactly what this ceiling exists to cut off.
- Where your organization runs a custom daily-spend override, the lower value wins — the ceiling engages at whichever bound you configured.
What to capture before escalating
Work the matrix above first. If a block still misreads — the destination is a real subscriber on a prefix that should be open, or the rate window keeps tripping well under its named limit — open a ticket with:- The full error body — the code, message, and the
detailsobject (theprefix,reason, orlimitfields above). - The destination number, E.164 normalized.
- The send path — single API send, batch send, or campaign.
- Your organization ID (Settings → Organization, or
organizationIdfromGET /api/v1/me).
What not to do
- Do not retry in a loop. Every pre-send gate re-fires on every attempt; only the rate and spend windows clear on their own.
- Do not reconfigure the sender or route. The block fires before the message reaches any carrier.
- Do not treat a blocked attempt as delivered traffic. Blocked sends
record as rejections in your analytics, so a spike in
SMS_BLOCKED_DESTINATIONrejections reads as refusals, not deliveries. - Do not reclassify a Fraud Shield 403 as one of these codes.
FRAUD_SHIELD_BLOCKEDis your own tenant policy — decode it on Troubleshoot FRAUD_SHIELD_BLOCKED.
See also
- Troubleshooting: voice destination and emergency blocks — the same triage shape on the voice side, guarding the caller-id you present rather than the destination prefix.
- Troubleshoot FRAUD_SHIELD_BLOCKED — your tenant-configured Fraud Shield when it rejects sends in enforcement mode.
- Troubleshoot sender ID rejected — the sender-identity registration gates that reject before these destination layers are consulted.
- Messages Blocklist — the tenant-owned
destination ban this page’s
CHANNEL_BLOCKED_DESTINATIONsection triages. - Rate-limit and cooldown taxonomy —
where
SMS_BLOCKED_DESTINATIONsits among the platform’s limiter families. - References: error codes — the error catalog this page triages.