Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions content/en/api-reference/common-4xx-errors.mdx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
description: "The four most common 4xx/410 mistakes against the SharpAPI REST API — offset over the pagination cap, pre-namespace opportunity paths, streaming on the API root, and unknown filter slugs — with the exact fix for each."
description: "The most common 4xx/410 mistakes against the SharpAPI REST API — offset over the pagination cap, market= vs market_type= confusion, market-segment slug passed as league, pre-namespace opportunity paths, streaming on the API root, and unknown filter slugs — with the exact fix for each."
---

import { Callout } from 'nextra/components'

# Common 4xx Mistakes

Four client-side usage mistakes account for most of the recurring 4xx/410 responses SharpAPI returns. Each error body already names the fix — this page collects them in one place so you can map a status code to the correction without opening a support ticket.
Six client-side usage mistakes account for most of the recurring 4xx/410 responses SharpAPI returns. Each error body already names the fix — this page collects them in one place so you can map a status code to the correction without opening a support ticket.

<Callout type="info">
These are **client-side** errors, not outages. The general error envelope (fields, status-code meanings, the full code list) lives in [Response Conventions](/en/api-reference/conventions/). Always branch on `error.code`, not the prose `message`.
Expand All @@ -33,6 +33,38 @@ Deep pagination with `offset` is capped at **500** on [`/api/v1/odds`](/en/api-r

On `/odds/delta`, advance `since=` to the previous response's `updated_at` instead of increasing `offset`.

## `market=` vs `market_type=` confusion → `400 invalid_filter`

The response field that names the market is called `market_type` (e.g. `"market_type": "moneyline"`). The **query parameter** is `market=` — the two names differ by design, because the filter also accepts category aliases that expand to multiple types. Sending `?market_type=moneyline` works (it is accepted as an alias for `market=`), but the common mistake is passing the full exact-type name when a category alias was intended, or vice versa.

| What you want | Correct param |
|---|---|
| All moneylines | `?market=moneyline` |
| All spreads (point spread, puck line, run line, set handicap) | `?market=spread` |
| All totals | `?market=total` |
| All player props | `?market=props` |
| Exact type from response | `?market=<market_type value>` (e.g. `market=point_spread`) |

`market=` and `market_type=` are interchangeable on the query string — both reach the same filter. Category aliases (`main`, `spread`, `total`, `props`) expand to a group of types; everything else is treated as an exact type match and validated against the market registry. A value that matches neither an alias nor a registry slug returns `400 invalid_filter` with a `did_you_mean` hint.

## League slug passed as `league=` when it is a market segment → `400 invalid_filter`

League slugs (e.g. `nfl`, `nba`, `mlb`) and market-segment slugs (e.g. `nfl_1st_quarter_spreads`, `nba_player_points`) look similar but belong to different filter parameters. Passing a market-segment slug as a league value returns `400 invalid_filter` because it is not a valid league:

```json
{
"error": {
"code": "invalid_filter",
"message": "invalid filter values: league=[nfl_1st_quarter_spreads]; see GET /api/v1/leagues for valid values",
"details": {
"fields": { "league": ["nfl_1st_quarter_spreads"] }
}
}
}
```

**Fix:** use `market_segment=nfl_1st_quarter_spreads` (or `market=<type>`) for market filtering, and `league=nfl` for league filtering. Fetch valid league slugs from [`GET /api/v1/leagues`](/en/api-reference/leagues/) and valid market-segment slugs from [`GET /api/v1/markets`](/en/api-reference/markets/).

## Pre-namespace opportunity paths → `410 Gone`

Every opportunity type lives under `/api/v1/opportunities/`. The bare shorthand paths (`/api/v1/ev`, `/api/v1/arbitrage`, `/api/v1/middles`, `/api/v1/low_hold`) return **410 Gone** and name their replacement:
Expand Down
10 changes: 9 additions & 1 deletion content/en/api-reference/odds.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ The sportsbooks returned in your results depend on your subscription tier. Free
| `sportsbook` | string | tier-allowed | Comma-separated sportsbook IDs (e.g., `draftkings,fanduel`). Tier limits enforced. |
| `sport` | string | all | Filter by sport(s), comma-separated (e.g., `basketball`, `football`). Supports category aliases. |
| `league` | string | all | Filter by league(s), comma-separated (e.g., `nba`, `nfl`, `nhl`) |
| `market` | string | all | Filter by market type(s), comma-separated. Supports [category aliases](#market-category-aliases) (`main`, `spread`, `total`, `props`) or exact types (`point_spread`, `player_points`). Also accepted as `market_type=` (mirrors the response field name). |
| `market` | string | all | Filter by market type(s), comma-separated. Accepts [category aliases](#market-category-aliases) (`main`, `spread`, `total`, `props`) **or** exact type names as they appear in the `market_type` response field (e.g., `moneyline`, `point_spread`, `player_points`). Also accepted as `market_type=`. |
| `event_id` | string | — | Filter by event ID(s), comma-separated |
| `is_live` | boolean | — | `true` = live only, `false` = prematch only, omit = both |
| `group_by` | string | — | Group results by field (e.g., `event`) |
Expand All @@ -44,6 +44,14 @@ The sportsbooks returned in your results depend on your subscription tier. Free
Use comma-separated values to filter by multiple sportsbooks: `sportsbook=draftkings,fanduel,betmgm`
</Callout>

<Callout type="warning">
**`market=` vs `market_type` — don't confuse the filter name with the response field name.** The response object contains a field called `market_type` (e.g. `"market_type": "moneyline"`). The query parameter is `market=` — which also accepts `market_type=` as an alias. Both `?market=moneyline` and `?market_type=moneyline` work and are equivalent. Passing an unrecognized value returns `400 invalid_filter`. See [Common 4xx Mistakes](/en/api-reference/common-4xx-errors/) for the full error shape.
</Callout>

<Callout type="warning">
**`league=` takes league slugs, not market-segment slugs.** League slugs look like `nfl`, `nba`, `mlb`. Market-segment slugs like `nfl_1st_quarter_spreads` belong on the `market_segment=` filter, not `league=`. Mixing them returns `400 invalid_filter`. Fetch valid league slugs from [`GET /api/v1/leagues`](/en/api-reference/leagues/).
</Callout>

### Market Category Aliases

Instead of listing individual market types, you can use a category alias to match a group of related markets. Aliases and exact types can be mixed freely in a comma-separated list.
Expand Down