// errors
Errors
Every error returns the same envelope with a stable, machine-readable code. Branch on code, not the HTTP status alone - several scenarios can share one status.
{
"status": "error",
"statusCode": 402,
"code": "INSUFFICIENT_CREDITS",
"message": "Not enough credit balance to send this message.",
"path": "/v1/messages",
"data": null,
"details": { "required": 2.8, "available": 1.2 }
}
The envelope fields:
| Field | Description |
|---|---|
| status | Always "error". |
| statusCode | Mirrors the HTTP status. |
| code | The stable discriminator to branch on. |
| message | Human-readable, safe to log; override for UX copy. |
| path | The request path that produced the error. |
| fieldErrors | Per-field messages on validation failures. |
| data | Always null on errors. |
Error codes
| Code | HTTP | Meaning |
|---|---|---|
| VALIDATION_ERROR | 422 | A field failed validation. See fieldErrors. |
| INVALID_API_KEY | 401 | The API key is missing or invalid. |
| API_KEY_REVOKED | 401 | The API key has been revoked. |
| API_KEY_SCOPE_DENIED | 403 | The key lacks the required scope for this call. |
| INSUFFICIENT_CREDITS | 402 | Not enough credit balance. Top up and retry. |
| NO_VALID_RECIPIENTS | 400 | No recipient passed validation (bad numbers). |
| SUPPRESSED_RECIPIENT | 400 | A recipient is on your opt-out / suppression list. |
| SENDER_ID_NOT_APPROVED | 403 | The requested sender ID is not approved. |
| IDEMPOTENCY_KEY_CONFLICT | 409 | The Idempotency-Key was reused with a different body. |
| PROVIDER_SEND_FAILED | 502 | The upstream network could not be reached. |
| RATE_LIMITED | 429 | Too many requests. Back off and retry. |
| NOT_FOUND | 404 | The requested resource does not exist. |
| INTERNAL_ERROR | 500 | An unexpected server error. Safe to retry idempotently. |
Branch on code
A business
403 (API_KEY_SCOPE_DENIED) is not the same as an auth 403 (FORBIDDEN). Keying on code keeps your handling correct as the API grows.Next: API reference