Exchange prices
Both sides of each selection, with the price and available size at each level.
Build with live, in-play odds through REST, SSE and WebSockets. Current live coverage is Betfair Exchange, with back and lay prices, liquidity and matched volume.
{
"event_id": "event-001",
"items": [{
"id": "betfair::1.23456789::moneyline",
"event_id": "event-001",
"exchange": "betfair",
"exchange_market_id": "1.23456789",
"market_key": "moneyline", "period": "full time",
"in_play": true, "status": "open",
"currency": "AUD", "total_matched": 24567.12,
"freshness": "live", "actively_collected": true,
"selections": [{
"selection_key": "moneyline:home", "selection_name": "Home",
"best_back_price": 2.08, "best_back_size": 120.50,
"best_lay_price": 2.10, "best_lay_size": 84.30
}]
}],
"resume": "1760000000000-0"
}
Read the exchange price, available liquidity and market state together.
Both sides of each selection, with the price and available size at each level.
Track total matched activity and each selection’s last traded price.
Handle open, suspended and closed markets alongside quote freshness.
Start with a Betfair in-play event. Copy the request or give the prompt to your AI agent.
X-API-Keybetfair/v1/events/{event_id}/exchange/orderbook/snapshot
Build a live Betfair odds board using https://api.odds-api.net/v1. Keep ODDS_API_KEY on the server and authenticate with X-API-Key.
Find events with /events?event_states=in_play&limit=50 and select one that lists betfair. Fetch /events/{event_id}/exchange/orderbook/snapshot?exchanges=betfair&depth=3&refresh=true. Show only order books with in_play=true.
Display back and lay ladders, price-level size, total_matched, status and freshness. Open the matching /exchange/orderbook/stream or /exchange/orderbook/ws route with the snapshot resume as since. Handle delta, heartbeat and resync. Treat suspended or stale books as unavailable for a current quote.
Use decimal exchange prices. Keep pre-match sportsbook prices separate from Betfair in-play exchange data.import json
import os
from urllib.parse import quote, urlencode
from urllib.request import Request, urlopen
base = "https://api.odds-api.net/v1"
headers = {"X-API-Key": os.environ["ODDS_API_KEY"]}
def get(path, **params):
request = Request(f"{base}{path}?{urlencode(params)}", headers=headers)
with urlopen(request, timeout=20) as response:
return json.load(response)
events = get("/events", event_states="in_play", limit=50)["items"]
event = next((event for event in events
if "betfair" in (event.get("bookmakers") or {})), None)
if event is None:
raise RuntimeError("No in-play Betfair event found in this event page.")
event_id = quote(str(event["event_id"]), safe="")
snapshot = get(f"/events/{event_id}/exchange/orderbook/snapshot",
exchanges="betfair", depth=3, refresh="true")
books = [book for book in snapshot.get("items", [])
if book.get("exchange") == "betfair" and book.get("in_play")]
if not books:
raise RuntimeError("No in-play Betfair order book returned for this event.")
print(json.dumps({"event_id": event["event_id"], "items": books,
"resume": snapshot.get("resume")}, indent=2))# Find an in-play event that lists betfair.
curl --get "https://api.odds-api.net/v1/events" \
--header "X-API-Key: $ODDS_API_KEY" \
--data-urlencode "event_states=in_play" \
--data-urlencode "limit=50"
# Set EVENT_ID to its event_id, then load the order book.
curl --get "https://api.odds-api.net/v1/events/$EVENT_ID/exchange/orderbook/snapshot" \
--header "X-API-Key: $ODDS_API_KEY" \
--data-urlencode "exchanges=betfair" \
--data-urlencode "depth=3" \
--data-urlencode "refresh=true"# Use the event_id and resume token from your snapshot.
curl --no-buffer --get \
"https://api.odds-api.net/v1/events/$EVENT_ID/exchange/orderbook/stream" \
--header "X-API-Key: $ODDS_API_KEY" \
--header "Accept: text/event-stream" \
--data-urlencode "exchanges=betfair" \
--data-urlencode "depth=3" \
--data-urlencode "since=$RESUME" \
--data-urlencode "catchup=true"
# delta: apply changes and retain the newest resume token.
# heartbeat: keep the connection open.
# resync: reload the snapshot and reconnect from its resume token.// Server-side Node.js. Install: npm install ws
import WebSocket from "ws";
if (!process.env.EVENT_ID || !process.env.RESUME || !process.env.ODDS_API_KEY) {
throw new Error("Set EVENT_ID, RESUME and ODDS_API_KEY from your snapshot.");
}
const eventId = encodeURIComponent(process.env.EVENT_ID);
const url = new URL(
`wss://api.odds-api.net/v1/events/${eventId}/exchange/orderbook/ws`
);
url.search = new URLSearchParams({
exchanges: "betfair", depth: "3", catchup: "true",
since: process.env.RESUME
}).toString();
const socket = new WebSocket(url, {
headers: { "X-API-Key": process.env.ODDS_API_KEY }
});
socket.on("message", (raw) => {
const message = JSON.parse(raw.toString());
if (message.event === "resync") {
console.log("Reload the snapshot, then reconnect with its resume token.");
socket.close();
return;
}
console.log(message.event, message.data);
});
socket.on("error", console.error);{
"event_id": "event-001",
"items": [{
"id": "betfair::1.23456789::moneyline",
"event_id": "event-001",
"exchange": "betfair",
"exchange_market_id": "1.23456789",
"market_key": "moneyline",
"period": "full time",
"period_str": "full time",
"status": "open",
"in_play": true,
"currency": "AUD",
"total_matched": 24567.12,
"freshness": "live",
"actively_collected": true,
"selections": [{
"selection_key": "moneyline:home",
"selection_name": "Home",
"best_back_price": 2.08,
"best_back_size": 120.50,
"best_lay_price": 2.10,
"best_lay_size": 84.30,
"available_to_back": [{"price": 2.08, "size": 120.50}],
"available_to_lay": [{"price": 2.10, "size": 84.30}]
}]
}],
"resume": "1760000000000-0"
}Build an in-play exchange board with back and lay ladders, traded activity and market state.
Keep both sides of the market, with the price and available size at each level.
available_to_backavailable_to_layFollow matched market volume and each selection’s last traded price alongside the quoted ladder.
total_matchedlast_traded_priceRead whether the market is in play and whether it is open, suspended or closed.
in_playstatusSeparate a current quote from a warming or stale book using the source observation fields.
freshnesssource_age_secondsobserved_atKeep the available size with each back and lay price. Use depth to select how many price levels your board needs.
best_back_sizebest_lay_sizecurrencyFollow delta messages, keep your resume token and reload the snapshot when the stream requests a resync.
deltaheartbeatresyncTools for events, odds, line movement, streams, and paid-plan positive EV or arbitrage feeds.
Agent-ready instructions.
TypeScript, Python, Postman and example builds.
Sports and racing odds coverage for agent workflows.
Lightweight streaming updates for dashboards and alerts.
Price updates for sportsbook and exchange products.
Load the snapshot, then follow changes using the same event and selection identifiers.
Filter events with event_states=in_play, then select a Betfair event by its canonical event ID.
Request exchanges=betfair and choose your ladder depth. Keep price, size, market and selection identity together.
Open SSE or WebSocket with since set to the snapshot’s resume token. Apply delta messages in order.
Retain the latest resume token. When the server sends resync, reload the snapshot before following updates again.
Choose a monthly plan based on request volume, rate limits, and support.
Enterprise grade
Custom projects, scoped with your team.
Connections, data fields and integration.
The live odds API returns Betfair in-play back and lay prices, available liquidity, matched activity and market state, alongside normalized identifiers, freshness fields and stream resume tokens.
Request /events with event_states=in_play, then select an event that lists betfair. Load its exchange order-book snapshot with exchanges=betfair and check in_play and status before displaying a current quote.
Use SSE for a simple HTTP connection that receives updates. Choose WebSocket when it fits your application’s connection model. Both exchange streams provide delta, heartbeat and resync messages and support resume tokens.
Read freshness, source_age_seconds, observed_at and actively_collected on the order book. Keep in_play and status with the quote, so a suspended market or an old observation is handled correctly.
The API supplies market data. It does not log in to a Betfair customer account, hold funds or submit bets.
Create your account and connect your first Betfair order book with REST, SSE or WebSocket.