Why SMS 2FA is still the dominant second factor in 2026 (even against WebAuthn)

WebAuthn, FIDO2, and passwordless push notifications have steadily gained ground, yet SMS 2FA still secures the majority of online accounts globally. The reason is economic and logistical: SMS requires zero user setup (works on any phone in any country), zero device registration, and zero recovery-key custody. A user signs up, receives a code on their existing number, and completes authentication in 30 seconds. WebAuthn and FIDO2 demand platform support (desktop browser, OS-level credential storage), hardware key distribution, or backup strategies—all frictions that reduce adoption for low-to-medium-risk transactions.

Crypto exchanges, fintech platforms, and wallets still use SMS as a baseline because it's carrier-agnostic, works internationally without roaming fees, and can be delivered to 149 countries from a single A2P gateway. For high-value operations (privileged admin access, large withdrawals, API key rotation), SMS is paired with push or hardware keys. But for account recovery, password reset, and transaction verification under $500, SMS remains the lowest-friction, highest-coverage solution. The real security shift in 2026 is not away from SMS, but toward SMS + something stronger (push, hardware key) or SMS with anomaly detection that blocks out-of-geography or out-of-pattern logins before OTP is even requested.

Code generation: HOTP, TOTP, and random 6-digit codes compared

Three distinct OTP schemes compete in production: HOTP (HMAC-based One-Time Password, RFC 4226), TOTP (Time-based One-Time Password, RFC 6238), and random server-generated codes. HOTP generates codes from a shared secret and an incrementing counter stored on both the server and client (usually a hardware token or authenticator app). Each successful use increments the counter; if the user generates a code but doesn't authenticate, the server and client can drift out of sync and require a resync step. TOTP removes the counter, deriving codes from the shared secret and the current UNIX timestamp in 30-second windows. Because time is publicly knowable, TOTP is stateless: the server and an authenticator app (like Google Authenticator or Authy) compute the same code simultaneously without state exchange. TOTP is faster to implement and doesn't suffer counter desync, which is why it powers most authenticator apps.

Random server-generated OTP codes (typically 6–8 digits, expiring in 5–10 minutes) are neither HOTP nor TOTP. Instead, they are generated by a cryptographically secure RNG, stored server-side with an expiry timestamp, and sent to the user via SMS (or email, voice, push). This approach is stateless, avoids phishing (the code cannot be intercepted and reused by an attacker on a phishing site), and requires no user-side cryptography or device provisioning. For SMS 2FA, random codes are standard because they're invisible to the user—no authenticator app needed, no manual entry of 6 digits—and the delivery channel (SMS) itself becomes a proof that the user controls the number. The tradeoff: SMS codes are sent in-band (over SMS), so an attacker who intercepts SMS (via SIM swap, SS7 intercept, or carrier insider threat) can steal the code. TOTP or hardware keys are out-of-band and immune to SMS interception, which is why they're preferred for high-security use cases.


# TOTP example (30-second window, HMAC-SHA1)
import hmac, hashlib, struct, time, base64

secret = base64.b32decode("JBSWY3DPEBLW64TMMQ======")  # shared key
counter = int(time.time() // 30)  # 30-second epoch
msg = struct.pack(">Q", counter)
digest = hmac.new(secret, msg, hashlib.sha1).digest()
offset = digest[-1] & 0x0f
code = struct.unpack(">I", digest[offset:offset+4])[0] & 0x7fffffff
otp = str(code % 1000000).zfill(6)
print(f"TOTP: {otp}")  # e.g., "123456"

# Random 6-digit SMS code (server-side)
import secrets
otp_sms = str(secrets.randbelow(1000000)).zfill(6)
print(f"SMS OTP: {otp_sms}")  # e.g., "789456"

The A2P SMS journey: API → SMSC → SS7 MAP → handset

When you call a send endpoint at your SMS gateway, a multi-hop carrier network springs into motion. Your API request lands at the gateway's SMSC (Short Message Service Center), which is the telecommunications industry's term for an SMS router and store-and-forward node. The SMSC validates the destination number format, checks it against carrier numbering plans, optionally performs an HLR (Home Location Register) lookup to verify the number is active, and queues the message for delivery. It then routes the SMS to the destination carrier's network via SS7 (Signaling System 7), which is the protocol stack that ties together telecommunications networks globally. Alternatively, modern providers use IP-based protocols like SIP and diameter to signal to the carrier's gateway.

Once the carrier receives the SMS, its MSC (Mobile Switching Center) consults the HLR to locate the subscriber and determine whether the subscriber's device is currently roaming (in which case it goes to a VLR, Visitor Location Register, instead). The message is then routed to the cell site serving that device, and the device receives it over the radio interface (2G SMS, 3G, or 4G LTE). The handset acknowledges receipt to the network, which generates a delivery receipt (SR-SMPP, Delivery Receipt). This receipt travels back through the same path to your SMSC, which logs the status and reports it to your API callback or polling endpoint. The round-trip is typically 2–30 seconds depending on network load, international routing hops, and whether the device is in a weak signal area. Crypto-only A2P gateways like smsroute connect directly to SMSC nodes in 149 countries with rates from $0.004/SMS, supporting payment in BTC, USDT, ETH, LTC, XMR, and SOL—no KYC required at signup.

The technical protocol details matter for debugging. SMPP (Short Message Peer-to-Peer) is the standard API between your application and the SMSC. You bind a session, submit PDUs (Protocol Data Units), and receive delivery receipts asynchronously. If the SMSC rejects a message, it returns an error code (e.g., ESME_RSUBMITFAIL for network congestion, ESME_RINVDSTADR for invalid address). Some errors are retryable; some are terminal. A professional gateway tracks these codes and adjusts retry strategy per-error-type. For SMS 2FA, a single failed send should trigger immediate fallback (voice, email, authenticator push) rather than waiting for a retry timeout.

Why transactional SMS bypasses most consent checks (and when it doesn't)

Transactional SMS—OTP, password resets, account alerts, delivery confirmations—is exempt from consent requirements in most jurisdictions because it serves a contractual or legal necessity. Under GDPR Article 4(11), a message directly related to an initiated transaction does not require prior opt-in consent if it is "necessary" for the transaction. The EDPB (European Data Protection Board) interprets this broadly: OTP for account access is necessary; a promotional notification is not. Under the US TCPA (Telephone Consumer Protection Act, 47 USC § 227), SMS to established business relationships (users who signed up) is exempt from do-not-call and do-not-text restrictions. The UK PECR (Privacy and Electronic Communications Regulations, Regulation 22(3)) exempts SMS to existing customers for transaction-related purposes but requires clear opt-out mechanisms for future communications.

Outside the West, rules vary. Russia's UU 27/2022 (Federal Law on the Protection of Personal Data) is stricter: transactional SMS requires consent unless it relates to direct customer service or account security. Germany's UWG (Unfair Competition Act, Section 7) requires explicit consent for most unsolicited SMS, including transactional ones in some interpretations—safer to include consent language. Brazil's LGPD (Law 13.709/2018) classifies OTP as "necessary processing" for security but still recommends a clear explanation to users. Argentina's RA 11934 requires pre-notification that SMS will be used for 2FA. The practical approach: obtain consent at signup ("We'll send you SMS codes for account access") and honor suppression lists immediately. Never send OTP to numbers the user did not explicitly register, and offer an out-of-SMS fallback (voice, email, authenticator) for users who want to opt out.

iOS autofill preambles: the @domain.com #123456 pattern

Apple's iOS 12+ (and later macOS, iPadOS) support domain-bound one-time codes via RFC 8254, a protocol that ties an OTP to a specific domain to defeat cross-domain phishing. If your SMS reads "Your Apple ID verification code is 123456 @apple.com #123456", iOS extracts the 6-digit code and autofills it only into password or auth fields under apple.com. If an attacker's phishing site (attacker.com) tricks the user into visiting and entering credentials, iOS will not autofill the code because the domain doesn't match. The #123456 suffix is a cryptographic checksum that prevents code injection attacks.

To enable this, your SMS gateway must send the preamble in a standardized format:


# Example OTP SMS with domain binding (RFC 8254)
Your verification code is 123456

@example.com #123456

# Or inline:
Your verification code is 123456 @example.com #123456

When deploying this, coordinate with your OTP provider (smsroute and other A2P gateways support custom message templates). Android's approach is different: Google Play Services and Google Smart Lock can read OTP from SMS and inject it into the correct app context if the app is using the Fido2 API (or GmsClient verification APIs). For maximum security, if you control the client app, use in-app verification APIs (iOS SFSafariViewController with AutoFill, Android Fido2) rather than relying on SMS extraction. SMS domain binding is a good second layer, but the strongest pattern is: code is sent via SMS, autofilled by OS-level API, and verified within the app—no user copy-paste, no manual entry, no phishing surface.

SMS pumping / toll fraud: the 2022–2024 epidemic and current mitigations

SMS pumping is a fraud technique where attackers exploit SMS 2FA systems to trigger expensive SMS sends to premium-rate numbers (short codes, INUM routes, international premium ranges). In 2022–2024, carriers and fintech operators reported a surge in account takeover flows where the attacker first gains a user's credentials (via phishing or breach), then triggers password resets or OTP flows to numbers they control—often forwarding SMS to expensive routes, pocketing the carrier revenue share, and leaving the operator with refund requests. Toll fraud is broader: attackers abuse SMS for fraudulent purposes (spreading malware links, sending spam), and the operator's reputation (IP address, sender ID) suffers carrier blocks and complaint escalation.

Mitigation layers include: (1) Per-number rate-limiting: max 3–5 OTP requests per number per hour, with cumulative limits per day. (2) Per-IP/session rate-limiting: max 10 authentication attempts per IP per hour; flag and block IPs with abnormal velocity. (3) Known-premium-route filtering: blacklist sends to INUM ranges (e.g., +882), high-fraud countries (varies by operator risk tolerance), and shortcodes not in your whitelist. (4) Velocity and anomaly rules: flag if one account sends OTP to 10+ different numbers in 1 day (account takeover signal), or authenticates from 5+ countries in 1 hour (impossible travel). (5) Carrier feedback loops and SCAM2 marking: carriers (T-Mobile, Verizon, AT&T) flag SMS sources with high complaint rates; professional gateways monitor these signals and adjust routing or alert operators. (6) Residential proxy detection: flag authentication from VPN exit nodes, datacenter IPs, and known residential proxy networks; SMS pumpers use these to avoid geographic detection.

Crypto exchanges and fintech are particularly vulnerable because they control user wallets and are lucrative targets. Best practice: geographic whitelisting (send SMS only to countries the user registered or has consistent login history), push notification as primary 2FA (immune to SMS fraud), and hardware key fallback. For 2FA implementations, never send OTP to unverified phone numbers; require user confirmation before dispatch ("We'll send a code to +1 650 ••• 3456. Correct?"). Monitor delivery receipt patterns: if 40%+ of sends are failing, investigate whether the attacker is flooding premium routes that carriers are rejecting. Finally, maintain a dedicated API endpoint for security-sensitive operations; don't reuse the same SMS quota for both transactional notifications and OTP.

Rate limits and retry strategy: per-number, per-IP, per-campaign

Rate limiting is essential to prevent both fraud and operational chaos. A single API key accidentally looping (sending OTP to the same number 1000 times) can cost thousands in minutes and exhaust your SMS quota. Professional providers implement concentric rate limits: per-destination-number (max 3–5 OTP codes per phone number per hour), per-source-IP (max 10 requests per IP per hour), per-API-key (max 1000 SMS per day or per billing period), and per-campaign (if you tag sends with a campaign ID, cap total SMS per campaign). These limits are configurable—a high-trust customer (verified business, long history, no fraud) might have looser limits; a new signup with unverified email gets tight limits until reputation builds.

Retry strategy matters separately. If an SMS send times out or the SMSC returns a retryable error (ESME_RSUBMITFAIL, network congestion), the gateway queues it for retry, typically after 5 seconds, then 30 seconds, then 2 minutes. But for OTP, the user-facing flow should not wait for all retries to exhaust; after 10 seconds with no delivery receipt, offer immediate fallback (voice IVR, email, authenticator app). This keeps user friction low and reduces the window for fraud. Log the original attempted send with all retries and outcomes for compliance and debugging. Some operators set a "no-more-than-3-attempts-per-session" rule: after 3 failed SMS sends (verified via delivery receipts, not just submitted status), lock the user out and require password reset via email or call center verification.


# Pseudocode: Rate limit and retry logic
def send_otp(phone, user_id, campaign_id):
    # Check per-number limit
    recent_sends = db.query(
        "SELECT COUNT(*) FROM otp_log WHERE phone=? AND ts > NOW() - '1 hour'"
    )
    if recent_sends >= 3:
        return error("Too many codes sent to this number. Retry in 1 hour.")
    
    # Check per-IP limit
    ip = request.remote_addr
    recent_ips = db.query(
        "SELECT COUNT(*) FROM otp_log WHERE ip=? AND ts > NOW() - '1 hour'"
    )
    if recent_ips >= 10:
        return error("Too many attempts from this IP.")
    
    # Check per-campaign limit
    campaign_total = db.query(
        "SELECT SUM(sms_count) FROM campaigns WHERE id=? AND ts > NOW() - '1 day'"
    )
    if campaign_total >= 100000:
        return error("Campaign quota exhausted.")
    
    # Generate OTP, set 5-min expiry, send via gateway
    otp_code = secrets.token_hex(3)  # e.g., "a1b2c3"
    db.insert("otp_codes", {
        "code": otp_code,
        "phone": phone,
        "user_id": user_id,
        "expires_at": now() + 300,
        "created_at": now()
    })
    
    sms_response = gateway.send(
        to=phone,
        text=f"Your code is {otp_code}",
        campaign_id=campaign_id
    )
    
    # Log the send
    db.insert("otp_log", {
        "phone": phone,
        "user_id": user_id,
        "sms_id": sms_response["id"],
        "campaign_id": campaign_id,
        "ip": ip,
        "ts": now()
    })
    
    return {"status": "sent", "sms_id": sms_response["id"]}

HLR lookups: what they tell you and when they're worth the $0.003

An HLR (Home Location Register) lookup queries the carrier's database to confirm that a phone number is active, subscribed, and roaming status. Before sending an OTP, you can optionally perform an HLR check to reduce wasted sends on inactive numbers, dormant SIMs, or ported-out numbers. The HLR response includes: number status (active, inactive, absent subscriber), roaming flag (whether the device is roaming internationally), and operator name. A professional SMS gateway can batch HLR checks and return results in 2–5 seconds per number.

HLR lookups cost $0.003–$0.01 per check (varies by provider and bulk discounts). The ROI calculation: if your average OTP SMS is $0.004 and your failure rate on unverified numbers is 8–12%, an HLR check at $0.003 saves you $0.0004–$0.00048 per send on average (0.08–0.12 * $0.004 expected loss). But there are hidden costs: HLR latency (2–5 seconds) delays code delivery, frustrating users. And HLR is not a foolproof guard; a number can be active in the HLR but unreachable on the actual network (tower down, no signal, SMS inbox full). For OTP use cases, HLR is most valuable in high-churn markets (telecom, prepaid) where inactive numbers are common, and least valuable in developed markets (US, EU) where numbers are stable. A hybrid approach: use HLR on first-time signups (verify the number is real), but skip it on retry flows within the same session (the user just registered that number).

Delivery receipt semantics: submitted vs delivered vs failed

When you send an OTP via SMS, the gateway returns status almost immediately: "submitted." This means the SMSC accepted the message and queued it for delivery. Do not confuse "submitted" with "delivered." Submitted is a contract between you and the SMSC; delivered is a promise from the SMSC and carrier that the message reached the handset. The SMSC then waits for a delivery receipt (SR-SMPP) from the carrier, which can take anywhere from 2 to 60 seconds depending on network load and geography.

Delivery receipt status meanings: "Delivered" = the carrier confirmed the SMS reached the device (device sent ACK back to the network). "Submitted" = stuck in queue, no receipt yet, outcome unknown. "Failed" = the SMSC or carrier rejected the send (invalid number, blacklist, network error, carrier block). Not all carriers return delivery receipts reliably, especially in Africa, South Asia, and Southeast Asia. If you wait 30 seconds and receive no "delivered" or "failed" status, the message is lost in the network and should be retried or fallback should be triggered. Best practice: log the status at each stage (submit timestamp, deliver timestamp, status code) for compliance audits. For OTP, set a 10–15 second timeout: if no delivery receipt arrives, immediately offer fallback (voice, email, authenticator push). Never retry silently; always surface the retry decision to the user ("Code not received? Resend").


# Pseudocode: Wait for delivery receipt
def send_otp_with_receipt(phone, otp_code, sms_gateway):
    # Send SMS
    response = sms_gateway.send(to=phone, text=f"Code: {otp_code}")
    sms_id = response["id"]
    submitted_at = time.time()
    
    # Poll for delivery receipt (with timeout)
    timeout = 30  # seconds
    poll_interval = 1  # second
    status = "submitted"
    
    while time.time() - submitted_at < timeout:
        receipt = sms_gateway.get_receipt(sms_id)
        if receipt["status"] in ["delivered", "failed"]:
            status = receipt["status"]
            break
        time.sleep(poll_interval)
    
    # If still submitted after timeout, treat as likely-failed
    if status == "submitted":
        status = "timeout"
    
    return {
        "sms_id": sms_id,
        "status": status,
        "delivered_at": receipt.get("delivered_at") if status == "delivered" else None
    }

Fallback channels: voice, email, authenticator push

SMS is not bulletproof. A user's phone might be off, in airplane mode, in a dead zone, or stolen. The SIM might be swapped. The number might be ported to a different carrier, causing routing delays. A professional 2FA flow always offers fallback channels. After 10–15 seconds with no SMS delivery receipt, the user interface should display "Code


Read next: prices · developer docs · 149 country pages · more blog posts

Why is SMS 2FA still used instead of WebAuthn or FIDO2?

SMS is cheaper to deploy (no hardware key distribution), works on every phone (no app or device registration required), and has no recovery-key fatigue. WebAuthn is stronger cryptographically but requires device provisioning, platform support (inconsistent on Android), and backup strategies. SMS remains economical for fraud-reduction on low-margin transactions under $500. For high-value operations—banking, crypto exchanges, privilege escalation—FIDO2 or passwordless push is preferable, but SMS still covers ~90% of online identity verification globally because it's carrier-agnostic and requires zero user infrastructure.

What's the difference between HOTP and TOTP codes?

HOTP (HMAC-based One-Time Password, RFC 4226) generates codes based on an incrementing counter that advances with each successful authentication; if you generate a code but don't use it, the next code requires server resync. TOTP (Time-based One-Time Password, RFC 6238) derives codes from UNIX timestamp in 30-second windows, so codes are deterministic from device time alone—no state sync required. TOTP is stateless (authenticator apps like Google Authenticator use it) while HOTP is stateful (hardware tokens, SIM-based OTP). Random 6-digit SMS codes are neither: they're generated server-side, single-use, usually expire in 5–10 minutes, and don't require user-side cryptography. SMS codes are most common in 2FA workflows because they're invisible to phishing (can't be copy-pasted to attacker) and work without user setup.

What happens if an SMS doesn't get delivered?

Delivery failure typically triggers a fallback flow: after 5–15 seconds with no delivery receipt, the system offers retry (another SMS), switch to voice (IVR), email, or push to an authenticator app. The user sees 'Code not received? Resend' or 'Try voice call.' If all channels fail, the session times out (30–60 minutes) and authentication fails safely—no account locked permanently. Under-the-hood, failures map to SMSC rejections (invalid number, blacklist), network congestion (retry queue), or handset issues (SMS inbox full, DND mode). Providers should track delivery receipt status (submitted vs. delivered vs. failed) separately; 'submitted' ≠ 'delivered.' HLR lookups before send can reduce failures by pre-validating active numbers, but cost $0.003–$0.01 per check and add latency.

How do I prevent SMS pumping and toll fraud?

SMS pumping (automated calls to premium-rate numbers hidden in the user's SMS) and toll fraud (attacker triggering SMS sends to expensive routes) are mitigated by: (1) rate-limiting per phone number (max 3–5 codes per hour), (2) per-IP/session rate-limiting (max 10 attempts per IP per hour), (3) known-premium-number filtering (blacklist routes to expensive countries or shortcodes), (4) velocity analysis (flag accounts sending OTP to 10+ different numbers in 1 day), and (5) SCAM2 marking and carrier feedback loops (T-Mobile, Verizon flag SMS sources with high complaint rates). Residential proxies and VPN exit nodes show elevated fraud risk. Crypto exchanges and fintech use geographic whitelisting (send SMS only to registered countries) to reduce exposure. Never send OTP to unverified phone numbers; require user confirmation ('Verify number ending in ...?') before dispatch.

Do I need explicit consent to send transactional SMS?

Transactional SMS (OTP, password reset, account alerts) is typically exempt from consent in most jurisdictions under exemptions for 'necessary' or 'contractually required' messages. Under GDPR (Article 4(11)), transactional SMS requires no prior opt-in if it relates to an initiated transaction. TCPA (47 USC § 227) exempts SMS to established business relationships. PECR (reg 22(3)) exempts existing-customer notifications. LGPD (Law 13.709/2018) and UU 27/2022 (Russia) have narrower exemptions—verify with local counsel. UWG § 7 (Germany) requires consent unless relationship-based. Crypto wallets, exchanges, and fintech apps should still offer SMS opt-out on lower-risk actions (notifications) but enforce OTP for high-risk (withdrawal, API key creation). Best practice: send OTP only to numbers the user registered and confirmed, and honor suppression lists immediately.

What does the iOS #123456 @domain.com autofill pattern do?

iOS 12+ supports domain-bound one-time codes in SMS (RFC 8254). If your SMS contains 'your code is 123456 @example.com #123456', iOS extracts '123456' and autofills it only into fields under example.com. The #123456 is a checksum; @domain.com associates the code with the domain. This blocks cross-domain phishing: an attacker's website cannot steal the code because iOS refuses to autofill it into a mismatched origin. For 2FA, include the preamble: 'Your Apple ID code is 123456 @apple.com #123456'. This requires clients to parse the message (not rely on manual copy-paste), but dramatically reduces phishing OTP theft. Android doesn't support this natively, but Google Play Services can read OTP from SMS and inject into correct app context. If you control the client app, use in-app verification APIs (iOS SFSafariViewController, Android Fido2 API) instead of SMS.

How does SMS routing work from API to the phone?

When you POST to /send with a number and message, the API hits your SMS gateway's SMSC (Short Message Service Center). The SMSC logs the message, validates the number, performs HLR check (optional), and routes to the destination carrier's network via SS7 (Signaling System 7) or modern IP-based protocols (SIP, MAP over IP). The carrier's MSC (Mobile Switching Center) locates the subscriber's HLR (Home Location Register) to confirm the device is active, then routes to the VLR (Visitor Location Register) at the device's current cell site. The phone receives the SMS via the radio interface, stores it in the SIM/device inbox, and triggers a notification. A delivery receipt (SR-SMPP) is sent back through the same path to the SMSC, which reports status to your API. The whole round-trip takes 2–30 seconds depending on network load and international routing. Crypto-only gateways like smsroute operate at the SMSC tier, connecting to 600+ carrier partnerships across 149 countries with rates from $0.004/SMS, using Bitcoin, USDT, ETH, and other crypto—no KYC at signup.

What do delivery receipt statuses (submitted, delivered, failed) actually mean?

'Submitted' = SMS accepted by the SMSC and queued for delivery; no guarantee it reaches the phone. 'Delivered' = SMSC received confirmation from carrier that the message reached the handset (SR-SMPP delivery receipt returned). 'Failed' = SMSC rejected the SMS (invalid number, carrier block, network error) or carrier reported non-delivery. The distinction matters: if you retry only on 'failed,' you miss 10–15% of actual losses that hang in 'submitted' limbo. Best practice: after 30 seconds with no 'delivered' receipt, treat as likely-failed and offer fallback. Some carriers don't return delivery receipts reliably (especially Africa, Southeast Asia); use HLR pre-check to avoid wasted sends. Never trust 'submitted' alone for compliance audits; log actual delivery receipts. For OTP, re-send after 10 seconds if no delivery receipt, and allow user to request voice/email fallback if repeated SMS attempts fail.

Why is SMS 2FA still used instead of WebAuthn or FIDO2?

SMS is cheaper to deploy (no hardware key distribution), works on every phone (no app or device registration required), and has no recovery-key fatigue. WebAuthn is stronger cryptographically but requires device provisioning, platform support (inconsistent on Android), and backup strategies. SMS remains economical for fraud-reduction on low-margin transactions under $500. For high-value operations—banking, crypto exchanges, privilege escalation—FIDO2 or passwordless push is preferable, but SMS still covers ~90% of online identity verification globally because it's carrier-agnostic and requires zero user infrastructure.

What's the difference between HOTP and TOTP codes?

HOTP (HMAC-based One-Time Password, RFC 4226) generates codes based on an incrementing counter that advances with each successful authentication; if you generate a code but don't use it, the next code requires server resync. TOTP (Time-based One-Time Password, RFC 6238) derives codes from UNIX timestamp in 30-second windows, so codes are deterministic from device time alone—no state sync required. TOTP is stateless (authenticator apps like Google Authenticator use it) while HOTP is stateful (hardware tokens, SIM-based OTP). Random 6-digit SMS codes are neither: they're generated server-side, single-use, usually expire in 5–10 minutes, and don't require user-side cryptography. SMS codes are most common in 2FA workflows because they're invisible to phishing (can't be copy-pasted to attacker) and work without user setup.

What happens if an SMS doesn't get delivered?

Delivery failure typically triggers a fallback flow: after 5–15 seconds with no delivery receipt, the system offers retry (another SMS), switch to voice (IVR), email, or push to an authenticator app. The user sees 'Code not received? Resend' or 'Try voice call.' If all channels fail, the session times out (30–60 minutes) and authentication fails safely—no account locked permanently. Under-the-hood, failures map to SMSC rejections (invalid number, blacklist), network congestion (retry queue), or handset issues (SMS inbox full, DND mode). Providers should track delivery receipt status (submitted vs. delivered vs. failed) separately; 'submitted' ≠ 'delivered.' HLR lookups before send can reduce failures by pre-validating active numbers, but cost $0.003–$0.01 per check and add latency.

How do I prevent SMS pumping and toll fraud?

SMS pumping (automated calls to premium-rate numbers hidden in the user's SMS) and toll fraud (attacker triggering SMS sends to expensive routes) are mitigated by: (1) rate-limiting per phone number (max 3–5 codes per hour), (2) per-IP/session rate-limiting (max 10 attempts per IP per hour), (3) known-premium-number filtering (blacklist routes to expensive countries or shortcodes), (4) velocity analysis (flag accounts sending OTP to 10+ different numbers in 1 day), and (5) SCAM2 marking and carrier feedback loops (T-Mobile, Verizon flag SMS sources with high complaint rates). Residential proxies and VPN exit nodes show elevated fraud risk. Crypto exchanges and fintech use geographic whitelisting (send SMS only to registered countries) to reduce exposure. Never send OTP to unverified phone numbers; require user confirmation ('Verify number ending in ...?') before dispatch.

Do I need explicit consent to send transactional SMS?

Transactional SMS (OTP, password reset, account alerts) is typically exempt from consent in most jurisdictions under exemptions for 'necessary' or 'contractually required' messages. Under GDPR (Article 4(11)), transactional SMS requires no prior opt-in if it relates to an initiated transaction. TCPA (47 USC § 227) exempts SMS to established business relationships. PECR (reg 22(3)) exempts existing-customer notifications. LGPD (Law 13.709/2018) and UU 27/2022 (Russia) have narrower exemptions—verify with local counsel. UWG § 7 (Germany) requires consent unless relationship-based. Crypto wallets, exchanges, and fintech apps should still offer SMS opt-out on lower-risk actions (notifications) but enforce OTP for high-risk (withdrawal, API key creation). Best practice: send OTP only to numbers the user registered and confirmed, and honor suppression lists immediately.

What does the iOS #123456 @domain.com autofill pattern do?

iOS 12+ supports domain-bound one-time codes in SMS (RFC 8254). If your SMS contains 'your code is 123456 @example.com #123456', iOS extracts '123456' and autofills it only into fields under example.com. The #123456 is a checksum; @domain.com associates the code with the domain. This blocks cross-domain phishing: an attacker's website cannot steal the code because iOS refuses to autofill it into a mismatched origin. For 2FA, include the preamble: 'Your Apple ID code is 123456 @apple.com #123456'. This requires clients to parse the message (not rely on manual copy-paste), but dramatically reduces phishing OTP theft. Android doesn't support this natively, but Google Play Services can read OTP from SMS and inject into correct app context. If you control the client app, use in-app verification APIs (iOS SFSafariViewController, Android Fido2 API) instead of SMS.

How does SMS routing work from API to the phone?

When you POST to /send with a number and message, the API hits your SMS gateway's SMSC (Short Message Service Center). The SMSC logs the message, validates the number, performs HLR check (optional), and routes to the destination carrier's network via SS7 (Signaling System 7) or modern IP-based protocols (SIP, MAP over IP). The carrier's MSC (Mobile Switching Center) locates the subscriber's HLR (Home Location Register) to confirm the device is active, then routes to the VLR (Visitor Location Register) at the device's current cell site. The phone receives the SMS via the radio interface, stores it in the SIM/device inbox, and triggers a notification. A delivery receipt (SR-SMPP) is sent back through the same path to the SMSC, which reports status to your API. The whole round-trip takes 2–30 seconds depending on network load and international routing. Crypto-only gateways like smsroute operate at the SMSC tier, connecting to 600+ carrier partnerships across 149 countries with rates from $0.004/SMS, using Bitcoin, USDT, ETH, and other crypto—no KYC at signup.

What do delivery receipt statuses (submitted, delivered, failed) actually mean?

'Submitted' = SMS accepted by the SMSC and queued for delivery; no guarantee it reaches the phone. 'Delivered' = SMSC received confirmation from carrier that the message reached the handset (SR-SMPP delivery receipt returned). 'Failed' = SMSC rejected the SMS (invalid number, carrier block, network error) or carrier reported non-delivery. The distinction matters: if you retry only on 'failed,' you miss 10–15% of actual losses that hang in 'submitted' limbo. Best practice: after 30 seconds with no 'delivered' receipt, treat as likely-failed and offer fallback. Some carriers don't return delivery receipts reliably (especially Africa, Southeast Asia); use HLR pre-check to avoid wasted sends. Never trust 'submitted' alone for compliance audits; log actual delivery receipts. For OTP, re-send after 10 seconds if no delivery receipt, and allow user to request voice/email fallback if repeated SMS attempts fail.

Why is SMS 2FA still used instead of WebAuthn or FIDO2?

SMS is cheaper to deploy (no hardware key distribution), works on every phone (no app or device registration required), and has no recovery-key fatigue. WebAuthn is stronger cryptographically but requires device provisioning, platform support (inconsistent on Android), and backup strategies. SMS remains economical for fraud-reduction on low-margin transactions under $500. For high-value operations—banking, crypto exchanges, privilege escalation—FIDO2 or passwordless push is preferable, but SMS still covers ~90% of online identity verification globally because it's carrier-agnostic and requires zero user infrastructure.

What's the difference between HOTP and TOTP codes?

HOTP (HMAC-based One-Time Password, RFC 4226) generates codes based on an incrementing counter that advances with each successful authentication; if you generate a code but don't use it, the next code requires server resync. TOTP (Time-based One-Time Password, RFC 6238) derives codes from UNIX timestamp in 30-second windows, so codes are deterministic from device time alone—no state sync required. TOTP is stateless (authenticator apps like Google Authenticator use it) while HOTP is stateful (hardware tokens, SIM-based OTP). Random 6-digit SMS codes are neither: they're generated server-side, single-use, usually expire in 5–10 minutes, and don't require user-side cryptography. SMS codes are most common in 2FA workflows because they're invisible to phishing (can't be copy-pasted to attacker) and work without user setup.

What happens if an SMS doesn't get delivered?

Delivery failure typically triggers a fallback flow: after 5–15 seconds with no delivery receipt, the system offers retry (another SMS), switch to voice (IVR), email, or push to an authenticator app. The user sees 'Code not received? Resend' or 'Try voice call.' If all channels fail, the session times out (30–60 minutes) and authentication fails safely—no account locked permanently. Under-the-hood, failures map to SMSC rejections (invalid number, blacklist), network congestion (retry queue), or handset issues (SMS inbox full, DND mode). Providers should track delivery receipt status (submitted vs. delivered vs. failed) separately; 'submitted' ≠ 'delivered.' HLR lookups before send can reduce failures by pre-validating active numbers, but cost $0.003–$0.01 per check and add latency.

How do I prevent SMS pumping and toll fraud?

SMS pumping (automated calls to premium-rate numbers hidden in the user's SMS) and toll fraud (attacker triggering SMS sends to expensive routes) are mitigated by: (1) rate-limiting per phone number (max 3–5 codes per hour), (2) per-IP/session rate-limiting (max 10 attempts per IP per hour), (3) known-premium-number filtering (blacklist routes to expensive countries or shortcodes), (4) velocity analysis (flag accounts sending OTP to 10+ different numbers in 1 day), and (5) SCAM2 marking and carrier feedback loops (T-Mobile, Verizon flag SMS sources with high complaint rates). Residential proxies and VPN exit nodes show elevated fraud risk. Crypto exchanges and fintech use geographic whitelisting (send SMS only to registered countries) to reduce exposure. Never send OTP to unverified phone numbers; require user confirmation ('Verify number ending in ...?') before dispatch.

Do I need explicit consent to send transactional SMS?

Transactional SMS (OTP, password reset, account alerts) is typically exempt from consent in most jurisdictions under exemptions for 'necessary' or 'contractually required' messages. Under GDPR (Article 4(11)), transactional SMS requires no prior opt-in if it relates to an initiated transaction. TCPA (47 USC § 227) exempts SMS to established business relationships. PECR (reg 22(3)) exempts existing-customer notifications. LGPD (Law 13.709/2018) and UU 27/2022 (Russia) have narrower exemptions—verify with local counsel. UWG § 7 (Germany) requires consent unless relationship-based. Crypto wallets, exchanges, and fintech apps should still offer SMS opt-out on lower-risk actions (notifications) but enforce OTP for high-risk (withdrawal, API key creation). Best practice: send OTP only to numbers the user registered and confirmed, and honor suppression lists immediately.

What does the iOS #123456 @domain.com autofill pattern do?

iOS 12+ supports domain-bound one-time codes in SMS (RFC 8254). If your SMS contains 'your code is 123456 @example.com #123456', iOS extracts '123456' and autofills it only into fields under example.com. The #123456 is a checksum; @domain.com associates the code with the domain. This blocks cross-domain phishing: an attacker's website cannot steal the code because iOS refuses to autofill it into a mismatched origin. For 2FA, include the preamble: 'Your Apple ID code is 123456 @apple.com #123456'. This requires clients to parse the message (not rely on manual copy-paste), but dramatically reduces phishing OTP theft. Android doesn't support this natively, but Google Play Services can read OTP from SMS and inject into correct app context. If you control the client app, use in-app verification APIs (iOS SFSafariViewController, Android Fido2 API) instead of SMS.

How does SMS routing work from API to the phone?

When you POST to /send with a number and message, the API hits your SMS gateway's SMSC (Short Message Service Center). The SMSC logs the message, validates the number, performs HLR check (optional), and routes to the destination carrier's network via SS7 (Signaling System 7) or modern IP-based protocols (SIP, MAP over IP). The carrier's MSC (Mobile Switching Center) locates the subscriber's HLR (Home Location Register) to confirm the device is active, then routes to the VLR (Visitor Location Register) at the device's current cell site. The phone receives the SMS via the radio interface, stores it in the SIM/device inbox, and triggers a notification. A delivery receipt (SR-SMPP) is sent back through the same path to the SMSC, which reports status to your API. The whole round-trip takes 2–30 seconds depending on network load and international routing. Crypto-only gateways like smsroute operate at the SMSC tier, connecting to 600+ carrier partnerships across 149 countries with rates from $0.004/SMS, using Bitcoin, USDT, ETH, and other crypto—no KYC at signup.

What do delivery receipt statuses (submitted, delivered, failed) actually mean?

'Submitted' = SMS accepted by the SMSC and queued for delivery; no guarantee it reaches the phone. 'Delivered' = SMSC received confirmation from carrier that the message reached the handset (SR-SMPP delivery receipt returned). 'Failed' = SMSC rejected the SMS (invalid number, carrier block, network error) or carrier reported non-delivery. The distinction matters: if you retry only on 'failed,' you miss 10–15% of actual losses that hang in 'submitted' limbo. Best practice: after 30 seconds with no 'delivered' receipt, treat as likely-failed and offer fallback. Some carriers don't return delivery receipts reliably (especially Africa, Southeast Asia); use HLR pre-check to avoid wasted sends. Never trust 'submitted' alone for compliance audits; log actual delivery receipts. For OTP, re-send after 10 seconds if no delivery receipt, and allow user to request voice/email fallback if repeated SMS attempts fail.

Why is SMS 2FA still used instead of WebAuthn or FIDO2?

SMS is cheaper to deploy (no hardware key distribution), works on every phone (no app or device registration required), and has no recovery-key fatigue. WebAuthn is stronger cryptographically but requires device provisioning, platform support (inconsistent on Android), and backup strategies. SMS remains economical for fraud-reduction on low-margin transactions under $500. For high-value operations—banking, crypto exchanges, privilege escalation—FIDO2 or passwordless push is preferable, but SMS still covers ~90% of online identity verification globally because it's carrier-agnostic and requires zero user infrastructure.

What's the difference between HOTP and TOTP codes?

HOTP (HMAC-based One-Time Password, RFC 4226) generates codes based on an incrementing counter that advances with each successful authentication; if you generate a code but don't use it, the next code requires server resync. TOTP (Time-based One-Time Password, RFC 6238) derives codes from UNIX timestamp in 30-second windows, so codes are deterministic from device time alone—no state sync required. TOTP is stateless (authenticator apps like Google Authenticator use it) while HOTP is stateful (hardware tokens, SIM-based OTP). Random 6-digit SMS codes are neither: they're generated server-side, single-use, usually expire in 5–10 minutes, and don't require user-side cryptography. SMS codes are most common in 2FA workflows because they're invisible to phishing (can't be copy-pasted to attacker) and work without user setup.

What happens if an SMS doesn't get delivered?

Delivery failure typically triggers a fallback flow: after 5–15 seconds with no delivery receipt, the system offers retry (another SMS), switch to voice (IVR), email, or push to an authenticator app. The user sees 'Code not received? Resend' or 'Try voice call.' If all channels fail, the session times out (30–60 minutes) and authentication fails safely—no account locked permanently. Under-the-hood, failures map to SMSC rejections (invalid number, blacklist), network congestion (retry queue), or handset issues (SMS inbox full, DND mode). Providers should track delivery receipt status (submitted vs. delivered vs. failed) separately; 'submitted' ≠ 'delivered.' HLR lookups before send can reduce failures by pre-validating active numbers, but cost $0.003–$0.01 per check and add latency.

How do I prevent SMS pumping and toll fraud?

SMS pumping (automated calls to premium-rate numbers hidden in the user's SMS) and toll fraud (attacker triggering SMS sends to expensive routes) are mitigated by: (1) rate-limiting per phone number (max 3–5 codes per hour), (2) per-IP/session rate-limiting (max 10 attempts per IP per hour), (3) known-premium-number filtering (blacklist routes to expensive countries or shortcodes), (4) velocity analysis (flag accounts sending OTP to 10+ different numbers in 1 day), and (5) SCAM2 marking and carrier feedback loops (T-Mobile, Verizon flag SMS sources with high complaint rates). Residential proxies and VPN exit nodes show elevated fraud risk. Crypto exchanges and fintech use geographic whitelisting (send SMS only to registered countries) to reduce exposure. Never send OTP to unverified phone numbers; require user confirmation ('Verify number ending in ...?') before dispatch.

Do I need explicit consent to send transactional SMS?

Transactional SMS (OTP, password reset, account alerts) is typically exempt from consent in most jurisdictions under exemptions for 'necessary' or 'contractually required' messages. Under GDPR (Article 4(11)), transactional SMS requires no prior opt-in if it relates to an initiated transaction. TCPA (47 USC § 227) exempts SMS to established business relationships. PECR (reg 22(3)) exempts existing-customer notifications. LGPD (Law 13.709/2018) and UU 27/2022 (Russia) have narrower exemptions—verify with local counsel. UWG § 7 (Germany) requires consent unless relationship-based. Crypto wallets, exchanges, and fintech apps should still offer SMS opt-out on lower-risk actions (notifications) but enforce OTP for high-risk (withdrawal, API key creation). Best practice: send OTP only to numbers the user registered and confirmed, and honor suppression lists immediately.

What does the iOS #123456 @domain.com autofill pattern do?

iOS 12+ supports domain-bound one-time codes in SMS (RFC 8254). If your SMS contains 'your code is 123456 @example.com #123456', iOS extracts '123456' and autofills it only into fields under example.com. The #123456 is a checksum; @domain.com associates the code with the domain. This blocks cross-domain phishing: an attacker's website cannot steal the code because iOS refuses to autofill it into a mismatched origin. For 2FA, include the preamble: 'Your Apple ID code is 123456 @apple.com #123456'. This requires clients to parse the message (not rely on manual copy-paste), but dramatically reduces phishing OTP theft. Android doesn't support this natively, but Google Play Services can read OTP from SMS and inject into correct app context. If you control the client app, use in-app verification APIs (iOS SFSafariViewController, Android Fido2 API) instead of SMS.

How does SMS routing work from API to the phone?

When you POST to /send with a number and message, the API hits your SMS gateway's SMSC (Short Message Service Center). The SMSC logs the message, validates the number, performs HLR check (optional), and routes to the destination carrier's network via SS7 (Signaling System 7) or modern IP-based protocols (SIP, MAP over IP). The carrier's MSC (Mobile Switching Center) locates the subscriber's HLR (Home Location Register) to confirm the device is active, then routes to the VLR (Visitor Location Register) at the device's current cell site. The phone receives the SMS via the radio interface, stores it in the SIM/device inbox, and triggers a notification. A delivery receipt (SR-SMPP) is sent back through the same path to the SMSC, which reports status to your API. The whole round-trip takes 2–30 seconds depending on network load and international routing. Crypto-only gateways like smsroute operate at the SMSC tier, connecting to 600+ carrier partnerships across 149 countries with rates from $0.004/SMS, using Bitcoin, USDT, ETH, and other crypto—no KYC at signup.

What do delivery receipt statuses (submitted, delivered, failed) actually mean?

'Submitted' = SMS accepted by the SMSC and queued for delivery; no guarantee it reaches the phone. 'Delivered' = SMSC received confirmation from carrier that the message reached the handset (SR-SMPP delivery receipt returned). 'Failed' = SMSC rejected the SMS (invalid number, carrier block, network error) or carrier reported non-delivery. The distinction matters: if you retry only on 'failed,' you miss 10–15% of actual losses that hang in 'submitted' limbo. Best practice: after 30 seconds with no 'delivered' receipt, treat as likely-failed and offer fallback. Some carriers don't return delivery receipts reliably (especially Africa, Southeast Asia); use HLR pre-check to avoid wasted sends. Never trust 'submitted' alone for compliance audits; log actual delivery receipts. For OTP, re-send after 10 seconds if no delivery receipt, and allow user to request voice/email fallback if repeated SMS attempts fail.