Webhooks and stream
FanDuel webhooks and live stream
FanDuel line and price changes pushed as they happen: a Server-Sent Events stream with resume on every plan, and signed webhooks on Production and up.
FanDuel API is an independent data service operated by FF API Inc. It is not affiliated with, endorsed by or sponsored by FanDuel.
Stop polling: take each change the moment it is collected, on a connection or at your URL.
- Stream
- Server-Sent Events with Last-Event-ID resume. Free sees it five minutes behind; concurrent connections scale with the plan.
- Webhooks
- HMAC-signed POSTs with retries and a delivery log, up to five endpoints, on plans that list Webhooks.
- Same frames
- Stream events, webhook bodies and change feed rows carry the same fields and cursors.
What it returns now
Real rows, 5 min delay, as of 3:25 PM ET
id: 36350
event: change
data: {"cursor":"36350","kind":"line_move","league":"NCAAF","player":"Antonio Jordan","stat":"receiving_yards","previous":{"line":34.5,"over_american":-114},"current":{"line":30.5,"over_american":-114},"at":"2026-11-06T20:24:13.461Z"}
id: 36311
event: change
data: {"cursor":"36311","kind":"line_move","league":"NBA","player":"Payton Pritchard","stat":"pra","previous":{"line":19.5,"over_american":-128},"current":{"line":20.5,"over_american":-102},"at":"2026-11-06T20:23:58.749Z"}
id: 36310
event: change
data: {"cursor":"36310","kind":"line_move","league":"NBA","player":"Neemias Queta","stat":"pra","previous":{"line":18.5,"over_american":100},"current":{"line":17.5,"over_american":-128},"at":"2026-11-06T20:23:58.749Z"}
Endpoints and parameters
/api/v1/streamLine, price and status changes pushed as they happen, with Last-Event-ID resume. Free is delayed 5 minutes; concurrent connections are capped per plan.
| Parameter | In | Description |
|---|---|---|
| league | query | League code as FanDuel lists it, such as NBA. |
/api/v1/webhooksYour registered webhook endpoints. Production and up.
/api/v1/webhooksRegister an HTTPS endpoint for signed change events; the signing secret is shown once. Production and up, up to five endpoints.
Code
curl "https://fanduelapi.com/api/v1/stream?league=NBA" \
-H "Authorization: Bearer $FANDUEL_API_KEY"import hmac, hashlib, time
# X-Webhook-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "t.raw_body">
def verified(raw_body: bytes, header: str, secret: str, tolerance=300) -> bool:
parts = dict(item.split("=", 1) for item in header.split(","))
t = int(parts["t"])
if abs(time.time() - t) > tolerance:
return False
expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts.get("v1", ""))Keys look like fd_.... Keep one in the FANDUEL_API_KEY environment variable on your server, never in browser code. Every response's meta says which plan answered, how far behind it is and how fresh the collection is.
Which plans include it
- FreeStream, 5 minutes behind; no webhooks
- DeveloperStream; webhooks from Production
- ProductionStream and signed webhooks
- ScaleStream and signed webhooks
Read from the plans on the pricing page. Every request counts against the monthly and per-minute allowance; request quotas explains how.
Works well with
- Change feedKeep a local copy of the board current by reading only what changed since your last call.
/api/v1/changes - Line historyReplay a prop or a game line from the first time it was seen to now, move by move.
/api/v1/props/{id}/history - WorkspaceRun the integration with keys you can rotate in seconds and limits you can see.
/dashboard/keys
Related
Make your first call in a few minutes
Sign up, create a key in the dashboard, and send it as a Bearer token. The free plan needs no card and reads the same data five minutes behind.
Get a free API key