Content-Type: application/problem+json:
string
The stable, machine-readable name of what went wrong. Branch on this, not on
detail and not on type.string
https://api.splox.com/problems/<code> — the same code as a URI.string
The status’s name.
integer
The HTTP status, repeated in the body.
string
A sentence for a person. Written to be shown; not to be parsed.
string
Whatever you sent as
X-Request-Id, echoed back — send one and the server’s logs and your logs name the same request.array
On a validation failure, one entry per bad field. See below.
Validation failures
A422 names every field it rejected, with a JSON Pointer at the exact place:
name is a JSON Pointer for body fields and the plain name for a parameter;
location is body, path, query or header; reason is for a person and
code is for your code.
A field the API does not know is a 400, not a shrug:
The codes
400 — the request is wrong before anything is looked up
401 / 402 / 403 / 404 — who you are, what you may spend, what you may see
406 / 409 / 410 — the request is fine, the state is not
422 — semantically wrong
429 / 5xx
Rate limits
A rate-limited request answers429 rate_limited with a Retry-After header —
seconds, or an HTTP date. Wait that long; retrying sooner earns another 429.
The SDKs surface the wait as a number: e.retry_after in Python,
err.retryAfter in Node, APIError.RetryAfter in Go. All three retry GETs
automatically with backoff, and honor Retry-After when it is there.
Running out of allowance
There is a second kind of 429, and it is not about how fast you are calling. A plan holds two rolling windows — five hours and a week — and when one fills, the refusal carries the whole quota so you can show somebody exactly what happened:status is allowed, limited or unknown — unknown means the read failed
and carries no numbers, because rendering it as 0% would claim room nobody
verified. mode says what the next call would be funded by: plan, extra (the
wallet pays past a full window) or blocked. Retry-After on the response
carries the same wait as retry_after_seconds.
A window that fills while a run is already going does not produce an HTTP
error at all: the run stops and comes back failed, with the reason on it. This
one is real, from a run on the account these pages were written against:
usage_window_exceeded and out_of_funds are deliberately different codes. One
is fixed by waiting and the other by paying, and telling somebody with money in
their account to go to a checkout is both wrong and expensive.
What is safe to retry
POST /v2/runs/{id}/cancel carries no key and needs none: it is idempotent on the
server, and a run that is already terminal comes back unchanged.
In the SDKs
Problems arrive as typed errors carryingstatus, code, detail, trace_id
and the parsed body:

