Errors
Every non-2xx response is a JSON object with a single error field:
{ "error": "invalid token" }There is no error code, no nested detail object, and no variation between endpoints. The HTTP status carries the category; the error string is a human-readable explanation, intended for your logs rather than for pattern matching.
HTTP/1.1 404 Not FoundContent-Type: application/jsonX-Localeo-RateLimit-Remaining: 986{ "error": "release not found" }Status codes
| Status | Meaning | What to do |
|---|---|---|
400 | The request was malformed — an unparseable release ID, or list parameters that could not be read. | Fix the request. Retrying will not help. |
401 | Missing, malformed, unknown or revoked token. | Check the token. See Authentication. Note that retrying still consumes quota. |
404 | The release does not exist, is not published, or belongs to another project. | Treat all three as “not available to you” — they are deliberately indistinguishable. |
429 | Rate limit exceeded. | Wait Retry-After seconds. See Rate limits. |
500 | Something failed inside Localeo. | Retry after a short delay. If it persists, get in touch. |
Do not match on the message
The error strings are not a stable API. They may be reworded to be clearer without that being a breaking change. Branch on the status code; log the message.
// Goodif (res.status === 429) await sleep(Number(res.headers.get('retry-after')) * 1000)
// Fragileif (body.error === 'rate limit exceeded') /* ... */404 is deliberately ambiguous
An unpublished release and a nonexistent one produce identical responses, as does a release belonging to a different project. This is intentional: distinguishing them would let a caller probe for the existence of releases they cannot read.
The practical implication is that a 404 on a release you believe exists usually means it is still a draft.
Errors carry the usual headers
Rate-limit headers are present on 400, 401 and 404 responses too, so you can read your remaining quota even from a failure. That is worth logging, because failed requests consume quota.
The exception is 429, which carries Retry-After instead — see rate limits.