Skip to content

Errors

Authevo uses standard HTTP status codes. Successful responses are wrapped in a data object; failures return an error object with a machine-readable code and a human-readable message. The tables below cover every code the public send/verify/TOTP endpoints can return — always branch on the HTTP status and error.code, not the message, since messages may change.

400 Bad Request
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "body/phone must match pattern \"^\\+[1-9]\\d{6,14}$\""
  }
}

General & authentication

StatusCodeMeaning
400VALIDATION_ERRORThe request body was malformed, missing a required field, or the phone number isn't a valid E.164 number.
401INVALID_API_KEYThe Authorization header is missing or the secret key is invalid.
401ACCOUNT_SUSPENDEDYour account is suspended and cannot call the API. Contact support.
404NOT_FOUNDThe requested resource (e.g. an OTP request id) doesn't exist or doesn't belong to your account.
429RATE_LIMIT_EXCEEDEDToo many requests. Slow down and retry after a short delay.
500INTERNAL_ERRORSomething failed on Authevo's side. Safe to retry — these are logged and monitored.

Sending & verification

StatusCodeMeaning
400INVALID_PHONEThe phone number is not a valid, reachable number for this endpoint.
400OTP_NOT_FOUNDThe code has expired, was already used, or was never sent for this phone number.
409IDEMPOTENCY_KEY_IN_PROGRESSA request with this Idempotency-Key is still being processed — wait for it to finish instead of sending a third attempt.
409TEMPLATE_NOT_READYThe WhatsApp message template isn't approved yet on the sending number. Falls back to Telegram automatically if the recipient has linked it.
409CHANNEL_NOT_LINKEDWhatsApp delivery failed and this recipient hasn't linked Telegram yet — nothing was delivered on this call. Show them the returned telegram_bot_url; once they tap Start in Telegram, behavior depends on which endpoint you called: /v1/otp/send delivers a fresh code there automatically (no need to call it again), but /v1/otp/deliver does not — Authevo can't regenerate a code you generated yourself, so retry /v1/otp/deliver with the same code once they've linked. Prefer to avoid this error entirely? Call the Telegram-link endpoint proactively, right after signup.
429TOO_MANY_ATTEMPTSToo many failed verification attempts for this phone number. Wait before trying again.
500DELIVERY_FAILEDThe message could not be delivered on any channel. Safe to retry.
503TELEGRAM_UNAVAILABLETelegram fallback isn't available right now.

Authevo's shared WhatsApp number

StatusCodeMeaning
400CENTRAL_WHATSAPP_UNSUPPORTED_REGIONThis destination is not enabled for sending on Authevo's shared WhatsApp number. The error message names the destinations that are; the live list is published on our pricing page. Connect your own WhatsApp Business Account to send anywhere else.
400INTL_PRICING_NOT_CONFIGUREDNo price is configured for this destination on your account, so the send is refused rather than billed at a guess. Connect your own WhatsApp Business Account, or contact support to have the destination enabled.
400INTL_PRICE_BELOW_COSTA price is configured for this destination but sits below what delivery costs, so sending is held rather than run at a loss. This is a configuration problem on our side — contact support.
403CENTRAL_WHATSAPP_CONNECT_REQUIREDYour account has used its allowance on Authevo's shared WhatsApp number. Connect your own WhatsApp Business Account to keep sending — it has no such allowance.
429CENTRAL_WHATSAPP_LIMITThe hourly sending limit for Authevo's shared WhatsApp number has been reached for your account. Retry after the window, or connect your own WhatsApp Business Account to remove the limit.
503CENTRAL_WHATSAPP_PAUSEDSending on Authevo's shared WhatsApp number is temporarily paused, either for your account or platform-wide. Retry shortly. Sending on your own WhatsApp Business Account is never affected.

Two-Factor (TOTP)

StatusCodeMeaning
400TOTP_NOT_ENROLLEDThis phone number has no active TOTP enrollment to verify or disable.
409ALREADY_ENROLLEDThis phone number already has a confirmed TOTP enrollment. Pass replace: true to reissue one.
429TOO_MANY_ATTEMPTSToo many failed verification attempts for this phone number. Wait before trying again.
503TOTP_NOT_CONFIGUREDTOTP is temporarily unavailable on Authevo's side.

Billing & credit

StatusCodeMeaning
402INSUFFICIENT_CREDITSYour account balance is below the amount required to send — add prepaid credit to continue (a $2 minimum balance applies).
402DEPOSIT_REQUIREDYour account has never had a deposit — add prepaid credit before your first send.
402FREE_TRIAL_EXHAUSTEDYou've used all of your free verifications. Add credit to keep sending.
429SPEND_CAP_EXCEEDEDYour hourly spend cap was reached. It resets automatically; raise it from your dashboard if you're hitting it often.
500BILLING_ERRORThe verification itself succeeded, but billing it failed — Authevo's side, not yours. Logged and reconciled automatically; the verified result stands.
503FREE_TRIAL_PAUSEDThe free trial is temporarily paused platform-wide. Retry shortly, or add credit to send immediately.
Always branch on the HTTP status and the error.code, not the message — messages may change.

Rate limits

Every API operation has a server-side admission policy, with separate burst and sustained controls plus recipient, account, credential, verification-lockout, and spend safeguards. When you exceed a limit, back off for the number of seconds in Retry-After; do not retry sooner. RateLimit-Policy and X-Authevo-Rate-Tier report the effective aggregate send allowance.

ScopeLimitWindow
Same recipient phone number (send)3 requests10 minutes
Same account + recipient resend1 request30 seconds
Same recipient across all accounts6 / 20 requests10 minutes / 24 hours
Same API credential (OTP send or verify)300 requests1 minute
Same account or API credential (OTP burst)100 requests (standard)10 seconds
Playground, same recipient1 / 3 / 5 requests1 minute / 10 minutes / 24 hours
Unauthenticated source IP (send backstop)10–40 requests1 hour
Failed verify attempts, same phone number5 attempts15-minute block

The 10–40/hour row applies only when a request has no authenticated account identity. Verified server traffic is isolated at the edge by an opaque credential fingerprint and receives a per-account hourly backstop equal to 60 times its sustained tier, so customers sharing cloud egress never consume each other's allowance. Standard accounts receive 300/min sustained, 100/10s burst, and 18,000/hour. Reviewed tiers of 1,000, 5,000, or a bounded custom rate expire automatically and require balance, fraud-history, expected-traffic, delivery-quality, and customer-owned-WABA review. Recipient and global safety limits can never be waived.

Need higher throughput?

The authenticated Usage & limits page shows your effective tier, live burst/minute/hour use with separate resets, sanitized recent throttles, and eligibility. Submit production traffic evidence there for human review. Approved tiers expire automatically; only aggregate throughput changes, while recipient cooldowns and platform safety ceilings remain enforced.

Open Usage & limits

Safety Floor

Beyond the limits above, the Safety Floor watches your account's real-world success rate: three consecutive days with a 24-hour verification success rate under 55% moves your account from pay-per-success back to the per-message tier until it recovers. It's a guardrail against sustained abuse or a broken integration silently running up your bill — automatic, nothing to configure.

Idempotency

Send an Idempotency-Key header on POST /v1/otp/send or POST /v1/otp/deliver to make network retries safe — a retry with the same key replays the original response instead of sending (and charging for) a second message.

Idempotency-Key: 5b6b4c9e-6e0a-4b7a-9b7a-2f2b6a7c9e10

Generate a fresh key per logical send attempt (a UUID works well) and reuse it only when retrying that exact same attempt. Keys are scoped to your account and remembered for 24 hours — a retry with the same key while the original request is still in flight gets back a 409 IDEMPOTENCY_KEY_IN_PROGRESS immediately, rather than racing it.

The header is entirely optional — requests without one behave exactly as before. It's worth adding wherever your client-side retry logic could plausibly re-send the same request after a timeout. The official Node SDK takes it as an idempotencyKey option on otp.send and otp.deliver (v0.3.0+).