Errors
The Qashio error envelope, status codes, and a retry strategy that will not double-spend.
Errors use a structured envelope. They omit success and always carry an errors array plus a
meta.request_id: the single most useful thing to quote when you contact Qashio support.
{
"status_code": 404,
"message": "Resource not found.",
"errors": [{ "field": null, "code": "NOT_FOUND", "message": "Resource not found." }],
"meta": { "request_id": "req_a1b2c3d4e5f6", "timestamp": "2026-07-17T08:00:00.000Z" }
}
meta.request_id is also returned as the x-request-id response header, so you can log it even when
you do not parse the body.
Status codes
| Status | Meaning | Retry? |
|---|---|---|
400 |
Invalid parameter: malformed id, unknown enum value, incomplete date range | No. Fix the request |
401 |
Missing, expired or invalid access token | Refresh the token, then retry once |
403 |
Token is valid but the user is not permitted to perform this action | No |
404 |
Resource does not exist, or belongs to another company | No |
429 |
Rate limit exceeded | Yes, with exponential backoff |
5xx |
Qashio-side failure | Yes, with backoff and a capped attempt count |
Field-level validation
When a write fails validation, each offending field appears as its own entry so you can map errors back onto a form.
{
"status_code": 400,
"message": "Validation failed.",
"errors": [
{ "field": "card_type", "code": "INVALID_ENUM", "message": "card_type must be VIRTUAL or PHYSICAL." },
{ "field": "spend_limit_max_amount", "code": "OUT_OF_RANGE", "message": "Must be greater than 0." }
],
"meta": { "request_id": "req_a1b2c3d4e5f6", "timestamp": "2026-07-17T08:00:00.000Z" }
}
Company scoping
All data is scoped to the company bound to your access token. A resource that belongs to another
company returns 404: never that company’s data. Treat a 404 on an id you believe is valid as a
scoping problem, not a deleted record.
A retry strategy that is safe for money
Reads are safe to retry. Writes are not uniformly safe, so:
- Never blindly retry
POST /public/v1/core/cards. A timeout does not prove the card was not issued. Re-list cards for the user and check before issuing again. PUTendpoints: updating top-up targets, suspending a card: are idempotent in effect. Retrying with the same body converges on the same state.- Back off exponentially on
429and5xx, with jitter, and cap total attempts. Qashio does not reward tight retry loops. - Log
meta.request_idon every failure. It is what Qashio support will ask for first.