Reference

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 accepts code and optional slug. 1 credit.
  • GET /api/arena/lobbies?status=waiting&sort=recent&limit=100 — live lobbies. Optional game; status accepts live, all, waiting, active, completed, expired, cancelled; sort accepts recent, high, low. limit is 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-effort cross.highscores and cross.rps data. 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 example limit=500 costs 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/sports 2, /v4/sports/{sport}/events 5, /v4/sports/{sport}/scores 5, /v4/events/{id} 10, /v4/events/{id}/history 25, and /v4/sports/{sport}/odds 5 per event, charged on limit (the default 25 events costs 125)
  • 500 credits: the full-history dumps /crash, /roulette, /spins. Page through /recent instead where you can.
  • WebSocket: 1.5 credits per round result pushed on crash or castle, and 1 credit per 2 events on odds_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: /account and /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 to limit items.

Pagination:

  • Page 0: Items 0 to limit (most recent)
  • Page 1: Items limit to 2*limit
  • Page 2: Items 2*limit to 3*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 to limit items.

Pagination:

  • Page 0: Items 0 to limit (most recent)
  • Page 1: Items limit to 2*limit
  • Page 2: Items 2*limit to 3*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, castle
  • player (optional): filter by username
  • min_usd (optional): minimum wager in USD
  • feed (optional): highrollers for 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:

  • extra holds 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) or wagered
  • order (optional): desc (default) or asc
  • limit (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 number
  • room (optional): chat room id
  • user (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:

  • status is pending until 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_round means 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 (or roulette): every castle roulette result, with coin, rolls and seed
  • bets: every casino bet, all games. Filter with game, player, min_usd and feed
  • crash.bets, castle.bets (or roulette.bets): bets on one game
  • chat: public chat messages
  • rps: rock-paper-scissors rounds
  • odds_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: pending when placed, and crash bets are sent again as settled once cashed out. The same bet can arrive more than once, so dedupe on id.
  • Castle bets aren't re-sent. Work out the result from the round on the castle channel (a bet on the winning coin pays its multiplier) or call /roulette/rounds/{round}.
  • Streaming uses credits: 1.5 per round result on crash and castle, 1 per 2 events on odds_events, 1 per 5 events on other channels. See Credits & Limits. When credits run out you get out_of_credits and the socket closes with code 4402.
  • 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): 1 live only, 0 upcoming 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): 1 live only, 0 upcoming only
  • limit (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 seconds
  • after (optional): cursor from the previous response
  • limit (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"