MagicMarkets API
You are helping a developer build against the MagicMarkets API — a peer-to-peer sports markets exchange with zero fees and zero commission. Users back and lay against each other; all stakes are denominated in USDT.
| Detail | Value |
|---|---|
| REST base URL | https://pro.magicmarkets.com/v2/ |
| Price feed (WebSocket) | wss://pro.magicmarkets.com/magic-cpricefeed/v2?api_key=<api_key> |
| Auth (REST) | X-Api-Key: <token> header |
| Auth (WebSocket) | ?api_key=<api_key> query parameter |
| Stake format | ["USDT", <amount>] tuples in every request and response |
| Price format | Decimal odds (e.g. 1.85, 2.40) |
| Model | P2P exchange — back, lay, or stack into parlays |
For deep schema reference, read references/rest-reference.md.
For the WebSocket protocol, read references/pricefeed-reference.md.
The two are complementary:
- Price feed (WebSocket) is where you get real-time market depth — best prices, stakes, and updates every 2 seconds.
- REST
/v2/betslips/and/v2/orders/is where you commit to a price and place orders.
You typically watch prices on the WebSocket, then create a betslip and place an order via REST when you want to trade.
Authentication
Every REST request needs the X-Api-Key header:
curl -H "X-Api-Key: $MM_API_KEY" https://pro.magicmarkets.com/v2/xrates/
WebSocket auth is via query parameter:
wss://pro.magicmarkets.com/magic-cpricefeed/v2?api_key=<api_key>
If the key starts with m-, an additional &jwt=<firebase_jwt> is
required. Plain API keys (the kind you mint from your account dashboard)
don't need a JWT.
Tell the developer to store the key in an environment variable
(export MM_API_KEY=...) rather than hard-coding it.
Glossary
A short conceptual reference. The terms below appear throughout the skill; read this first if you're new to MagicMarkets.
Betslip — A quote. You ask "what prices are available for this market?"
and the API returns a betslip_id plus a price_list of currently-available
price/stake levels. A betslip expires ~45 seconds after creation; refresh it
or create a fresh one.
Order — A commitment. You take a betslip_id and a price/stake and
ask the engine to fill it. An order can be open (still trying), done
(filled), expired (timed out), or failed (rejected).
Bet — A fill. Inside an order, each individual match against a counterparty
is a bet. A single order may produce multiple bets (e.g. partially filled at
several price levels). Bets have their own bet_id and profit_loss once
the underlying event settles.
Lifecycle:
betslip (quote) ──POST /v2/orders/──▶ order (commitment)
│
├─ matches ─▶ bet (fill) ──▶ event settles ──▶ profit_loss
└─ expires / cancelled / failed
Back vs lay — Back means you win if the selection happens; lay means
you win if it doesn't. The API uses betslip_type: "normal" for back and
betslip_type: "lay" for lay. Both work on the same bet_type string —
e.g. for,h with normal is "back home"; for,h with lay is "lay home".
for vs against — Independent of back/lay: for,h picks the selection
home wins, while against,h picks the selection home does not win. In
practice you usually want for,X with either normal or lay — the
against,* book has thinner liquidity (see Common mistakes).
Parlay (acca) — Stack 2–10 back legs into one bet that pays only if every
leg wins. betslip_type: "parlay" with a legs[] array.
Heartbeat — A deadman's switch. Open one with a timeout (10–300s) and
all your open orders auto-close if you don't refresh before it expires.
Settlement — A bet is "reconciled" when the event ends and profit_loss
becomes non-null. For pre-match orders this is usually within a few minutes
of full-time. In-running orders settle when the period or match ends.
Lay pricing quick reference
MagicMarkets lays fill at the complement price, not the back price — this is not the Betfair convention. If a back is sitting at 2.38 in the book, your lay fills at 1.73, not 2.38.
| Back price in book | Lay-fill price | Liability per 1 USDT lay |
|---|---|---|
| 1.25 | 5.00 | 4.00 |
| 1.50 | 3.00 | 2.00 |
| 2.00 | 2.00 | 1.00 |
| 2.50 | 1.67 | 0.67 |
| 3.00 | 1.50 | 0.50 |
| 4.00 | 1.33 | 0.33 |
| 5.00 | 1.25 | 0.25 |
Formula: P_lay = P_back / (P_back − 1). Equivalently, this is the price
at which backing the opposite outcome would have the same payoff.
For the full payoff structure, force-price gotchas, and the against,X vs
for,X lay distinction, see the "Lay order pricing" section in
references/rest-reference.md.
Key concepts
Sport codes
| Code | Sport | Typical markets |
|---|---|---|
fb | Football (soccer) 90 min | wdw, ah, ahou, cs, gr, oe, wm, score,both, tahou,h/a, proposition,* |
fb_ht | Football 1st half | wdw, ah, ahou, cs, score,both |
fb_2h | Football 2nd half | as fb_ht |
fb_et | Football extra time | reduced market set |
fb_corn / fb_corn_ht | Football corners | ahou (corner totals), wdw (most corners) |
fb_book | Football yellow cards | ahou (booking points) |
fb_htft | Football HT/FT result | wdw-style 9-way |
basket | Basketball full | ml, ah, ahou |
basket_ht / basket_2h / basket_q1–q4 | Basketball segments | ml, ah, ahou |
tennis | Tennis | tennis_match,all, tennis_ah,set,all, tennis_ahou,game,all |
tt | Table tennis | similar to tennis |
ih | Ice hockey | time_win,tp,reg,wdw, time_win,tp,all,ml, time_ah,tp,*, time_ahou,tp,* |
af | American football | ml, ah, ahou per quarter/half |
rl / ru | Rugby league / union | wdw, ah, ahou |
arf | Australian rules football | wdw, ah, ahou; also outright win |
hand | Handball | wdw, ah, ahou |
volley | Volleyball | ml, ah (set-based) |
baseball | Baseball | ml, ah (run line), ahou (totals) |
cricket | Cricket | mostly outright win; some ml for limited-overs |
darts | Darts | mostly outright win; ml for matches |
snooker | Snooker | ml, ahou (frame totals) |
boxing | Boxing | ml (no draw on most fights) |
mma | Mixed martial arts | ml, ahou (round totals) |
golf | Golf | outright win (multirunner) |
cycling | Cycling | outright win |
moto | Motorsport | outright win |
horse | Horse racing | outright win, sometimes top |
dog | Greyhound racing | outright win |
esports | Esports | ml, map-based markets via tmap,n |
politics | Political markets | outright win |
specials | Specials / novelty | varies |
This list is not a closed enum — new sports are added over time. Don't
hard-fail on unknown codes. On parlay betslips/orders, sport is the literal
string parlay; per-leg sport sits inside each legs[] entry.
The "typical markets" column is empirically observed — individual events may
expose more or fewer markets. Read the WS offers_event columns or
POST /v2/betslips/ response to see what's actually available for a given
event.
Important: the /v2/sports/{sport}/bet_types/{bet_type}/ endpoint does not
validate sport codes — it accepts any string including made-up ones. Only
POST /v2/betslips/ with a real sport+event_id combination will reject an
invalid sport. Always read event_info.sport from real orders or the price feed;
do not rely on this endpoint for sport validation.
Where event IDs come from
There is **no REST endpoint that lists available events