Troubleshooting: cooldown and rate-limit 429s
A429 response means the request was valid but dropped by a protective limit — a cooldown, a frequency cap, or a throughput ceiling. Every 429 carries an error code that tells you which limiter fired, and most include a retry_after value in seconds. For the full taxonomy of Orbit’s limiter families, see Rate-limit and cooldown taxonomy. This page is the live-fix surface — use the codes below to branch on which limiter is firing and how to stop hammering the same gate.
Common Verify / OTP 429 codes
Cross-channel 429 codes
The messaging and voice surfaces raise more specific 429 codes. The table below is the quick breakdown; the full catalogue with response shapes is in the Error codes reference, and the Rate-limit and cooldown taxonomy concept groups them into the four limiter families.Response shape
Every 429 uses the same envelope.retry_after lives inside error, not at the top level, and the HTTP Retry-After header carries the same value so proxies and SDK header-readers agree:
error.retry_after (numeric seconds) when it is present; fall back to the Retry-After header only when the body field is missing. The global HTTP quota limiter always sets both. Per-recipient cooldown codes (VERIFY_RESEND_COOLDOWN, FREQUENCY_CAP_EXCEEDED) may carry the hint in error.details.retry_after_seconds instead — treat the field as a hint, not a guarantee, and fall back to backoff when it is absent.
Codes by surface
Same codes, organized by which surface raised them. The surface column is the diagnostic lever: it tells you whether the limiter is keyed on one recipient, a cap you configured, or your tenant’s aggregate throughput.How to retry correctly
- Read
retry_after. Most 429 responses include aretry_aftervalue (seconds) — wait that long before retrying rather than looping with a fixed delay. - Back off per recipient, not per batch. Per-recipient cooldowns fire on one recipient; other recipients in the same batch are unaffected, so retry only the limited rows.
- Fix the loop. If one recipient keeps tripping
VERIFY_RECIPIENT_RATE_LIMITED, the throttle is doing its job — check for a re-send loop in your client before bumping limits.
Backoff code
One copy-pasteable pattern covers every 429 here. It prefers the server’sretry_after hint, falls back to exponential backoff with jitter (2^attempt seconds plus up to 1s random, capped at 60s), and gives up after five retries so a persistent gate cannot drain your queue:
retry_after from parking a worker, and the budget (5 retries) turns a terminal gate into an exception you can dead-letter instead of an infinite loop. Audit the thrown error code before re-queueing — per Do not retry, some gates should discard the row.
Identify which limiter fired
Work top-down; the first match tells you where to look next:- Read
error.codeon the 429. It names the limiter family — do not guess from the endpoint you called. - Starts with
VERIFY_? A per-recipient gate fired. Cooldown or recipient-rate, keyed on that one phone number. See Rate-limit and cooldown taxonomy for how the recipient gates stack. - Starts with
FREQUENCY_? A cap your org configured fired. Open the cap and check its window — see Frequency caps. - Ends in
_MPS_EXCEEDED, or isCONCURRENCY_LIMIT_EXCEEDED/VOICE_COUNTRY_RATE_LIMITED? A tenant throughput ceiling fired. Your org is sending faster than its quota, not one recipient. Dashboard surfaces and quota tuning are in API key usage limits. - Is
RATE_LIMITEDorRATE_LIMIT_EXCEEDED? The shared fallback or the global HTTP quota. Treat it as tenant-wide throughput and follow step 4 unless you know the recipient-specific path raised it.
Do not retry
Two codes look retriable but are not — a retry loop makes both worse:VERIFY_RESEND_COOLDOWNis keyed on the recipient. Retrying the same phone number just re-trips the gate and counts against its send-rate budget. Drop that recipient from the batch, wait out the cooldown, and surface the countdown to the end user.FREQUENCY_CAP_EXCEEDEDmeans the contact already received the allowed number of sends inside the rolling window. Retrying the same contact inside the window always fails. Skip the contact for this window; if legitimate traffic keeps hitting the cap, raise the cap itself in Frequency caps.
Fleet-wide 429s
If every request across recipients and channels returns 429 at the same moment, you are hitting a tenant-level throughput ceiling, not a recipient gate — check your org’s usage-limit dashboard, covered in API key usage limits. A wallet run dry is a different failure class: those responses come back as balance errors, not 429s — see Troubleshooting: insufficient balance. When a fleet-wide 429 spike coincides with elevated error rates across customers, check the status page before tuning your own thresholds.A cooldown is not an outage. If every request across recipients returns 429 at the same moment, check for a tenant-level throughput cap; if it is only one recipient, the per-recipient gate is working as intended.