Event
Something with markets on it.GET /v2/events/ lists every event that currently has prices, with filters for sport, competition, event, start time and ir_status. The WebSocket carries the same objects: on connect the server sends every currently priced event as ["event", ...] entries, then a ["sync", ...] marker, and after that it pushes each change as it happens.
ir_status can stay pre_event after start_time passes. Check start_time before you treat an event as not started.
Two shapes, told apart by event_type:
normal: a match, withhomeandaway.multirunner: an outright or futures market, with ateamsarray and anend_time.
2026-09-13,1001,2002: an event date, the home team id, the away team id. A multirunner id looks like 2026-09-10,multirunner,100375008. Treat the id as an opaque string. The date in it does not always match start_time.
Offer
One priced selection on the public feed, keyed by(sport, event_id, bet_type). It carries a price_list sorted by decimal price descending, with the stake available at each price. for and against on the same selection are two separate offers.
GET /v2/offers/ returns a snapshot of the offers on up to 20 events per call. event_id is a repeated query parameter, one value for each event. The reply is paged. limit defaults to 500 (max 5000). Pass the last entry’s "{event_id},{bet_type}" as after for the next page. A page shorter than limit is the last one. For live updates, register_event on the stream. On the stream, an empty price_list means no liquidity right now: pick another offer. The REST response leaves out markets with no available stake.
Betslip
The first step to place an order on one selection. The app calls it an order ticket: see Placing and managing orders. You name a selection withsport, event_id and bet_type, and you get a betslip_id. The response carries no prices. The quote arrives separately as pmm messages on the WebSocket, usually within a couple of seconds.
Betslips are short-lived. A betslip closes about 45 seconds after creation unless you extend it with POST /v2/betslips/{betslip_id}/refresh/. Watch expiry_ts. An account can hold a limited number of open betslips; a create beyond the cap returns 403 too_many_open_betslips. Close a betslip you no longer need with DELETE /v2/betslips/{betslip_id}/, which frees its slot. When a betslip closes, a betslip_closed message carries its close_reason and no further pmm arrives. An order already placed on it stays open until it fills, times out or you close it. Create a new betslip to re-quote.
betslip_type is normal unless you set it. To take the other side of an outcome, the usual way is a normal betslip with an against bet type: its price is odds on the outcome not happening, and higher is better, as with for. A lay betslip carries a lay price instead, where lower is better. Its prices are not on the same scale as a normal betslip’s, so keep one convention in a strategy. See Prices and ticks.
Nothing is at risk until you place an order against a betslip.
pmm
Your private quote for an open betslip, delivered on the socket. It carries thebetslip_id and a price_list for you specifically. Match it to your betslip by id.
Order
A commitment: abetslip_id plus a price and a stake. Orders move open, then pending, then done or failed. Once the event settles, a filled order shows reconciled and its profit_loss is filled in. The spec also lists partial_void and full_void, so treat status as an open set.
done means filled, not settled. The order found a counterparty and you hold a position. profit_loss stays empty until the event finishes and the market settles.close_reason, such as order_filled, timed_out, event_concluded or cancelled. The app shows the same orders with its own status names. See Order statuses.
Always send a
request_uuid from automated code. Reusing one returns 409 order_already_created with the existing order_id, so a retry after a timeout cannot double-place. You can look an order up by its request_uuid at GET /v2/orders/tracked/{uuid}/ for several days after placement.
Order options
POST /v2/orders/ takes more than a price and a stake. The ones that change behaviour:
live_score on a betslip is for your reference only. Use current_score on the order for score protection.
The full field list is on the Create order reference page.
Heartbeat
A dead-man’s switch. Create one with a timeout between 10 and 300 seconds and keep refreshing it. If you stop, the server closes every open order on the account, across all sessions and API keys. Matched positions are unaffected. Any unattended strategy should run inside one. See Safety.The flow, end to end
GET /v2/events/ in place of the sync, and GET /v2/offers/ for a snapshot of an event’s offers. A REST reply can be about 4 seconds behind live prices. The pmm quote and order updates still arrive on the socket, or you poll the betslip and the order.
Combos
A combo joins 2 to 10 selections into one order. Create the betslip withbetslip_type: "parlay" and a legs array of 2 to 10 selections, each {sport, event_id, bet_type}, in place of the top-level fields. On combo betslips and orders, sport and bet_type are both the literal parlay. A combo price is the product of its legs’ prices, so it does not sit on the tick schedule.
Sports and bet types
sport is a short lowercase code such as fb or basket_q1. bet_type is a comma-separated string that starts with for (back) or against (lay). Read both off an offer and pass them through unchanged. See Sports and bet types.
Money
Stakes and balances are[currency, amount] tuples, always USDT:
Response envelope
Every JSON response uses one envelope. Checkstatus before reading data, and branch on code rather than on the HTTP status alone.

