Skip to content

Commit 41affda

Browse files
Mlaz-codeCodexclaude
authored
docs: deprecate last_seen_at + wire_received_at; document odds_changed_at (#256)
* docs: deprecate last_seen_at + wire_received_at on the odds response; document odds_changed_at Phase 1 of internalizing the two non-betting response timestamps (sharp-api-go issue #743). Customer-facing deprecation signal: - openapi.json (Odds schema): mark `last_seen_at`, `wire_received_at`, and the stale `timestamp` prop `deprecated: true`; ADD the canonical `odds_changed_at` prop (it was missing) as the freshness field to read. - Field tables (odds / odds-batch / odds-best / odds-comparison .mdx): mark the rows ⚠️ Deprecated and redirect to `odds_changed_at`. Also fixes odds-best's mislabeled "best odds determination" description for last_seen_at. Fields still emit during the deprecation window — no contract break yet; removal is tracked in Mlaz-code/sharp-api-go#743. Type: docs 🤖 Generated with [Claude Code](https://claude.com/claude-code) * docs: bump OpenAPI spec to 2.3.0 + changelog (odds_changed_at add + deprecations) Satisfies the openapi-version-check policy: schema changed (added odds_changed_at, deprecated last_seen_at/wire_received_at/timestamp) → MINOR bump + CHANGELOG entry. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Codex <codex@sharpapi.local> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent c86b7de commit 41affda

6 files changed

Lines changed: 26 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ to bump. Every change to API paths or response schemas gets a one-line entry her
66
the [OpenAPI Version Check](.github/workflows/openapi-version-check.yml) CI job
77
enforces that a bump has a matching entry.
88

9+
## 2.3.0 — 2026-06-01
10+
11+
- Add `odds_changed_at` to the `Odds` schema — the canonical per-row freshness field (previously undocumented; also the only per-odd freshness timestamp OpticOdds exposes). Deprecate `last_seen_at`, `wire_received_at`, and the stale `timestamp` prop (`deprecated: true`) — being internalized; read `odds_changed_at` for freshness. Removal tracked in sharp-api-go #743.
12+
913
## 2.2.0 — 2026-05-31
1014

1115
- Add `is_active` field to the `Odds` schema (`false` = market suspended/closed, price frozen; mirrors OpticOdds locked-odds; absent treated as `true`). SHA-3803.

content/en/api-reference/odds-batch.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ Each item in the `data.events` array is an event object with nested odds:
289289
| `odds_american` | number | American odds |
290290
| `odds_decimal` | number | Decimal odds |
291291
| `line` | number \| null | Line value |
292-
| `last_seen_at` | string | ISO 8601 timestamp when our pipeline last observed this row. Use this as your pipeline freshness signal. |
292+
| `last_seen_at` | string | **⚠️ Deprecated** — being internalized; will be removed in a future release. Liveness heartbeat (advances every cycle even when the price is unchanged), not a price-freshness signal. Read `odds_changed_at` for freshness. |
293293
| `odds_changed_at` | string | ISO 8601 timestamp of when the price, line, or `is_live` flag last actually changed. Sportsbook-provided when available; on Pinnacle it carries forward across unchanged refreshes — see [Understanding Pinnacle's `odds_changed_at`](/en/concepts/pinnacle-odds-changed-at/). |
294294

295295
## Use Cases

content/en/api-reference/odds-best.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ X-Request-Id: req_best_789xyz
215215
| `all_books[].line` | number \| null | Line at this sportsbook |
216216
| `all_books[].last_seen_at` | string | When our pipeline last observed this book's row — pipeline freshness signal |
217217
| `all_books[].odds_changed_at` | string | When this book's price, line, or `is_live` flag last actually changed. On Pinnacle, carries forward across unchanged refreshes — see [Understanding Pinnacle's `odds_changed_at`](/en/concepts/pinnacle-odds-changed-at/). |
218-
| `last_seen_at` | string | ISO 8601 timestamp of the best odds determination |
218+
| `last_seen_at` | string | **⚠️ Deprecated** — being internalized; will be removed in a future release. Liveness heartbeat for the row (advances every cycle even when the price is unchanged), not a price-freshness signal. Read `odds_changed_at` for freshness. |
219219
| `player_name` | string\|undefined | Player name (player prop markets only) |
220220
| `stat_category` | string\|undefined | Stat category, e.g. `points`, `rebounds` (player prop markets only) |
221221

content/en/api-reference/odds-comparison.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ Each entry in the `books` object:
253253
|-------|------|-------------|
254254
| `odds_american` | number | American odds |
255255
| `odds_decimal` | number | Decimal odds |
256-
| `last_seen_at` | string | When our pipeline last observed this book's row — pipeline freshness signal |
256+
| `last_seen_at` | string | **⚠️ Deprecated** — being internalized; will be removed in a future release. Liveness heartbeat (advances every cycle even when the price is unchanged), not a price-freshness signal. Read `odds_changed_at` for freshness. |
257257
| `odds_changed_at` | string | When this book's price, line, or `is_live` flag last actually changed. On Pinnacle, carries forward across unchanged refreshes — see [Understanding Pinnacle's `odds_changed_at`](/en/concepts/pinnacle-odds-changed-at/). |
258258

259259
## Understanding Hold

content/en/api-reference/odds.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -325,9 +325,9 @@ X-Request-Id: req_abc123def456
325325
| `is_alternate_line` | boolean | `true` when this row's `line` differs from the canonical main line for its `(event, market_type, selection)` group. `false` for the consensus main line, for no-line markets (moneyline, outright), and for rows whose cohort hasn't been published yet (cold start, brand-new event). See `is_main_line` for the positive-polarity sibling that disambiguates "main" from "cohort-pending". |
326326
| `is_main_line` | boolean | `true` when this row's `line` equals the canonical main line for its `(event, market_type, selection)` group, AND for no-line markets (moneyline, outright — always main by definition). `false` for alt-line rows and for rows whose cohort hasn't been published yet. **Mutually exclusive with `is_alternate_line`:** both true never coexists; both false is the cohort-pending state. Filter for `is_main_line=true` when you want a positive "main lines only" view that excludes cohort-pending rows. Also accepted as a query filter on [`/odds/best?is_main_line=true`](/en/api-reference/odds-best/). |
327327
| `event_start_time` | string | ISO 8601 event start time |
328-
| `last_seen_at` | string | ISO 8601 timestamp of our adapter's last observation of this row. Advances every ingest cycle even when the content is unchanged — use as a heartbeat that the row is still being maintained, not as an ingest-latency benchmark. |
329-
| `wire_received_at` | string\|undefined | ISO 8601 timestamp of when SharpAPI first observed a content change for this row, carried forward across subsequent unchanged refreshes. **Use this field for ingest-latency benchmarking** — it isolates SharpAPI's pipeline contribution from the sportsbook's source-side publish cadence. Omitted on cold-start rows where no prior observation exists. See [Understanding Pinnacle's `odds_changed_at`](/en/concepts/pinnacle-odds-changed-at/#benchmarking-pipeline-latency). |
330-
| `odds_changed_at` | string | ISO 8601 timestamp of the sportsbook's own source update for this line, when available. On Pinnacle, carries forward while the price/line/`is_live` flag are unchanged (see [Understanding Pinnacle's `odds_changed_at`](/en/concepts/pinnacle-odds-changed-at/)). Not suitable for SharpAPI pipeline-latency benchmarking — use `wire_received_at` for that. |
328+
| `last_seen_at` | string | **⚠️ Deprecated** — being internalized; will be removed in a future release. Liveness heartbeat: advances every ingest cycle even when the price is unchanged, so it is *not* a price-freshness signal. Read `odds_changed_at` for freshness. |
329+
| `wire_received_at` | string\|undefined | **⚠️ Deprecated** — being internalized; will be removed in a future release. SharpAPI pipeline-arrival stamp for ingest-latency benchmarking only — not a betting signal. Read `odds_changed_at` for price freshness. |
330+
| `odds_changed_at` | string | **The freshness field to read.** Best-available last-price-change time: the sportsbook's own source-update timestamp when provided, otherwise when SharpAPI first detected a price/line/`is_live` change — carried forward across unchanged refreshes (see [Understanding Pinnacle's `odds_changed_at`](/en/concepts/pinnacle-odds-changed-at/)). |
331331
| `is_live` | boolean | Whether the event is currently live |
332332
| `is_active` | boolean | `true` (default) = market open and bettable; `false` = market suspended/closed with the price **frozen** at its last value (so you can grey it out rather than trust a stale price). Mirrors OpticOdds' `locked-odds`, but as a queryable field you can also filter on. Absent is treated as `true`. An active→suspended transition is pushed on the [odds stream](/en/api-reference/stream/) as an `odds:update` carrying `is_active: false`. |
333333
| `event_uuid` | string\|undefined | Stable canonical event UUID from the SharpAPI atlas, when the event is mapped. Where `event_id` carries the adapter's primary event identifier (often the originating sportsbook's), `event_uuid` is a feed-stable hash you can use for cross-feed joins. Absent for unmapped events. |

public/openapi.json

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"openapi": "3.1.0",
33
"info": {
44
"title": "SharpAPI",
5-
"version": "2.2.0",
5+
"version": "2.3.0",
66
"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",
77
"contact": {
88
"name": "SharpAPI Support",
@@ -4462,15 +4462,28 @@
44624462
"type": "boolean",
44634463
"description": "true (default) = market open and bettable; false = market suspended/closed with the price frozen. Mirrors OpticOdds locked-odds but exposed as a queryable field. Absent is treated as true. An active->suspended transition is emitted on the odds stream (odds:update with is_active=false)."
44644464
},
4465+
"odds_changed_at": {
4466+
"type": "string",
4467+
"format": "date-time",
4468+
"description": "Best-available last-price-change time for this line: the sportsbook's own source-update timestamp when provided, otherwise when SharpAPI first detected a price/line/is_live change — carried forward across unchanged refreshes. This is the freshness field to read."
4469+
},
44654470
"timestamp": {
44664471
"type": "string",
44674472
"format": "date-time",
4468-
"description": "When these odds were last updated"
4473+
"deprecated": true,
4474+
"description": "DEPRECATED — not emitted on the odds response; read `odds_changed_at` for price freshness."
4475+
},
4476+
"last_seen_at": {
4477+
"type": "string",
4478+
"format": "date-time",
4479+
"deprecated": true,
4480+
"description": "DEPRECATED (being internalized, will be removed in a future release): liveness heartbeat — advances every ingest cycle even when the price is unchanged, so it is NOT a price-freshness signal. Read `odds_changed_at` instead."
44694481
},
44704482
"wire_received_at": {
44714483
"type": "string",
44724484
"format": "date-time",
4473-
"description": "Pipeline-arrival stamp — when sharp-api-go last observed a content-hash change for this row. Distinct from `last_seen_at` (adapter observation) and `odds_changed_at` (sportsbook's own source update)."
4485+
"deprecated": true,
4486+
"description": "DEPRECATED (being internalized, will be removed in a future release): SharpAPI pipeline-arrival stamp for ingest-latency benchmarking only — not a betting/price-freshness signal. Read `odds_changed_at` for price freshness."
44744487
},
44754488
"event_uuid": {
44764489
"type": "string",

0 commit comments

Comments
 (0)