Errores 4xx comunes
Cuatro errores de uso del lado del cliente concentran la mayoría de las respuestas 4xx/410 recurrentes que devuelve SharpAPI. Cada cuerpo de error ya nombra su corrección. Esta página las reúne en un solo lugar para que puedas pasar del código de estado a la corrección sin abrir un ticket de soporte.
Son errores del lado del cliente, no caídas del servicio. El envelope general de errores (campos, significado de los códigos de estado, lista completa de códigos) está en Convenciones de respuesta. Ramifica siempre sobre error.code, no sobre el texto de message.
offset por encima de 500 → 400 offset_too_large
La paginación profunda con offset está limitada a 500 en /api/v1/odds y /api/v1/odds/delta. Un escaneo completo con ordenación cuesta lo mismo sin importar la profundidad del offset, así que el límite evita cadenas de páginas costosas.
{
"error": {
"code": "offset_too_large",
"message": "offset must be <= 500; use cursor= from the previous response for deeper pagination",
"max_offset": 500
}
}Solución: no pagines más allá de offset=500. Para llegar a más filas, o bien
- pasa el valor
cursor=de la respuesta anterior de/odds(paginación keyset, sin límite de offset), o - acota la petición para que cada conjunto de resultados quepa bajo el límite: añade
league=, un filtro de fecha oevent=, o un únicomarket_type=.
En /odds/delta, avanza since= al updated_at de la respuesta anterior en lugar de aumentar offset.
Rutas de opportunities sin namespace → 410 Gone
Cada tipo de opportunity vive bajo /api/v1/opportunities/. Las rutas abreviadas (/api/v1/ev, /api/v1/arbitrage, /api/v1/middles, /api/v1/low_hold) devuelven 410 Gone y nombran su reemplazo:
{
"error": {
"code": "unknown_endpoint",
"message": "There is no /api/v1/ev endpoint. Use GET /api/v1/opportunities/ev (Pro tier or higher).",
"correct_endpoint": "/api/v1/opportunities/ev",
"docs": "https://docs.sharpapi.io/api-reference"
}
}Solución: usa la ruta con namespace de correct_endpoint.
| Lo que enviaste | Usa en su lugar |
|---|---|
/api/v1/ev | /api/v1/opportunities/ev (Pro+) |
/api/v1/arbitrage | /api/v1/opportunities/arbitrage (Hobby+) |
/api/v1/middles | /api/v1/opportunities/middles (Pro+) |
/api/v1/low_hold | /api/v1/opportunities/low-hold |
Streaming en la raíz de la API → 400
El streaming en tiempo real no se sirve desde la raíz de la API (https://api.sharpapi.io/). Una petición a la raíz con intención de streaming, es decir con un parámetro channels=/channel= o una cabecera Upgrade de WebSocket, se responde con un puntero a los endpoints reales en lugar del redirect a la documentación que recibe una visita simple a la raíz:
{
"error": {
"code": "validation_error",
"message": "Streaming is not available on the API root. Use Server-Sent Events at GET /api/v1/stream, or WebSocket at wss://ws.sharpapi.io — both require the WebSocket add-on. Channels: odds, opportunities, gamestate.",
"stream_endpoints": {
"sse": "https://api.sharpapi.io/api/v1/stream",
"websocket": "wss://ws.sharpapi.io"
},
"docs": "https://docs.sharpapi.io/api-reference"
}
}Solución: elige un transporte:
- Server-Sent Events:
GET https://api.sharpapi.io/api/v1/stream, consulta Flujo SSE. - WebSocket:
wss://ws.sharpapi.io, consulta Flujo WebSocket.
Ambos requieren el add-on de WebSocket (o un trial de streaming activo / Enterprise).
Slug de filtro desconocido → 400 invalid_filter
?league=, ?sport=, ?sportsbook= y ?market= se validan contra el registro vivo. Un valor desconocido devuelve 400 invalid_filter en lugar de coincidir silenciosamente con cero filas, de modo que una errata aparece como bug del cliente, no como “sin datos”. El cuerpo siempre apunta al endpoint que lista los valores válidos y añade una sugerencia did_you_mean cuando el valor se acerca a un slug real:
{
"error": {
"code": "invalid_filter",
"message": "invalid filter values: league=[norway_2nd_div]; see GET /api/v1/leagues for valid values",
"details": {
"fields": { "league": ["norway_2nd_div"] },
"reference": { "league": "/api/v1/leagues" },
"did_you_mean": [
{ "field": "league", "value": "norway_2nd_div", "try": { "league": "norway_-_second_division" } }
]
}
}
}Solución: obtén el conjunto válido del endpoint de referencia indicado en details.reference y filtra con un slug exacto:
| Campo rechazado | Valores válidos en |
|---|---|
league | GET /api/v1/leagues |
sport | GET /api/v1/sports |
sportsbook | GET /api/v1/sportsbooks |
market | GET /api/v1/markets |
details.fields y did_you_mean son la vía legible por máquina. Basa el comportamiento del SDK en esos campos, no en el texto de message.