Skip to content
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ to bump. Every change to API paths or response schemas gets a one-line entry her
the [OpenAPI Version Check](.github/workflows/openapi-version-check.yml) CI job
enforces that a bump has a matching entry.

## 3.1.0 — 2026-06-02

- Add `player_id` to the `EVOpportunity` schema (`/opportunities/ev`) — the canonical cross-book player identifier resolved by atlas_players (e.g. `baseball_mlb_corbin_carroll`). Nullable and always present alongside `player_name`; `null` until the producer flips a book to active player-id capture. Consumers should group player props on `player_id` and fall back to `player_name`. Additive, backward-compatible. sharp-api-go #213.

## 3.0.0 — 2026-06-02

- **BREAKING:** the `Odds` response now exposes a single per-odd `timestamp` field and no longer emits `odds_changed_at`, `last_seen_at`, or `wire_received_at`. `timestamp` is the **delivery / last-refreshed** stamp (advances every ingest cycle — a feed-freshness/liveness signal, matching OpticOdds' `timestamp`), **not** a price-last-changed time. **Migration:** anyone reading `odds_changed_at` / `last_seen_at` / `wire_received_at` should read `timestamp`. Note there is no longer a field for *when the price last moved* (CLV / line-movement) — full OpticOdds-parity. Supersedes the 2.3.0 deprecations. SHA-1048.
Expand Down
3 changes: 3 additions & 0 deletions content/de/api-reference/opportunities-ev.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ for opp in data['data']:
"arb_profit": null,
"is_player_prop": false,
"player_name": null,
"player_id": null,
"stat_category": null,
"possibly_stale": false,
"oldest_odds_age_seconds": null,
Expand Down Expand Up @@ -182,6 +183,7 @@ for opp in data['data']:
"arb_profit": null,
"is_player_prop": false,
"player_name": null,
"player_id": null,
"stat_category": null,
"possibly_stale": false,
"oldest_odds_age_seconds": null,
Expand Down Expand Up @@ -312,6 +314,7 @@ X-Request-Id: req_abc123def456
| `arb_profit` | number\|null | Arbitrage-Gewinnprozentsatz, falls verfügbar |
| `is_player_prop` | boolean | Ob es sich um einen Player-Prop-Markt handelt |
| `player_name` | string\|null | Spielername (bei Player Props) |
| `player_id` | string\|null | Kanonische buchübergreifende Spieler-ID (z. B. `baseball_mlb_corbin_carroll`), von atlas_players aufgelöst. `null` bis aufgelöst — Player Props nach `player_id` gruppieren, Fallback auf `player_name`. |
| `stat_category` | string\|null | Statistiktyp (bei Player Props, z. B. `points`, `rebounds`) |
| `possibly_stale` | boolean | `true`, wenn sich die zugrundeliegenden Quoten seit der Erkennung möglicherweise verändert haben |
| `oldest_odds_age_seconds` | number\|null | Alter der ältesten in der EV-Berechnung verwendeten Quoten (in Sekunden) |
Expand Down
3 changes: 3 additions & 0 deletions content/en/api-reference/opportunities-ev.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ for opp in data['data']:
"arb_profit": null,
"is_player_prop": false,
"player_name": null,
"player_id": null,
"stat_category": null,
"possibly_stale": false,
"oldest_odds_age_seconds": null,
Expand Down Expand Up @@ -182,6 +183,7 @@ for opp in data['data']:
"arb_profit": null,
"is_player_prop": false,
"player_name": null,
"player_id": null,
"stat_category": null,
"possibly_stale": false,
"oldest_odds_age_seconds": null,
Expand Down Expand Up @@ -312,6 +314,7 @@ X-Request-Id: req_abc123def456
| `arb_profit` | number\|null | Arbitrage profit percentage if available |
| `is_player_prop` | boolean | Whether this is a player prop market |
| `player_name` | string\|null | Player name (if player prop) |
| `player_id` | string\|null | Canonical cross-book player ID (e.g. `baseball_mlb_corbin_carroll`), resolved by atlas_players. `null` until resolved — group player props on `player_id` and fall back to `player_name`. |
| `stat_category` | string\|null | Stat type (if player prop, e.g., `points`, `rebounds`) |
| `possibly_stale` | boolean | `true` if underlying odds may have moved since detection |
| `oldest_odds_age_seconds` | number\|null | Age of the stalest odds used in the EV calculation (seconds) |
Expand Down
3 changes: 3 additions & 0 deletions content/es/api-reference/opportunities-ev.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ for opp in data['data']:
"arb_profit": null,
"is_player_prop": false,
"player_name": null,
"player_id": null,
"stat_category": null,
"possibly_stale": false,
"oldest_odds_age_seconds": null,
Expand Down Expand Up @@ -182,6 +183,7 @@ for opp in data['data']:
"arb_profit": null,
"is_player_prop": false,
"player_name": null,
"player_id": null,
"stat_category": null,
"possibly_stale": false,
"oldest_odds_age_seconds": null,
Expand Down Expand Up @@ -312,6 +314,7 @@ X-Request-Id: req_abc123def456
| `arb_profit` | number\|null | Porcentaje de beneficio del arbitraje, si está disponible |
| `is_player_prop` | boolean | Indica si se trata de un mercado de player prop |
| `player_name` | string\|null | Nombre del jugador (si es un player prop) |
| `player_id` | string\|null | Identificador canónico del jugador entre casas (p. ej. `baseball_mlb_corbin_carroll`), resuelto por atlas_players. `null` hasta resolverse — agrupa los player props por `player_id` con respaldo en `player_name`. |
| `stat_category` | string\|null | Tipo de estadística (si es un player prop, p. ej. `points`, `rebounds`) |
| `possibly_stale` | boolean | `true` si las cuotas subyacentes pueden haberse movido desde la detección |
| `oldest_odds_age_seconds` | number\|null | Antigüedad de las cuotas más obsoletas utilizadas en el cálculo de EV (segundos) |
Expand Down
3 changes: 3 additions & 0 deletions content/pt-BR/api-reference/opportunities-ev.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ for opp in data['data']:
"arb_profit": null,
"is_player_prop": false,
"player_name": null,
"player_id": null,
"stat_category": null,
"possibly_stale": false,
"oldest_odds_age_seconds": null,
Expand Down Expand Up @@ -182,6 +183,7 @@ for opp in data['data']:
"arb_profit": null,
"is_player_prop": false,
"player_name": null,
"player_id": null,
"stat_category": null,
"possibly_stale": false,
"oldest_odds_age_seconds": null,
Expand Down Expand Up @@ -312,6 +314,7 @@ X-Request-Id: req_abc123def456
| `arb_profit` | number\|null | Porcentagem de lucro de arbitragem, se disponível |
| `is_player_prop` | boolean | Se este é um mercado de player prop |
| `player_name` | string\|null | Nome do jogador (se player prop) |
| `player_id` | string\|null | Identificador canônico do jogador entre casas (ex.: `baseball_mlb_corbin_carroll`), resolvido pelo atlas_players. `null` até ser resolvido — agrupe os player props por `player_id` com fallback para `player_name`. |
| `stat_category` | string\|null | Tipo de estatística (se player prop, ex.: `points`, `rebounds`) |
| `possibly_stale` | boolean | `true` se as odds subjacentes podem ter se movido desde a detecção |
| `oldest_odds_age_seconds` | number\|null | Idade das odds mais antigas usadas no cálculo de EV (segundos) |
Expand Down
9 changes: 8 additions & 1 deletion public/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"openapi": "3.1.0",
"info": {
"title": "SharpAPI",
"version": "3.0.0",
"version": "3.1.0",
"description": "Real-time sports betting odds API with +EV detection, arbitrage, middles, and low-hold opportunities.\n\n## Spec Versioning\n\n`info.version` is bumped on every schema or path change. Minor version (`2.x.0`) for additive changes or breaking shape fixes that align the spec to the live response; major version (`x.0.0`) for backward-incompatible redesigns. Removed paths and renamed fields always bump the minor at minimum. Check `x-generated-at` and `x-commit-sha` for the build provenance of a given snapshot.\n\n## Authentication\n\nAll authenticated endpoints accept an API key via one of three methods:\n\n| Method | Header / Param | Use case |\n|--------|---------------|----------|\n| `X-API-Key` | `X-API-Key: sk_live_...` | Recommended for server-side |\n| `Authorization` | `Authorization: Bearer sk_live_...` | Standard Bearer token |\n| `api_key` query | `?api_key=sk_live_...` | SSE/EventSource (cannot set headers) |\n\n## Subscription Tiers\n\n| Tier | Rate Limit | Data Delay | Max Books | EV | Arb | Middles | Game State |\n|------|-----------|------------|-----------|-----|-----|---------|------------|\n| Free | 12/min | 60s | 2 (DK, FD) | - | - | - | - |\n| Hobby | 120/min | Real-time | 5 | - | Yes | - | - |\n| Pro | 300/min | Real-time | 15 | Yes | Yes | Yes | - |\n| Sharp | 1000/min | Real-time | All | Yes | Yes | Yes | - |\n| Enterprise | Custom | Real-time | All | Yes | Yes | Yes | Yes |\n\n## Rate Limit Headers\n\nEvery authenticated response includes:\n\n- `X-RateLimit-Limit` - Requests allowed per minute\n- `X-RateLimit-Remaining` - Requests remaining in current window\n- `X-RateLimit-Reset` - Unix timestamp when the window resets\n- `X-Data-Delay` - Odds delay in seconds for your tier (0 = real-time)\n- `X-Request-Id` - Unique request identifier for support\n\n## WebSocket Streaming\n\nThe WebSocket endpoint at `wss://ws.sharpapi.io` is documented separately in [`asyncapi.yaml`](./asyncapi.yaml) (AsyncAPI 3.0). OpenAPI 3.x cannot express WebSocket subprotocols and message channels, so the SSE endpoint (`/stream`) is the only stream covered by this document.\n\n## MCP Server\n\nThe `POST /mcp` endpoint is a Model Context Protocol server (JSON-RPC 2.0 over Streamable HTTP). Tools are self-described at runtime via `tools/list`, so it's documented as a setup guide rather than an OpenAPI path — see [`/sdks/mcp`](https://docs.sharpapi.io/sdks/mcp).\n",
"contact": {
"name": "SharpAPI Support",
Expand Down Expand Up @@ -1744,6 +1744,7 @@
"arb_profit": null,
"is_player_prop": false,
"player_name": null,
"player_id": null,
"stat_category": null,
"possibly_stale": false,
"oldest_odds_age_seconds": 12,
Expand Down Expand Up @@ -4588,6 +4589,7 @@
"arb_profit",
"is_player_prop",
"player_name",
"player_id",
"stat_category",
"possibly_stale",
"oldest_odds_age_seconds",
Expand Down Expand Up @@ -4731,6 +4733,11 @@
"type": "string",
"nullable": true
},
"player_id": {
"type": "string",
"nullable": true,
"description": "Canonical cross-book player identifier resolved by atlas_players (e.g. \"baseball_mlb_corbin_carroll\"). null when the producer has not resolved a canonical id for this player — group on `player_id` and fall back to `player_name`. Player-prop markets only."
},
"stat_category": {
"type": "string",
"nullable": true
Expand Down