Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.
get_api_artifactsOne API's artifacts, grouped by type.
get_openapiThe primary OpenAPI for this API.
find_similar_apisAPIs that look like this one.
apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
resolveTurn a domain, URL or GitHub org into the provider it belongs to.
find_cohortsEvery scored population of providers in the catalog.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/sharpapi:sharpapi-streaming-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Sharp Streaming API
version: 3.28.0
description: Real-time sports betting odds API with +EV detection, arbitrage, middles, and low-hold opportunities.
contact:
name: SharpAPI Support
url: https://sharpapi.io
email: support@sharpapi.io
license:
name: Proprietary
url: https://sharpapi.io/terms
x-generated-at: '2026-10-13T20:02:34Z'
x-commit-sha: 850f5cb
servers:
- url: https://api.sharpapi.io/api/v1
description: Production
security:
- ApiKeyHeader: []
- BearerAuth: []
tags:
- name: Streaming
description: Real-time SSE streaming
paths:
/stream:
get:
operationId: stream
summary: Real-time SSE stream
description: 'Server-Sent Events stream for real-time odds and opportunity updates. Requires streaming access (WebSocket add-on, Enterprise tier, or active trial).
Use `api_key` query parameter for authentication since `EventSource` cannot set headers.
## Channels
| Channel | Description |
|---------|-------------|
| `opportunities` | EV, arbitrage, middles, low-hold updates (default) |
| `odds` | Raw odds changes |
| `all` | Both odds and opportunities |
| `gamestate` | Live game state updates (Game State add-on or Enterprise) |
## Event Types
| Event | Payload | Description |
|-------|---------|-------------|
| `connected` | `{filters, channels}` | Stream established |
| `snapshot` | Array of items | Initial data dump (one per type) |
| `snapshot:complete` | `{}` | All snapshots sent |
| `odds:update` | `Odds` | Odds changed |
| `odds:removed` | `{id, sportsbook}` | Selection removed |
| `ev:detected` | `{opportunities: EVOpportunity[], count, type}` | New or updated +EV opportunities |
| `ev:expired` | `{expired: id[], count, type}` | EV opportunities gone |
| `arb:detected` | `{opportunities: ArbitrageOpportunity[], count, type}` | New or updated arbitrage |
| `arb:expired` | `{expired: id[], count, type}` | Arbitrage gone |
| `middles:detected` | `{opportunities: MiddleOpportunity[], count, type}` | New or updated middles |
| `middles:expired` | `{expired: id[], count, type}` | Middles gone |
| `low_hold:detected` | `{opportunities: LowHoldOpportunity[], count, type}` | New or updated low-hold |
| `low_hold:expired` | `{expired: id[], count, type}` | Low-hold gone |
| `gamestate:snapshot` | `{sport, events}` | Initial game state |
| `gamestate:update` | `{sport, event_id, ...}` | Game state changed |
| `heartbeat` | `{ts}` | Keep-alive (every 30s) |
| `error` | `{message}` | Recoverable error |
A `:detected` event carries new opportunities **and** updated versions of ones already sent: since 2026-09-26, an opportunity whose content changes (price, EV%, fair probability, leg odds, `is_suspended`, `quality_tier`) is re-sent under the same `id`. Upsert by `id`, and treat only an `id` you have not seen as new.
Supports `Last-Event-ID` header for reconnection.'
tags:
- Streaming
security:
- ApiKeyQuery: []
- ApiKeyHeader: []
- BearerAuth: []
parameters:
- name: api_key
in: query
description: API key (for EventSource which cannot set headers)
schema:
type: string
- name: channel
in: query
description: Stream channel
schema:
type: string
enum:
- opportunities
- odds
- all
- gamestate
default: opportunities
- $ref: '#/components/parameters/sport'
- $ref: '#/components/parameters/league'
- $ref: '#/components/parameters/sportsbook'
- $ref: '#/components/parameters/market'
- $ref: '#/components/parameters/event_id'
- $ref: '#/components/parameters/is_live'
- $ref: '#/components/parameters/live'
- $ref: '#/components/parameters/min_ev'
- $ref: '#/components/parameters/min_profit'
- name: state
in: query
description: US state code for deep-link routing only; does not filter odds or return state-specific prices. Recognises the 50 US state codes plus dc. When a recognised code is set, deep_link values in odds events include ?state=XX. Omitted, empty, and unsupported codes all emit no ?state= — unlike the REST odds and single-redirect endpoints, the stream handshake does not reject an unsupported code, but emits filter_warning after connected — and the redirect endpoint then applies its own pa default.
schema:
type: string
responses:
'200':
description: SSE event stream
content:
text/event-stream:
schema:
type: string
description: Server-Sent Events stream. Each event has `event:` type, `data:` JSON payload, and `id:` for reconnection.
example: 'event: connected
data: {"filters":{"channel":"opportunities","sport":null},"session_id":"abc123"}
id: 1709993400000-1
event: ev:detected
data: {"id":"a1b2c3d4e5f67890","ev_percentage":4.2,"sportsbook":"draftkings","selection":"Los Angeles Lakers","market":"moneyline","sport":"basketball","league":"nba"}
id: 1709993400000-2
event: heartbeat
data: {"ts":1709993430000}
id: 1709993430000-3
'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
description: Streaming access required
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
error:
code: streaming_not_available
message: Streaming requires WebSocket add-on or Enterprise tier
docs: https://sharpapi.io/pricing
components:
parameters:
event_id:
name: event_id
in: query
description: 'Filter by event ID (comma-separated). `event_id` is the canonical name. The legacy spellings `event`, `events` and `event_ids` are still accepted, but a request that uses one is answered with `Deprecation: true` and `Warning: 299 - "filter alias(es) ... deprecated; use event_id"`. No `Sunset` date is sent. Send `event_id` to avoid those headers.'
schema:
type: string
min_ev:
name: min_ev
in: query
description: Minimum EV percentage
schema:
type: number
default: 0
is_live:
name: is_live
in: query
description: 'Filter by live status. `is_live` is the canonical name. The legacy spelling `live` is still accepted, but a request that uses it is answered with `Deprecation: true` and `Warning: 299 - "filter alias(es) live deprecated; use is_live"`. Send `is_live` to avoid those headers.'
schema:
type: boolean
sport:
name: sport
in: query
description: Filter by sport (comma-separated)
schema:
type: string
example: basketball
min_profit:
name: min_profit
in: query
description: Minimum profit percentage
schema:
type: number
default: 0.5
sportsbook:
name: sportsbook
in: query
description: 'Filter by sportsbook (comma-separated). **Intentionally not enumerated.** This one parameter definition is shared by eleven operations, and they do not accept the same set of values, so no single `enum` would be correct for all of them. Nine of them validate the value and answer `400 invalid_filter` for one they do not accept; the other two do not reject an unrecognised value at all — `/splits/history` returns no rows for it and `/stream` opens the stream. See `/sportsbooks` for the book roster. The clearest per-operation difference is the synthetic `consensus` value: it is meaningful only on `/splits`, and every other operation that validates this filter rejects it.'
schema:
type: string
example: draftkings,fanduel
market:
name: market
in: query
description: Filter by market type (comma-separated)
schema:
type: string
example: moneyline,point_spread
league:
name: league
in: query
description: Filter by league (comma-separated)
schema:
type: string
example: nba
live:
name: live
in: query
deprecated: true
description: 'Deprecated alias of `is_live`, still accepted and behaving identically. A request using it is answered with `Deprecation: true` and `Warning: 299 - "filter alias(es) live deprecated; use is_live"`. No `Sunset` date is sent. Prefer `is_live`.'
schema:
type: boolean
schemas:
ErrorResponse:
type: object
required:
- error
properties:
error:
type: object
required:
- code
- message
properties:
code:
type: string
enum:
- missing_api_key
- invalid_api_key
- unauthorized
- forbidden
- tier_restricted
- rate_limited
- invalid_request
- validation_error
- not_found
- streaming_not_available
- stream_limit_exceeded
- service_unavailable
- internal_error
description: Machine-readable error code
message:
type: string
description: Human-readable error message
docs:
type: string
format: uri
description: Link to relevant documentation
tier:
type: string
description: Current subscription tier
required_tier:
type: string
description: Minimum tier required for this feature
retry_after:
type: integer
description: Unix timestamp (ms) when request can be retried
retryAfter:
type: integer
description: Seconds until the request can be retried — same instant as retry_after, different unit and casing
max_books:
type: integer
requested_books:
type: integer
responses:
Unauthorized:
description: Missing or invalid API key
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
missing:
summary: Missing API key
value:
error:
code: missing_api_key
message: API key required
docs: https://docs.sharpapi.io/en/authentication#authentication-methods
invalid:
summary: Invalid API key
value:
error:
code: invalid_api_key
message: Invalid API key
docs: https://docs.sharpapi.io/en/authentication#authentication-methods
securitySchemes:
ApiKeyHeader:
type: apiKey
in: header
name: X-API-Key
description: API key passed in the `X-API-Key` header
BearerAuth:
type: http
scheme: bearer
description: API key passed as a Bearer token in the `Authorization` header
ApiKeyQuery:
type: apiKey
in: query
name: api_key
description: API key as query parameter (for SSE/EventSource only)