Skip to Content
API ReferenceOverview

API Reference Overview

Complete reference for the SharpAPI v1 REST API. All endpoints return JSON and follow consistent conventions for authentication, filtering, pagination, and error handling.

Base URLPermalink for this section

https://api.sharpapi.io/api/v1

Always use api.sharpapi.io as the base URL, not sharpapi.io.

OpenAPI SpecificationPermalink for this section

The full OpenAPI 3.1 spec is available for import into tools like Postman, Insomnia, or code generators:

This spec covers all endpoints, request/response schemas, and authentication requirements.

Request FormatPermalink for this section

  • All requests use HTTPS
  • Authentication via X-API-Key header, Authorization: Bearer header, or api_key query param
  • Request bodies (where applicable) use JSON with Content-Type: application/json
  • All field names are snake_case

Endpoint SummaryPermalink for this section

SharpAPI exposes 35 routes across 7 namespaces plus reference and health endpoints.

OddsPermalink for this section

MethodPathAuthMin Tier
GET/api/v1/oddsYesFree
GET/api/v1/odds/deltaYesFree
GET/api/v1/odds/bestYesFree
GET/api/v1/odds/comparisonYesFree
POST/api/v1/odds/batchYesFree

EventsPermalink for this section

MethodPathAuthMin Tier
GET/api/v1/eventsYesFree
GET/api/v1/events/:eventIdYesFree
GET/api/v1/events/:eventId/oddsYesFree
GET/api/v1/events/:eventId/marketsYesFree

OpportunitiesPermalink for this section

MethodPathAuthMin Tier
GET/api/v1/opportunities/evYesPro
GET/api/v1/opportunities/arbitrageYesHobby
GET/api/v1/opportunities/middlesYesPro

SplitsPermalink for this section

MethodPathAuthMin Tier
GET/api/v1/splitsYesPro
GET/api/v1/splits/historyYesPro

StreamingPermalink for this section

MethodPathAuthMin Tier
GET/api/v1/streamYesAdd-on

AccountPermalink for this section

MethodPathAuthMin Tier
GET/api/v1/accountYesFree
GET/api/v1/account/usageYesFree
GET/api/v1/account/keysYesFree
POST/api/v1/account/keysYesFree
DELETE/api/v1/account/keys/:keyIdYesFree
POST/api/v1/account/keys/:keyId/rotateYesFree

Reference Data (Public)Permalink for this section

MethodPathAuthMin Tier
GET/api/v1/sportsNo-
GET/api/v1/leaguesNo-
GET/api/v1/sportsbooksNo-
GET/api/v1/marketsNo-
GET/api/v1/teamsNo-

EnterprisePermalink for this section

MethodPathAuthMin Tier
GET/api/v1/futuresYesEnterprise
GET/api/v1/futures/oddsYesEnterprise

HealthPermalink for this section

MethodPathAuthMin Tier
GET/api/v1/healthNo-

Response FormatPermalink for this section

Two top-level shapes — both put data first and updated_at last, with an optional pagination block in between. There is no success field; the HTTP status code is the source of truth. See Response Conventions for the full rule set.

Paginated list responsePermalink for this section

{ "data": [ { "id": "draftkings_33483153_moneyline_PHO", "sportsbook": "draftkings", "sport": "basketball", "home_team": "PHI 76ers", "away_team": "PHO Suns", "market_type": "moneyline", "selection": "PHO Suns", "odds_american": -150, "odds_decimal": 1.667, "odds_probability": 0.60, "is_live": false } ], "pagination": { "limit": 50, "offset": 0, "count": 1, "total": 3095, "has_more": true, "next_offset": 50, "next_cursor": "eyJlIjoiMzM0ODMxNTMiLCJiIjoiZHJhZnRraW5ncyIsIm0iOiJtb25leWxpbmUiLCJpIjoiZHJhZnRraW5nc18zMzQ4MzE1M19tb25leWxpbmVfUEhJIn0" }, "updated_at": "2026-01-26T02:10:37.846Z" }
FieldDescription
dataArray of results
pagination.limitMaximum items per page (default: 50, max: 200)
pagination.offsetCurrent offset into results
pagination.countNumber of items returned in this response
pagination.totalTotal matching items across all pages. Omitted on endpoints that can’t compute it cheaply (e.g. /odds).
pagination.has_moreWhether more results exist beyond this page
pagination.next_offsetOffset value to use for the next page. Prefer next_cursor on live-data endpoints.
pagination.next_cursorOpaque cursor for the next page. Pass as ?cursor= — stable against live data changes. Recommended for multi-page scans. Present only on cursor-supporting endpoints (/odds, /odds/delta).
updated_atISO 8601 timestamp of when the data was last refreshed

Single resource responsePermalink for this section

Used for singletons (/account, /events/:eventId) and non-paginated reference endpoints. No pagination block.

{ "data": { "id": "nba_celtics_lakers_2026-02-08_b3", "sport": "nba", "home_team": "PHI 76ers", "away_team": "PHO Suns", "start_time": "2026-01-26T19:00:00Z" }, "updated_at": "2026-01-26T02:10:37.846Z" }

Error EnvelopePermalink for this section

All errors follow a consistent format:

{ "error": { "code": "rate_limited", "message": "Rate limit exceeded. Upgrade your plan or wait 45 seconds.", "docs": "https://docs.sharpapi.io/en/authentication#rate-limits" } }
FieldDescription
error.codeMachine-readable error code
error.messageHuman-readable description
error.docsLink to relevant documentation (optional — included on auth, tier, rate limit, and streaming errors)
error.correct_endpointThe correct endpoint to use (optional — included on unknown_endpoint errors when the API recognizes the path as a known wrong route)
error.retry_afterSeconds until retry is allowed (optional — included on rate_limited errors)

Standard Response HeadersPermalink for this section

Every API response includes these headers:

HeaderExampleDescription
X-RateLimit-Limit300Maximum requests per minute for your tier
X-RateLimit-Remaining299Requests remaining in the current window
X-RateLimit-Reset1705804800Unix timestamp when the rate limit resets
X-Data-Delay0Data delay in seconds (60 for Free, 0 for paid tiers)
X-Request-Idreq_a1b2c3d4Unique request identifier for debugging and support
X-Cache-StatusHITEdge-cache state for this response (HIT, MISS, STALE, BYPASS). STALE means the edge briefly served slightly outdated content while revalidating against the origin — expected during transient origin slowness, not an error
Alt-Svch3=":443"; ma=86400Indicates HTTP/3 (QUIC) is available on this host. Clients that opt in skip the TCP + TLS handshake on subsequent connections — see Connection Reuse below

Include the X-Request-Id value when contacting support about a specific request.

Connection ReusePermalink for this section

For polling clients, the dominant cost on a fresh connection to api.sharpapi.io is the TLS handshake — typically 150–200 ms — not the API server itself, which returns in ~40–50 ms once TCP + TLS are up. Reusing a single TLS connection across requests collapses subsequent calls to roughly the server-side TTFB.

# Fresh connection — first request pays full TCP + TLS: curl -o /dev/null -s \ -w "ssl=%{time_appconnect}s ttfb=%{time_starttransfer}s total=%{time_total}s\n" \ -H "X-API-Key: $SHARPAPI_KEY" \ https://api.sharpapi.io/api/v1/gamestate/baseball # → ssl=0.16s ttfb=0.20s total=0.20s # Two URLs in one curl call — the second reuses the open connection: curl -o /dev/null -s \ -w "ssl=%{time_appconnect}s ttfb=%{time_starttransfer}s total=%{time_total}s\n" \ -H "X-API-Key: $SHARPAPI_KEY" \ https://api.sharpapi.io/api/v1/gamestate/baseball \ https://api.sharpapi.io/api/v1/gamestate/tennis # → ssl=0.00s ttfb=0.04s total=0.04s

RecommendationsPermalink for this section

  • HTTP/1.1 keep-alive is the default in curl, Python httpx / requests.Session(), aiohttp, Node fetch / axios / undici, Go http.Client, OkHttp, and most other modern clients. Reuse a single client/session across calls — don’t construct a new client per request.
  • HTTP/2 connection coalescing multiplexes many concurrent requests over one connection to the same host. Enabled by default in HTTP/2-capable clients.
  • HTTP/3 (QUIC) is offered via Alt-Svc: h3=":443". Clients that opt in (curl --http3, httpx[http2,http3], Node undici with allowH2: true) skip the TCP handshake entirely on subsequent connections. Worthwhile for cold-start workloads such as serverless functions.
  • For real-time data, use streaming. The /api/v1/stream endpoint keeps a single connection open and pushes deltas as they happen — no per-request handshake at all.

For a polling client hitting /api/v1/odds once per second, the TLS cost amortizes to ~0 after the first request. The 150 ms handshake matters most for serverless / short-lived clients that close the connection between calls.

Tier ComparisonPermalink for this section

FeatureFreeHobbyProSharpEnterprise
Sportsbooks2 (DK, FD)515All 32All 32
Data Delay60s0s0s0s0s
Requests/min121203001,000Custom
PinnacleNoNoYesYesYes
EV / Arb / MiddlesNoNoYesYesYes
StreamingNoAdd-onAdd-onAdd-onIncluded
Batch max events10105050100

Streaming requires the WebSocket add-on ($99/mo) on paid tiers. Enterprise includes streaming at no extra cost.

FilteringPermalink for this section

All list endpoints support filtering via query parameters. Filters use singular parameter names and accept comma-separated values for multi-select.

Filter ParametersPermalink for this section

ParameterTypeExampleDescription
sportsbookstringdraftkings,fanduelFilter by one or more sportsbooks
sportstringbasketball,footballFilter by sport
leaguestringnba,nflFilter by league
marketstringmoneyline,spreadFilter by market type
eventstringnba_celtics_lakers_2026-02-08_b3Filter by event ID
livebooleantrueOnly live/in-progress events
sortstring-odds_americanSort field with optional - prefix for descending
fieldsstringid,sportsbook,odds_americanComma-separated fields to include in response
min_oddsnumber-110Minimum American odds filter
max_oddsnumber200Maximum American odds filter
group_bystringeventGroup results by field
limitnumber25Results per page (default: 50, max: 200)
offsetnumber50Pagination offset. May produce duplicate rows on live endpoints when data changes between requests.
cursorstringOpaque cursor from next_cursor. Recommended for multi-page scans over live data — eliminates offset drift.

ExamplesPermalink for this section

# Multiple sportsbooks (comma-separated) curl "https://api.sharpapi.io/api/v1/odds?sportsbook=draftkings,fanduel" \ -H "X-API-Key: YOUR_KEY" # Combine filters curl "https://api.sharpapi.io/api/v1/odds?league=nba,nhl&sportsbook=pinnacle&live=true" \ -H "X-API-Key: YOUR_KEY" # Paginate through results curl "https://api.sharpapi.io/api/v1/odds?limit=25&offset=50" \ -H "X-API-Key: YOUR_KEY"

Parameter names are always singular (sportsbook, not sportsbooks). Use commas to pass multiple values: sportsbook=draftkings,fanduel.

Odds FormatsPermalink for this section

All odds are returned as flat fields on each odds object:

{ "odds_american": -110, "odds_decimal": 1.909, "odds_probability": 0.5238 }
FieldExampleDescription
odds_american-110, +150Standard US format
odds_decimal1.909, 2.50Multiplier format
odds_probability0.5238Implied probability (0 to 1)

Error CodesPermalink for this section

The canonical list of error codes emitted by the API. The string in error.code is the stable contract — check it rather than the prose message.

HTTP error codesPermalink for this section

Emitted in REST responses.

CodeHTTP StatusDescription
missing_api_key401No API key supplied via X-API-Key, ?api_key=, or Authorization: Bearer
invalid_api_key401API key was supplied but is not recognized
expired_api_key401API key has expired — generate a new one in the dashboard
disabled_api_key401API key is disabled, usually because the subscription lapsed
unauthorized401Bearer-token auth failed on admin or /api/v1/monitoring/* endpoints (distinct from invalid_api_key)
invalid_token401Clerk session token failed verification (dashboard-only endpoints)
tier_restricted403Endpoint or feature is not available on your tier — response includes tier and required_tier
not_found404Resource not found
method_not_allowed405HTTP method is not supported on this route
gone410Event has ended or expired — use /api/v1/events for current events
unknown_endpoint410Wrong API path — response includes correct_endpoint with the right route (e.g. /api/v1/arbitrage/api/v1/opportunities/arbitrage)
validation_error400Request body or query parameters failed validation
offset_too_large400offset exceeds the per-endpoint maximum (currently 500 on /odds and /odds/delta). Switch to cursor-based pagination or advance since
rate_limited429Per-minute request rate limit exceeded — response includes retry_after
concurrent_request_cap429Too many in-flight requests for your tier — reduce parallelism or upgrade
too_many_streams429Maximum concurrent SSE or WebSocket streams exceeded for this API key
backpressureEmitted as an SSE event: error (not an HTTP status) when the client cannot keep up; server then closes the stream
upstream_error502Temporary issue reaching an upstream sportsbook or auth provider
service_unavailable503A required service (e.g. key management) is not configured or is offline
not_ready503A backing store the endpoint depends on (e.g. ClickHouse, closing-line capture) is not yet ready to serve the request. Retry with backoff
internal_error500Unexpected server error — retry with backoff and contact support with X-Request-Id if it persists

bad_request and invalid_request are deprecated — both were collapsed into validation_error. Clients that match on the old strings should add validation_error to their error map.

WebSocket frame error codesPermalink for this section

Emitted only inside {"type": "error", "code": "..."} frames on an open WebSocket connection. They describe client-protocol mistakes and do not correspond to an HTTP status.

CodeMeaning
invalid_messageFrame could not be parsed as JSON or did not match the expected shape
unknown_message_typetype field is not one of the documented values (auth, subscribe, filter, refresh_token, ping)
missing_tokenauth or refresh_token frame did not include a token field
missing_channelssubscribe frame did not include a non-empty channels array
not_authenticatedFrame requires an authenticated session (sent subscribe, filter, or refresh_token before auth)
already_authenticatedClient sent a second auth frame after the first one succeeded
Last updated on