API Documentation
Everything you need to query crash, roulette and sports odds data from DuelAPI.
Introduction
Base URL: https://api.duelapi.com
All endpoints require authentication using an API key in the X-API-Key header, except for the /health endpoint.
Authentication
Include your API key in the request header:
X-API-Key: cr_your_read_key_here
PvP Arena API
Use your DuelAPI read key to access live Duel Arena data. These endpoints require a paid Starter, Pro, or Scale plan, purchased top-up credits, or a legacy unlimited key. Extra keys share their subscription’s credit pool. Successful requests use credits; failed requests are not charged.
The arena board shows only waiting games with open player spots and refreshes every five seconds while visible. Posting there uses your DuelAPI account. Programmatic access uses the endpoints below.
GET /api/arena/games— all 12 games. 1 credit.GET /api/arena/resolve?url=…— parse a link or six-character code and return its session and game metadata. Also acceptscodeand optionalslug. 1 credit.GET /api/arena/lobbies?status=waiting&sort=recent&limit=100— live lobbies. Optionalgame;statusaccepts live, all, waiting, active, completed, expired, cancelled;sortaccepts recent, high, low.limitis 1–500. Costs 1 credit per 100 rows requested (default 100).GET /api/arena/session?code=Q4FN36— one session. 1 credit.GET /api/arena/game?slug=8ball— game metadata. 1 credit.POST /api/arena/watch— track a join link or raw code. JSON body:{"url":"https://duel.com/arena/8ball?code=Q4FN36"}or{"code":"Q4FN36"}. 1 credit.GET /api/arena/history?game=&player=&status=&limit=50&offset=0— tracked lobby history. Player accepts a username or ID. 1 credit per 100 rows requested.GET /api/arena/players?sort=games&q=&limit=50&offset=0&min_games=1— tracked player statistics. Sort accepts games, wins, winrate, wagered. 1 credit per 100 rows requested.GET /api/arena/player?name=…— one player’s stats, per-game totals, last 40 games, and best-effortcross.highscoresandcross.rpsdata. 1 credit.GET /api/arena/stats— tracked/scored lobbies, players seen, and tracking start. 1 credit.GET /api/arena/watched— upstream tracked lobbies (shared feed, not an account-specific list). 1 credit.
curl -H "X-API-Key: your_duelapi_read_key" \
"https://api.duelapi.com/api/arena/lobbies?status=waiting&limit=100"
Statistics accumulate from the source’s tracking start; they are not lifetime arena totals. wagered_usd includes USD pots only. Other currencies stay in history without conversion. Missing cross-data means the source has no matching data yet. Duel usernames identify the same account across arena, casino, high scores, and RPS. Sportsbook odds have no per-user data.
The existing /players/{username} casino high-score endpoint also passes through the source’s new arena statistics when available.
A waiting lobby can be full: check player_count < max_players before offering Join. Active games are already playing. Unknown or expired codes return 404; temporary feed errors return 502. An exact expiration timestamp is shown only when the source supplies one.
Credits & Limits
Every successful request costs credits from your key's balance. Failed requests (4xx and 5xx) cost nothing. Your plan's monthly credits refill every 30 days; top-ups are used after them and last 12 months. Keys created before credits existed keep unlimited access.
What each request costs
- 1 credit:
/crash/last,/roulette/last,/players,/players/{username},/bets/games,/data/status - 1 credit per 100 rows requested:
/crash/recent,/roulette/recent,/bets/recent,/crash/bets,/roulette/bets,/chat/recent,/rps/recent(for examplelimit=500costs 5) - 2 credits:
/crash/rounds/{round},/roulette/rounds/{round} - 5 credits:
/crash/stats,/roulette/stats,/bets/stats,/analytics/overview - Sports (full market books from the sportsbook, so priced higher):
/v4/sports2,/v4/sports/{sport}/events5,/v4/sports/{sport}/scores5,/v4/events/{id}10,/v4/events/{id}/history25, and/v4/sports/{sport}/odds5 per event, charged onlimit(the default 25 events costs 125) - 500 credits: the full-history dumps
/crash,/roulette,/spins. Page through/recentinstead where you can. - WebSocket: 1.5 credits per round result pushed on
crashorcastle, and 1 credit per 2 events onodds_events, and 1 credit per 5 events on every other channel (bets,crash.bets,castle.bets,chat,rps). Requests sent over the socket cost the same as REST. Roughly: streaming crash and castle results all month uses about 240,000 credits (Starter), adding their bets about 1.2M (Pro), and the all-games bet feed about 2M (Scale). The sports event stream runs about 1–5M credits a month depending on how busy the fixtures are. - Free:
/accountand/health
Response headers
X-Credits-Cost: 5
X-Credits-Remaining: 1499995
Out of credits
A request that costs more than you have left returns 402:
{
"error": "out_of_credits",
"message": "This request costs 5 credits and 3 are left on your free plan.",
"credits_remaining": 3,
"resets_at": "2026-10-23T12:16:29.390Z",
"top_up": "https://api.duelapi.com/subscribe",
"upgrade": "https://api.duelapi.com/#pricing"
}
On the WebSocket you'll get {"type":"error","code":"out_of_credits"} and the socket closes with code 4402.
Rate limits
- Free: 10 requests per minute
- Starter: 60 per minute
- Pro: 300 per minute
- Scale: 1,200 per minute
Going over returns 429 with a Retry-After header.
GET/account
Your key's plan, credit balance, refill date and rate limit. Costs nothing.
API key required
Example Response:
{
"plan": "pro",
"credits": {
"remaining": 1482310,
"monthly_remaining": 1482310,
"monthly_allowance": 1500000,
"topups_remaining": 0,
"resets_at": "2026-10-23T12:16:29.390Z"
},
"rate_limit_per_minute": 300,
"subscription": { "active": true, "renews_or_expires_at": "2026-10-23T12:16:00.000Z" },
"requests_total": 17690
}
Endpoints
GET/health
Check API status and get basic statistics. Rate limited to 60 requests per minute per IP.
No authentication required
Example Request:
curl https://api.duelapi.com/health
Example Response:
{
"status": "ok",
"uptime": 12345.67,
"totalSpins": 150,
"totalRoulette": 120,
"totalCrashes": 30
}
GET/crash/recent
Get the most recent crash game rounds.
API key required
Query Parameters:
limit(optional): Number of crashes to return (default: 10, max: 10,000)page(optional): Page number for pagination (default: 0). Each page contains up tolimititems.
Pagination:
- Page 0: Items 0 to
limit(most recent) - Page 1: Items
limitto2*limit - Page 2: Items
2*limitto3*limit
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/crash/recent?limit=5"
Example Response:
{
"total": 150,
"limit": 5,
"page": 0,
"totalPages": 30,
"hasMore": true,
"range": {
"start": 0,
"end": 5
},
"recent": [
{
"game": "crash",
"round": 455814,
"multiplier": 1.60,
"timestamp": 1765481292567,
"isoTimestamp": "2025-12-11T20:12:31.815Z",
"state": "crashed",
"nextRound": 455815
}
]
}
GET/roulette/recent
Get the most recent roulette spins.
API key required
Query Parameters:
limit(optional): Number of spins to return (default: 10, max: 10,000)page(optional): Page number for pagination (default: 0). Each page contains up tolimititems.
Pagination:
- Page 0: Items 0 to
limit(most recent) - Page 1: Items
limitto2*limit - Page 2: Items
2*limitto3*limit
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/roulette/recent?limit=5"
Example Response:
{
"total": 35000,
"rouletteCount": 200,
"limit": 5,
"page": 0,
"totalPages": 40,
"hasMore": true,
"range": {
"start": 0,
"end": 5
},
"recent": [
{
"game": "roulette",
"multiplier": 2,
"coinName": "Red",
"timestamp": 1765481292567,
"isoTimestamp": "2025-12-11T20:12:31.815Z"
}
]
}
GET/crash/last
Get the most recent crash game.
API key required
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/crash/last"
GET/roulette/last
Get the most recent roulette spin.
API key required
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/roulette/last"
GET/crash/stats
Get comprehensive statistics about crash games.
API key required
Example Response:
{
"total": 150,
"averageMultiplier": 2.45,
"minMultiplier": 1.01,
"maxMultiplier": 10.23,
"byMultiplier": {
"1.5": 20,
"2.0": 15
}
}
Castle Roulette Details
Every castle roulette round in /roulette/recent and /roulette/last now includes the round number, winning coin, the winning roll, the roll history and the provably-fair seed.
GET/roulette/stats
Hit counts per coin over the last N rounds, the observed hit rate next to the expected rate, and how many rounds since each coin last hit.
API key required
Query Parameters:
rounds(optional): rounds to analyse (default 1,000, max 100,000)
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/roulette/stats?rounds=500"
Example Response:
{
"rounds": 500,
"coins": [
{
"coin": "two",
"name": "Red",
"multiplier": 2,
"hits": 233,
"observed_rate": 0.466,
"expected_rate": 0.5,
"rounds_since_last": 0
}
]
}
Casino Bets
Every casino bet seen on Duel.com across all games (slots, castle, dice, limbo, plinko, crash, keno, mines, blackjack and more). Coins are pegged 1:1 to USD.
GET/bets/recent
The most recent bets, newest first.
API key required
Query Parameters:
limit(optional): bets per page (default 50, max 1,000)page(optional): page number (default 0)game(optional): filter by game, e.g.crash,slots,castleplayer(optional): filter by usernamemin_usd(optional): minimum wager in USDfeed(optional):highrollersfor Duel's high-roller feed only
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/bets/recent?game=crash&min_usd=50&limit=10"
Example Response:
{
"total": 12332,
"limit": 10,
"page": 0,
"hasMore": true,
"items": [
{
"id": "1348548716",
"ts": "2026-09-23T11:21:20Z",
"game": "CRASH",
"type": "crash_round_bet",
"player": "SNapp",
"player_id": 4911510,
"wager": 100,
"won": 0,
"multiplier": 0,
"wager_usd": 100,
"won_usd": 0,
"currency": 106,
"feed": "all",
"extra": { "round": 1328473, "auto_cashout": null }
}
]
}
Notes:
extraholds game-specific detail when available (for example the crash round).- The default feed is Duel's unfiltered feed. High-roller bets can also appear there, so don't add the two feeds together.
GET/bets/stats
Totals for a recent time window: bet count, unique players, wagered, paid out, house profit, RTP, biggest win, and a per-game breakdown.
API key required
Query Parameters:
minutes(optional): window size (default 60, max 1,440)game(optional): limit to one game
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/bets/stats?minutes=60"
Example Response:
{
"window_minutes": 60,
"bets": 12000,
"unique_players": 435,
"wagered_usd": 45415.03,
"won_usd": 33065.96,
"house_profit_usd": 12349.07,
"rtp": 0.7281,
"biggest_win": { "player": "David Wang", "game": "CASTLE", "won_usd": 1055.89, "multiplier": 24 },
"by_game": [
{ "game": "SLOTS", "bets": 2400, "wagered_usd": 20548.55, "won_usd": 10601.61, "rtp": 0.5159 }
]
}
GET/bets/games
Every game with bets on the feed, busiest first: bets stored, bets in the last hour and the time of the latest bet. Use a game value with /bets/recent?game=.
API key required
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/bets/games"
Example Response:
[
{ "game": "castle", "bets_stored": 8615, "bets_last_hour": 6284, "last_bet_at": "2026-09-23T11:58:15Z" },
{ "game": "slots", "bets_stored": 4177, "bets_last_hour": 2703, "last_bet_at": "2026-09-23T11:58:19Z" },
{ "game": "crash", "bets_stored": 907, "bets_last_hour": 661, "last_bet_at": "2026-09-23T11:57:47Z" }
]
GET/crash/bets
The latest crash bets, newest first. Same shape as /bets/recent; extra.round is the crash round the bet was placed on.
API key required
Query Parameters:
limit(optional): bets per page (default 50, max 1,000)page(optional): page number (default 0)
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/crash/bets?limit=20"
GET/roulette/bets
The latest castle roulette bets, newest first. extra.coin is the coin bet on and extra.round the round. Also available as /castle/bets.
API key required
Query Parameters:
limit(optional): bets per page (default 50, max 1,000)page(optional): page number (default 0)
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/roulette/bets?limit=20"
Players
Duel.com's public high-score table: about 63,000 players with lifetime wagered, profit, deposits, withdrawals and ranks.
GET/players
The leaderboard, sorted by profit or by amount wagered.
API key required
Query Parameters:
sort(optional):profit(default) orwageredorder(optional):desc(default) orasclimit(optional): rows per page (default 50, max 200)offset(optional): rows to skip
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/players?sort=wagered&limit=10"
Example Response:
{
"total": 63085,
"rows": [
{
"username": "jarik",
"wagered": 1001983676.88,
"profit": 12341874.77,
"deposits": 46780486.44,
"withdrawals": 59213283.85,
"rank_profit": 1,
"rank_wagered": 2
}
]
}
GET/players/{username}
One player's lifetime stats, plus their last 50 bets and a summary of those bets.
API key required
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/players/SNapp"
Example Response:
{
"username": "SNapp",
"wagered": 479671.26,
"profit": -8588.88,
"rank_wagered": 2946,
"recent_bets": [ ... ],
"recent_bets_summary": { "bets": 50, "wagered_usd": 3120.5, "rtp": 0.91 }
}
Chat & Rock-Paper-Scissors
GET/chat/recent
Duel.com public chat messages, newest first.
API key required
Query Parameters:
limit(optional): messages per page (default 50, max 1,000)page(optional): page numberroom(optional): chat room iduser(optional): display name
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/chat/recent?limit=20"
Example Response:
{
"total": 19298,
"items": [
{
"id": "0b4dd649-2168-4216-9ace-cdac54917036",
"ts": "2026-09-23T11:17:24Z",
"room": "0",
"user_id": 5441027,
"name": "malibuca12",
"message": "gg",
"reply_to": null,
"level": 0,
"mentions": []
}
]
}
Notes:
- Messages are passed through unedited from Duel.com's public chat.
GET/rps/recent
Rock-paper-scissors rounds with their match details. winner_id: null means a draw.
API key required
Query Parameters:
limit(optional): rounds per page (default 50, max 1,000)page(optional): page number
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/rps/recent?limit=10"
Example Response:
{
"items": [
{
"match_id": 177568,
"round": 8,
"creator_choice": "scissors",
"challenger_choice": "rock",
"winner_id": 5640877,
"match": {
"creator_name": "i_keep_trying",
"challenger_name": "Seby22",
"amount_coins": 0
}
}
]
}
Analytics
GET/analytics/overview
One call for a dashboard: crash distribution, castle coin frequencies, the last hour of betting, chat activity and data-source health.
API key required
Query Parameters:
rounds(optional): crash and castle rounds to analyse (default 1,000)
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/analytics/overview"
Example Response:
{
"crash": {
"rounds": 1000,
"average": 7.65,
"median": 1.96,
"max": 888.71,
"share_at_or_above": { "1.5x": 0.664, "2x": 0.492, "5x": 0.199, "10x": 0.089, "100x": 0.009 }
},
"castle_roulette": { "rounds": 1000, "coins": [ ... ] },
"bets_last_hour": { "bets": 12000, "wagered_usd": 45415.03, "rtp": 0.7281, ... },
"chat_last_hour": { "messages": 812 },
"rps_matches_tracked": 405,
"data_source": { "odds": "ok", "last_webhook_delivery": "2026-09-23T11:21:06Z" }
}
GET/data/status
Health of the data feed: whether the source is reachable, when data last arrived, and how much of each type is stored.
API key required
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/data/status"
Round Details
A round's result together with everyone who bet on it. Bets are kept for about the last day.
GET/crash/rounds/{round}
One crash round: the bust multiplier, every bet on it and the round totals.
API key required
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/crash/rounds/1328549"
Example Response:
{
"round": { "game": "crash", "round": 1328549, "multiplier": 9.71, "isoTimestamp": "2026-09-23T11:57:42.000Z" },
"summary": {
"bets": 7,
"players": 7,
"wagered_usd": 6.25,
"paid_out_usd": 1.04,
"player_pnl_usd": -5.22,
"pending_bets": 0
},
"bets": [
{ "player": "Seby22", "player_id": 5640877, "wager_usd": 0.2005, "won_usd": 0.0025,
"multiplier": 1.44, "status": "settled", "auto_cashout": null, "ts": "2026-09-23T11:57:02Z" }
]
}
Notes:
statusispendinguntil the cash-out result arrives, usually within a few seconds of the round ending.
GET/roulette/rounds/{round}
One castle roulette round: the winning coin, rolls and seed, every bet with its coin, and the amount wagered on each coin. Also available as /castle/rounds/{round}.
API key required
Example Request:
curl -H "X-API-Key: your_key" \
"https://api.duelapi.com/roulette/rounds/982632"
Example Response:
{
"round": { "game": "roulette", "round": 982632, "coin": "eight", "coinName": "Purple", "multiplier": 8,
"winner": "12", "rolls": [12, 31, 28, 44, 26], "seed": "6b00e18c..." },
"summary": {
"bets": 71,
"players": 6,
"wagered_usd": 89.1,
"paid_out_usd": 69.15,
"player_pnl_usd": -19.95,
"pending_bets": 0,
"by_coin": [ { "coin": "four", "bets": 22, "wagered_usd": 64.39 } ]
},
"bets": [
{ "player": "Floppyfino", "wager_usd": 0.4552, "won_usd": 0, "multiplier": 4,
"coin": "four", "status": "settled_from_round", "ts": "2026-09-23T11:57:40Z" }
]
}
Notes:
settled_from_roundmeans the payout was worked out from the winning coin: a bet on the winning coin pays its multiplier, every other bet pays 0.
WebSocket API
Get crash results, castle rounds, bets, chat and sports events pushed to you the moment they happen, instead of polling. The same socket also answers REST-style requests.
URL: wss://api.duelapi.com/ws?apiKey=your_key
API key required
Connection
// Server, on connect
{ "type": "welcome",
"channels": ["crash", "castle", "roulette", "bets", "crash.bets", "castle.bets", "roulette.bets", "chat", "rps", "odds_events"],
"limits": { "connections_per_key": 5, "subscriptions": 20, "messages_per_second": 20 } }
// Bad or missing key: an error message, then the socket closes with code 4001
Channels
crash: every crash round as it busts (same shape as/crash/last)castle(orroulette): every castle roulette result, with coin, rolls and seedbets: every casino bet, all games. Filter withgame,player,min_usdandfeedcrash.bets,castle.bets(orroulette.bets): bets on one gamechat: public chat messagesrps: rock-paper-scissors roundsodds_events: sports events going live, changing status or score
Subscribe and receive
// You send
{ "op": "subscribe", "channel": "crash" }
{ "op": "subscribe", "channel": "bets", "filters": { "game": "castle", "min_usd": 50 } }
// Server confirms
{ "type": "subscribed", "channel": "crash", "ok": true }
// Then pushes events
{ "type": "event", "channel": "crash",
"data": { "game": "crash", "round": 1328550, "multiplier": 6.45, "isoTimestamp": "2026-09-23T11:58:21.000Z" } }
{ "type": "event", "channel": "bets",
"data": { "id": "55789202083150", "game": "CASTLE", "player": "dvxu021", "wager_usd": 54.18,
"multiplier": 48, "status": "pending", "extra": { "round": 982630, "coin": "forty_eight" } } }
// Stop
{ "op": "unsubscribe", "channel": "crash" }
Requests over the socket
Send get with any data endpoint's path and query. The reply carries your id, the HTTP status and the same body the REST endpoint returns.
Request and response
// You send
{ "op": "get", "id": "r1", "path": "/crash/recent", "query": { "limit": 5 } }
// Server replies
{ "type": "response", "id": "r1", "status": 200, "data": { "total": 55166, "recent": [ ... ] } }
// Keepalive
{ "op": "ping", "id": "p1" } -> { "type": "pong", "id": "p1", "time": "2026-09-23T11:58:22Z" }
Notes:
- Bet events have
status:pendingwhen placed, and crash bets are sent again assettledonce cashed out. The same bet can arrive more than once, so dedupe onid. - Castle bets aren't re-sent. Work out the result from the round on the
castlechannel (a bet on the winning coin pays its multiplier) or call/roulette/rounds/{round}. - Streaming uses credits: 1.5 per round result on
crashandcastle, 1 per 2 events onodds_events, 1 per 5 events on other channels. See Credits & Limits. When credits run out you getout_of_creditsand the socket closes with code4402. - Limits: 5 connections per key, 20 subscriptions per connection, 20 messages per second you send. The server pings every 30 seconds; standard WebSocket clients answer automatically.
- If your client falls far behind, events are dropped rather than queued. Reconnect and use the REST endpoints to fill any gap.
JavaScript (Node or browser)
const ws = new WebSocket('wss://api.duelapi.com/ws?apiKey=your_api_key_here');
ws.onopen = () => {
ws.send(JSON.stringify({ op: 'subscribe', channel: 'crash' }));
ws.send(JSON.stringify({ op: 'subscribe', channel: 'castle.bets', filters: { min_usd: 25 } }));
};
ws.onmessage = (msg) => {
const m = JSON.parse(msg.data);
if (m.type === 'event' && m.channel === 'crash') {
console.log(`Round ${m.data.round} crashed at ${m.data.multiplier}x`);
}
if (m.type === 'event' && m.channel === 'castle.bets') {
console.log(`${m.data.player} bet $${m.data.wager_usd} on ${m.data.extra.coin}`);
}
};
Python
import asyncio, json, websockets
async def main():
url = 'wss://api.duelapi.com/ws?apiKey=your_api_key_here'
async with websockets.connect(url) as ws:
await ws.send(json.dumps({'op': 'subscribe', 'channel': 'crash'}))
await ws.send(json.dumps({'op': 'get', 'id': 'last', 'path': '/crash/last'}))
async for raw in ws:
m = json.loads(raw)
if m['type'] == 'event':
print('crash', m['data']['round'], m['data']['multiplier'])
elif m['type'] == 'response':
print('reply', m['id'], m['status'])
asyncio.run(main())
Sports Betting Odds API
Live and prematch odds from Duel.com's sportsbook in an Odds-API compatible format, read live from the sportsbook with a few seconds of caching.
Base URL: https://api.duelapi.com/v4 or https://api.duelapi.com/odds/v4
Authentication: All endpoints require a Read API key, sent as the X-API-Key header or as ?apiKey=your_key.
Odds API Endpoints
GET/v4/sports
Every sport currently offered, with event and live-event counts. Use key in the endpoints below.
API key required
Example Request:
curl "https://api.duelapi.com/v4/sports?apiKey=your_key"
Example Response:
[
{
"key": "soccer",
"group": "Soccer",
"title": "Soccer",
"description": "937 events, 20 live",
"active": true,
"has_outrights": false,
"events": 937,
"live_events": 20
}
]
GET/v4/sports/{sport}/events
Events for a sport without odds. Live events come first, then upcoming ones by kickoff.
API key required
Query Parameters:
live(optional):1live only,0upcoming only
Example Request:
curl "https://api.duelapi.com/v4/sports/soccer/events?apiKey=your_key"
Example Response:
[
{
"id": "2714471436365475875",
"sport_key": "soccer",
"sport_title": "Soccer",
"commence_time": "2026-09-23T09:30:00Z",
"home_team": "Mohun Bagan Super Giant",
"away_team": "Sreenidi Deccan FC",
"tournament": "IFA Shield",
"live": true,
"status": "1st period",
"scores": { "home": "4", "away": "0" },
"markets_count": 18,
"duel_url": "https://duel.com/sports?bt-path=..."
}
]
GET/v4/sports/{sport}/odds
Events with their full market books: every market, outcome and price.
API key required
Query Parameters:
live(optional):1live only,0upcoming onlylimit(optional): events per request (default 25, max 100)offset(optional): events to skip, for paging
Example Request:
curl "https://api.duelapi.com/v4/sports/soccer/odds?live=1&limit=10&apiKey=your_key"
Example Response:
[
{
"id": "2714471436365475875",
"home_team": "Mohun Bagan Super Giant",
"away_team": "Sreenidi Deccan FC",
"live": true,
"bookmakers": [
{
"key": "duel",
"title": "Duel",
"last_update": "2026-09-23T11:21:02Z",
"markets": [
{
"key": "m_18_total=4.5",
"title": "Total (4.5)",
"outcomes": [
{ "name": "over 4.5", "price": 1.9, "open_price": 2.05, "move": -0.15 },
{ "name": "under 4.5", "price": 1.85, "open_price": 1.72, "move": 0.13 }
]
}
]
}
]
}
]
Notes:
- Suspended or withdrawn outcomes are left out.
- A freshly listed event can show only its main markets for a short while until the full book loads.
GET/v4/sports/{sport}/scores
Live events for a sport with their current status and score.
API key required
Example Request:
curl "https://api.duelapi.com/v4/sports/tennis/scores?apiKey=your_key"
GET/v4/events/{eventId}
One event's full market book.
API key required
Example Request:
curl "https://api.duelapi.com/v4/events/2714471436365475875?apiKey=your_key"
GET/v4/events/{eventId}/history
Every recorded price change for one event, oldest first. Page with next_cursor passed back as after. Kept for 3 days.
API key required
Query Parameters:
from, to(optional): time range, ISO 8601 or unix secondsafter(optional): cursor from the previous responselimit(optional): changes per page (default 500, max 1,000)
Example Request:
curl "https://api.duelapi.com/v4/events/2714471436365475875/history?apiKey=your_key"
Code Examples
Want to try a request first? The playground sends real requests with your key and writes this code for you.
JavaScript - Crash/Roulette
const apiKey = 'your_api_key_here';
const response = await fetch(
'https://api.duelapi.com/crash/recent?limit=10',
{
headers: {
'X-API-Key': apiKey
}
}
);
const data = await response.json();
console.log(data.recent);
JavaScript - Sports Odds
const apiKey = 'your_api_key_here';
// Get available sports
const sportsResponse = await fetch(
`https://api.duelapi.com/v4/sports?apiKey=${apiKey}`
);
const sports = await sportsResponse.json();
console.log('Available sports:', sports);
// Get odds for a specific sport
const oddsResponse = await fetch(
`https://api.duelapi.com/v4/sports/soccer/odds?apiKey=${apiKey}`
);
const odds = await oddsResponse.json();
console.log('Odds:', odds);
Python - Crash/Roulette
import requests
api_key = 'your_api_key_here'
headers = {'X-API-Key': api_key}
response = requests.get(
'https://api.duelapi.com/crash/recent?limit=10',
headers=headers,
timeout=60
)
data = response.json()
print(data['recent'])
Python - Sports Odds
import requests
api_key = 'your_api_key_here'
# Get available sports
sports_response = requests.get(
f'https://api.duelapi.com/v4/sports?apiKey={api_key}'
)
sports = sports_response.json()
print('Available sports:', sports)
# Get odds for a specific sport
odds_response = requests.get(
f'https://api.duelapi.com/v4/sports/soccer/odds?apiKey={api_key}'
)
odds = odds_response.json()
print('Odds:', odds)
cURL - Crash/Roulette
curl -H "X-API-Key: your_api_key_here" \
"https://api.duelapi.com/crash/recent?limit=10"
cURL - Sports Odds
# Get sports list
curl "https://api.duelapi.com/v4/sports?apiKey=your_api_key_here"
# Get odds for a sport
curl "https://api.duelapi.com/v4/sports/soccer/odds?apiKey=your_api_key_here"