Reference
Errors
All error responses share the shape {"error":{"code","message"}}. Match on error.code, not on the message text — messages may change for clarity. Some errors add optional links: upgradeUrl and docsUrl.
Error shape
Every non-2xx response from /api/v1 carries a stable machine-readable code under error.code. Build your retry and alerting logic against that field.
Entitlement and quota errors are actionable. A 403 forbidden for a bookmaker your plan does not include carries error.upgradeUrl (the billing page on app.betspread.io) and error.docsUrl (this reference). The monthly-quota 429 rate_limit_exceeded carries error.upgradeUrl. Both fields are optional: other errors omit them, so treat them as hints and ignore unknown fields.
{
"error": {
"code": "forbidden",
"message": "No product-verified bookmaker entitlements available for this sport and transport",
"upgradeUrl": "https://app.betspread.io/dashboard/billing",
"docsUrl": "https://betspread.io/docs/errors#forbidden"
}
}Error codes
missing_api_key401No Authorization header and no X-Api-Key header was supplied.
invalid_api_key401Credential is rejected (unknown, expired, or revoked).
validation_failed400A query or path parameter failed validation (e.g. unknown sport, non-numeric eventId, limit out of range, duplicate bookmaker filter).
forbidden403Authenticated but no product-verified bookmaker entitlement for the requested sport and transport. The body adds upgradeUrl (billing page on app.betspread.io) and docsUrl (this entry); compare your plan's bookmakers there or request fewer bookmakers.
live_not_enabled403Caller requested transport=live but plan entitlement does not include the Live channel.
api_key_scope_denied403The API key is restricted and does not allow the requested product channel, bookmaker, or sport. Use an unrestricted key or create a key whose scope includes the requested REST/Live/History channel, sport, and bookmaker.
not_found404Well-formed numeric eventId, but the event does not exist or is not visible to your organization.
rate_limit_exceeded429Hourly rate limit or monthly REST quota exhausted. Use X-RateLimit-Reset and Retry-After before retrying. The monthly-quota variant adds upgradeUrl (billing page) for a higher quota.