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.
{"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://sendside.xyz/docs/errors#quota_exceeded"}}
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@sendside.xyz with the
X-Request-Id.
