Structured. Predictable. Useful.
Every error has a stable type, a human message, a request ID, and a link back here. What we never do: hide behind 500s, return HTML, or count failed upstream calls against your quota.
The envelope
Gateway-originated errors (auth, quota, upstream failure) all use this shape. Errors that originate upstream are forwarded with their original body untouched.
api.souslab.site
{
"error": {
"type": "quota_exceeded",
"message": "Monthly request limit reached. Upgrade your plan or wait until 2026-06-01.",
"request_id": "req_2y4Zp7H8...",
"docs_url": "https://souslab.site/docs/errors#quota_exceeded"
}
}● 200 OK · 38 ms
Status codes
| Status | Type | Meaning | Counts toward quota? |
|---|---|---|---|
| 400 | bad_request | Malformed query or path. Fix your call. | Yes |
| 401 | unauthenticated | Missing or malformed Authorization header. | No |
| 403 | key_revoked | The API key was revoked. | No |
| 429 | quota_exceeded | You hit the monthly cap. Reset is in the response body. | No |
| 502 | upstream_error | Upstream returned 5xx. We forwarded it; not your fault. | No |
| 503 | upstream_timeout | Upstream took >30s. Retry with backoff. | No |
When to retry
- 429: wait until
X-RateLimit-Reset. Don't hammer. Consider upgrading. - 502 / 503: exponential backoff. The failed call did not count against your quota.
- 4xx (other): fix the request. Retrying won't help.
- 5xx from us: safe to retry once. If it persists, ping hello@souslab.site with the
X-Request-Id.