# WebSocket delivery with retained-change replay

Connect a server-side WebSocket client, process bounded retained odds pages, preserve sequence checkpoints and reconnect when the session ends.

Canonical page: https://getoddsapi.com/docs/odds-stream

## Free API key

Get a free GetOdds API key: **1,000 requests per UTC day and 60 per minute, no card**. One key covers REST and the hosted MCP server.

Sign up: https://getoddsapi.com/sign-up?ref=ai-claudebot

## Quickstart

1. Create an account at https://getoddsapi.com/sign-up?ref=ai-claudebot, open https://getoddsapi.com/dashboard and issue a key with the sources you need (draftkings, fanduel, betrivers, prizepicks or underdog). Keep it in a server environment variable named GETODDS_API_KEY.
2. Read current DraftKings NBA spreads with curl:

```bash
curl --fail-with-body "https://getoddsapi.com/api/v1/odds?sport=NBA&market=spread&fresh_only=true&limit=50" \
  -H "Authorization: Bearer $GETODDS_API_KEY"
```

3. The same request in Python (standard library only):

```python
import json, os, urllib.request

req = urllib.request.Request(
    "https://getoddsapi.com/api/v1/odds?sport=NBA&market=spread&fresh_only=true&limit=50",
    headers={"Authorization": "Bearer " + os.environ["GETODDS_API_KEY"]},
)
with urllib.request.urlopen(req) as res:
    rows = json.load(res)["data"]
for row in rows:
    print(row["away"], "at", row["home"], row["side"], row["line"], row["american"], row["observed_at"])
```

4. Check `observed_at`, `age_seconds` and `stale` on every row before using a price. Full reference: https://getoddsapi.com/docs

## Use with Claude (MCP)

```bash
claude mcp add --transport http getodds https://getoddsapi.com/api/mcp \
  --header "Authorization: Bearer $GETODDS_API_KEY"
```

The MCP tools follow the key's source grants and share its allowance. Setup guide: https://getoddsapi.com/use-with-claude

## Pricing

| Plan | Allowance | Price |
| --- | --- | --- |
| Free key | 1,000 requests a day, 60 a minute | $0, no card |
| Developer Bundle | 10,000 requests or credits a month on each of four sources | $149 a month |

Free development allowance: 1,000 requests per UTC day and 60 per minute per account, with no payment step. Paid: the Developer Bundle at $149 per month, with 10,000 monthly requests or credits on each of four sources.
Details: https://getoddsapi.com/bundle

## Guide


Canonical: https://getoddsapi.com/docs/odds-stream
Reviewed: 2026-11-07 UTC

Connect a server-side WebSocket client, process bounded retained odds pages, preserve sequence checkpoints and reconnect when the session ends.

## Connect with a server-side bearer key

Connect to wss://getoddsapi.com/api/v1/odds/stream with Authorization: Bearer in the upgrade headers. The key needs draftkings access and the account must have DraftKings selected. Browser-native WebSocket cannot set this bearer header; use a trusted backend client. Do not put credentials in the URL or browser storage.

The query accepts the same after, through, limit, event_ids, sport and market filters as /api/v1/odds/replay. A normal HTTP GET receives 426; this endpoint upgrades to a real WebSocket and does not return Server-Sent Events.

## Read what the source actually retained

The transport polls retained DraftKings-via-ESPN changes every five seconds, with at most 200 rows per page. It preserves observed_at and source metadata. A live socket does not make an old observation fresh or increase the collector’s capture frequency.

welcome describes the protocol. changes carries a replay data envelope; checkpoint carries an empty one. replay_complete marks the end of the initial bounded catch-up. Subsequent polls capture a new source watermark. No complete-capture, market-removal or settlement guarantee is implied.

## Checkpoint after processing, then reconnect

Process every row in a changes or checkpoint frame before saving pagination.next_after. Keep pagination.through while has_more is true; omit through after a completed page. Keep filters unchanged during catch-up. Sequence values are decimal strings and can exceed JavaScript’s safe integer range.

The server does not persist a client acknowledgement. If a connection ends before your application commits a page, reconnect from your last committed checkpoint and tolerate repeated seq values. A simple consumer can deduplicate by the source sequence. Durable processing and checkpoint storage belong in your application’s transaction.

Connections close after at most 240 seconds with 1012, allowing a clean reconnect before the platform deadline. Reconnect with backoff using your own processed checkpoint, not an unprocessed server hint. A resync_required frame means the anchor is outside retained coverage or missing; stop retrying it unchanged and deliberately bootstrap again.

## Respect account limits and errors

At most two sockets may be active per customer across all API keys. Connection leases live in the customer database and expire after 270 seconds if a worker disappears. Orderly close releases the lease after the server observes it. An abrupt disconnect can remain invisible to the platform proxy temporarily and retain a slot until detection, the 240-second session deadline or the 270-second lease expiry. A third concurrent upgrade returns 429.

Upgrade admission consumes request allowance but zero data credits. Every successful five-second poll consumes one data credit and one request, including empty polls. The same account allowance applies to REST and MCP. Key revocation, source scope and bookmaker selection are checked again on each poll.

Permission or replay-anchor failures close with 1008; quota/backpressure closes with 1013; source/transport failures close with 1011. Rate errors include a retry_after hint. Do not keep reconnecting an invalid key or an unchanged expired cursor. Application messages are not supported, incoming frames are limited to 1 KiB and slow clients are disconnected with a resumable checkpoint contract.

## Run a minimal Node client

Install ws, export GETODDS_API_KEY and run this example in a server process. It prints received frames; it does not claim to persist or automatically process checkpoints. Add durable processing and reconnect handling before using it as a production consumer.

```javascript
import WebSocket from "ws";

const key = process.env.GETODDS_API_KEY;
if (!key) throw new Error("Set GETODDS_API_KEY");
const socket = new WebSocket(
  "wss://getoddsapi.com/api/v1/odds/stream?after=0&limit=50",
  { headers: { Authorization: `Bearer ${key}` }, maxPayload: 1024 * 1024 }
);
socket.on("message", raw => console.log(JSON.parse(String(raw))));
socket.on("close", code => console.log("Closed:", code));
socket.on("error", () => console.error("Connection failed; inspect access and retry policy"));
```

## Questions

### Is this a complete real-time bookmaker feed?

No. It delivers actual retained changes over a live WebSocket. Collection completeness and source freshness remain separate constraints.

### Does the server acknowledge that my application processed a page?

No. Your application must commit its own checkpoint after processing. Reconnecting may repeat a previously received page.

### Can I keep a connection open indefinitely?

No. Sessions close after at most 240 seconds. Reconnect from your processed checkpoint, observing shared quotas and retry guidance.

## Sources

- [GetOdds replay contract](https://getoddsapi.com/docs/odds-replay)
- [GetOdds bookmaker selection](https://getoddsapi.com/docs/bookmaker-selection)
- [Vercel WebSocket support](https://vercel.com/docs/functions/websockets)
- [Vercel upgradeWebSocket API](https://vercel.com/docs/functions/functions-api-reference/vercel-functions-package#upgradewebsocket)

Independent product; not affiliated with the operators named. No picks or predicted profits.

---

GetOdds is an independent developer product and is not affiliated with any sportsbook or pick’em operator. Prices describe data, not betting advice.
