Errors
How EzPays reports failures.
Every error response uses the same envelope:
{
"error": {
"code": "validation_error",
"message": "amount: must be a positive integer in minor units, as a string",
"request_id": "req_2f8a4d9c1e0b4a5c",
"details": [
{ "path": ["amount"], "message": "must be a positive integer in minor units, as a string" }
]
}
}code— stable, machine-readable identifier. Branch on this.message— human-readable. Never branch on the text.request_id— quote this in support tickets.details— optional structured info; shape depends on the code.
Error codes
| Code | HTTP | Meaning |
|---|---|---|
validation_error | 400 | Request body or query failed schema validation. |
unauthorized | 401 | Missing or invalid API key. |
payment_rejected | 402 | Payment provider declined the operation. |
forbidden | 403 | Authenticated but missing scope. |
not_found | 404 | The targeted resource doesn't exist (or belongs to a different tenant). |
method_not_allowed | 405 | HTTP method not supported on this path. |
idempotency_conflict | 409 | Idempotency-Key reused with a different body. |
rate_limited | 429 | Too many requests; honor the Retry-After header. |
internal | 500 | Unexpected server error. Safe to retry with idempotency. |
provider_unavailable | 502 | Upstream payment provider failed; safe to retry. |
Retry policy
| Code | Safe to retry? | Strategy |
|---|---|---|
internal, provider_unavailable, rate_limited | Yes | Exponential backoff (start 1s, max 60s, with jitter); always reuse the same Idempotency-Key. |
validation_error, forbidden, not_found, idempotency_conflict | No | Fix the request and try again. |
unauthorized | After fixing | Rotate or fix the key. |
Tips
- Always log
request_idfrom error responses; we can match it to server-side traces. detailsforvalidation_erroris an array of{ path, message }items — easy to surface at the field level in your UI.