diff --git a/CHANGELOG.md b/CHANGELOG.md index f8b85cd..22d20b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/content/de/api-reference/opportunities-ev.mdx b/content/de/api-reference/opportunities-ev.mdx index 6497d7e..f29a6da 100644 --- a/content/de/api-reference/opportunities-ev.mdx +++ b/content/de/api-reference/opportunities-ev.mdx @@ -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, @@ -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, @@ -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) | diff --git a/content/en/api-reference/opportunities-ev.mdx b/content/en/api-reference/opportunities-ev.mdx index 2c18e7f..612012b 100644 --- a/content/en/api-reference/opportunities-ev.mdx +++ b/content/en/api-reference/opportunities-ev.mdx @@ -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, @@ -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, @@ -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) | diff --git a/content/es/api-reference/opportunities-ev.mdx b/content/es/api-reference/opportunities-ev.mdx index cd02907..0c86dac 100644 --- a/content/es/api-reference/opportunities-ev.mdx +++ b/content/es/api-reference/opportunities-ev.mdx @@ -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, @@ -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, @@ -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) | diff --git a/content/pt-BR/api-reference/opportunities-ev.mdx b/content/pt-BR/api-reference/opportunities-ev.mdx index 6f68154..837d9fd 100644 --- a/content/pt-BR/api-reference/opportunities-ev.mdx +++ b/content/pt-BR/api-reference/opportunities-ev.mdx @@ -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, @@ -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, @@ -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) | diff --git a/public/openapi.json b/public/openapi.json index 3889530..9594be4 100644 --- a/public/openapi.json +++ b/public/openapi.json @@ -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", @@ -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, @@ -4588,6 +4589,7 @@ "arb_profit", "is_player_prop", "player_name", + "player_id", "stat_category", "possibly_stale", "oldest_odds_age_seconds", @@ -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