Errors
Flow uses standard HTTP status codes and a consistent error envelope across every endpoint.
Error envelope
All non-2xx responses return an object with a single top-level key:
json
{
"error": {
"code": "invalid_api_key",
"message": "API key is invalid, revoked, or expired",
"details": { }
}
}Always branch on error.code rather than the English message. Messages may be refined over time; codes are stable.
Status codes
| Status | When |
|---|---|
| 200 OK | Successful response. |
| 400 Bad Request | Invalid parameters, bad JSON, malformed cursor. |
| 401 Unauthorized | Missing, invalid, revoked, or expired API key. |
| 404 Not Found | The resource doesn't exist. |
| 429 Too Many Requests | You've exceeded the per-minute or per-day rate limit. |
| 500 Internal Server Error | Unexpected server error. Safe to retry with backoff. |
| 503 Service Unavailable | Upstream dependency temporarily down. Retry with backoff. |
Error codes
| Code | Meaning |
|---|---|
missing_api_key | The X-API-Key header was not sent. |
invalid_api_key | The key is unknown, revoked, or past its expiration. |
rate_limit_exceeded | Either the per-minute or per-day quota has been hit. Check details.window. |
not_found | The addressed resource (league, contest, market, position) doesn't exist. |
invalid_status | A status filter was provided that isn't one of the accepted values. |
invalid_position_hash | The position_hash isn't a 6-part colon-separated string. |
internal_error | Unexpected server-side failure. Safe to retry. |
Retrying
Safe to retry: 429 (after Retry-After), 500, 503. Use exponential backoff with jitter.
Not safe to retry without changes: 400 and 404 — fix your input first.
Never retry: 401. A second attempt with the same bad key will fail the same way.