Documentation
Error codes
Every error uses the same envelope, an HTTP status plus a typed body. Switch on error.type to handle them.
Every error uses the same envelope: an HTTP status plus a typed body. Switch on
error.type to handle them programmatically.
{
"error": {
"type": "InsufficientFundsError",
"message": "Not enough balance to send."
}
}
Reference
| Status | Type | Meaning |
|---|---|---|
422 | ValidationError | Missing or malformed request body. |
422 | InvalidRecipientError | recipient is not a valid phone or email. |
401 | HTTPException | Missing, invalid, or revoked API key. |
404 | HTTPException | otp_id not found, or not on your company. |
409 | NoEnabledChannelError | No enabled channel can reach this recipient. Configure your channels first. |
403 | GeoBlockedError | The recipient’s country is blocked. |
403 | IpReputationBlockedError | The declared client_ip is a known abuse source (see send). |
402 | InsufficientFundsError | Not enough balance to send. |
429 | RateLimitExceededError | Too many requests for this recipient. |
409 | ResendNotAllowedError | The OTP’s send attempts are spent, or no enabled channel is left for the recipient. |
429 | ResendCooldownError | Resend attempted within the cooldown window. Retry-After carries the seconds left. |
422 | InvalidIdempotencyKeyError | The idempotency-key header is longer than 128 characters. |
Handling errors
401means the key is wrong or revoked. Check Authentication.402and403are account, destination, or client-IP policy limits, not code bugs; surface a clear message and stop retrying.429is rate limiting or a resend cooldown; back off and try again later. A message ofRate limit exceeded: client_ipmeans your requests are not passing the end user’s IP; addclient_ipto send for the normal limits.409means there is no channel to use: on send your app has none enabled, and on resend the OTP’s attempts are spent. Start a new send if appropriate.422is a validation problem in the request: fix the body (or theidempotency-keyheader) and retry. Retrying the same request unchanged will fail the same way.