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.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "body/phone must match pattern \"^\\+[1-9]\\d{6,14}$\""
}
}General & authentication
| Status | Code | Meaning |
|---|---|---|
400 | VALIDATION_ERROR | The request body was malformed, missing a required field, or the phone number isn't a valid E.164 number. |
401 | INVALID_API_KEY | The Authorization header is missing or the secret key is invalid. |
401 | ACCOUNT_SUSPENDED | Your account is suspended and cannot call the API. Contact support. |
404 | NOT_FOUND | The requested resource (e.g. an OTP request id) doesn't exist or doesn't belong to your account. |
429 | RATE_LIMIT_EXCEEDED | Too many requests. Slow down and retry after a short delay. |
500 | INTERNAL_ERROR | Something failed on Authevo's side. Safe to retry — these are logged and monitored. |
Sending & verification
| Status | Code | Meaning |
|---|---|---|
400 | INVALID_PHONE | The phone number is not a valid, reachable number for this endpoint. |
400 | OTP_NOT_FOUND | The code has expired, was already used, or was never sent for this phone number. |
409 | IDEMPOTENCY_KEY_IN_PROGRESS | A request with this Idempotency-Key is still being processed — wait for it to finish instead of sending a third attempt. |
409 | TEMPLATE_NOT_READY | The WhatsApp message template isn't approved yet on the sending number. Falls back to Telegram automatically if the recipient has linked it. |
409 | CHANNEL_NOT_LINKED | WhatsApp 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. |
429 | TOO_MANY_ATTEMPTS | Too many failed verification attempts for this phone number. Wait before trying again. |
500 | DELIVERY_FAILED | The message could not be delivered on any channel. Safe to retry. |
503 | TELEGRAM_UNAVAILABLE | Telegram fallback isn't available right now. |
Authevo's shared WhatsApp number
| Status | Code | Meaning |
|---|---|---|
400 | CENTRAL_WHATSAPP_UNSUPPORTED_REGION | This 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. |
400 | INTL_PRICING_NOT_CONFIGURED | No 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. |
400 | INTL_PRICE_BELOW_COST | A 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. |
403 | CENTRAL_WHATSAPP_CONNECT_REQUIRED | Your 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. |
429 | CENTRAL_WHATSAPP_LIMIT | The 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. |
503 | CENTRAL_WHATSAPP_PAUSED | Sending 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)
| Status | Code | Meaning |
|---|---|---|
400 | TOTP_NOT_ENROLLED | This phone number has no active TOTP enrollment to verify or disable. |
409 | ALREADY_ENROLLED | This phone number already has a confirmed TOTP enrollment. Pass replace: true to reissue one. |
429 | TOO_MANY_ATTEMPTS | Too many failed verification attempts for this phone number. Wait before trying again. |
503 | TOTP_NOT_CONFIGURED | TOTP is temporarily unavailable on Authevo's side. |
Billing & credit
| Status | Code | Meaning |
|---|---|---|
402 | INSUFFICIENT_CREDITS | Your account balance is below the amount required to send — add prepaid credit to continue (a $2 minimum balance applies). |
402 | DEPOSIT_REQUIRED | Your account has never had a deposit — add prepaid credit before your first send. |
402 | FREE_TRIAL_EXHAUSTED | You've used all of your free verifications. Add credit to keep sending. |
429 | SPEND_CAP_EXCEEDED | Your hourly spend cap was reached. It resets automatically; raise it from your dashboard if you're hitting it often. |
500 | BILLING_ERROR | The verification itself succeeded, but billing it failed — Authevo's side, not yours. Logged and reconciled automatically; the verified result stands. |
503 | FREE_TRIAL_PAUSED | The free trial is temporarily paused platform-wide. Retry shortly, or add credit to send immediately. |
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.
| Scope | Limit | Window |
|---|---|---|
| Same recipient phone number (send) | 3 requests | 10 minutes |
| Same account + recipient resend | 1 request | 30 seconds |
| Same recipient across all accounts | 6 / 20 requests | 10 minutes / 24 hours |
| Same API credential (OTP send or verify) | 300 requests | 1 minute |
| Same account or API credential (OTP burst) | 100 requests (standard) | 10 seconds |
| Playground, same recipient | 1 / 3 / 5 requests | 1 minute / 10 minutes / 24 hours |
| Unauthenticated source IP (send backstop) | 10–40 requests | 1 hour |
| Failed verify attempts, same phone number | 5 attempts | 15-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 & limitsSafety Floor
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-2f2b6a7c9e10Generate 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+).