Safeguards
Rate limits & fraud
OTPRelay protects your budget and your users from abuse out of the box - sensible per-number limits and Fraud Guard are on by default, with no configuration required.
Every OTPRelay account ships with built-in safeguards that cap how often a single number can be messaged and detect artificially inflated traffic before it reaches a carrier. You don't have to opt in: the limits below and Fraud Guard apply to all live traffic by default. Use them as a backstop, and layer your own application-level checks on top.
Built-in limits
These limits are enforced per verification and per destination number. When a limit is reached, the verification is closed (or the request is rejected) and a matching error code is returned - see Errors for the full envelope.
| Limit | Value |
|---|---|
| Sends per number, per verification | 5, then max_send_attempts (429) |
| Checks per verification | 5, then max_check_attempts (429) |
| Concurrent verifications per number | Guarded, then too_many_requests (429) |
Re-sending within the active expiry window does not generate a new passcode - OTPRelay delivers the samecode again, so a user who didn't receive the first message can retry without invalidating it. Each resend still counts toward the 5-send limit. The default window is 600 seconds; see Send a verification to tune expiry.
Fraud Guard
Fraud Guard is enabled by default and protects you from SMS pumping - also called artificially inflated traffic (AIT) - where attackers trigger high volumes of OTP sends to numbers they control in order to earn a share of the messaging revenue. Left unchecked, AIT can quietly drain your messaging budget.
Fraud Guard scores each send before it leaves OTPRelay, combining signals such as:
- Velocity checks - bursts of sends from one account, IP, or toward a single number or prefix in a short window.
- Suspicious-country rules - traffic to destinations or ranges with no prior legitimate history for your account.
- Sequential-number detection - runs of consecutive or patterned numbers that indicate scripted enumeration rather than real users.
When Fraud Guard blocks a send, the request fails with delivery_blocked (HTTP 402) and the message is never billed. Inspect the error body and your dashboard to review what was blocked.
Blocked sends aren't charged
delivery_blocked (402) and is not billed. If a legitimate user is caught, start a fresh verification once the risk signals clear - passing the end-user IP and metadata (see below) improves scoring accuracy.Rate-limit responses
When a built-in limit is hit, OTPRelay returns a 429 Too Many Requests with an error body of type rate_limit_error. The example below shows the concurrency guard firing with code too_many_requests; the same envelope shape is used for max_send_attempts and max_check_attempts.
Treat 429 responses as retryable, but back off - retrying immediately will keep tripping the same guard. Use exponential backoff(for example 1s, 2s, 4s, 8s) with a little jitter, and surface a "try again shortly" state to the user rather than looping. The closing limits (max_send_attempts, max_check_attempts) are not retryable on the same verification - start a new one instead.
Programmable rate limits
Today the limits above are fixed. Configurable, programmable rate limits - per-IP and per-user buckets that you define and attach to a send - are planned but not yet finalized. The exact API shape (bucket definitions, intervals, and how rules are keyed) is still open; reach out if a specific limit shape would unblock you.
Send risk signals for better scoring
device_ip-style field) and relevant metadata on each send so Fraud Guard can score risk more accurately and reduce false positives for your real users. See Errors for every code these safeguards can return.