Skip to main content
GET
/
arbitrage
/
current
Cross-venue arbitrage
curl --request GET \
  --url https://api.oddpool.com/arbitrage/current
Find markets where buying YES on one venue and NO on another costs less than 1 dollar combined. The gap is risk-free profit. Prices and order books are live — recomputed continuously from real-time venue WebSocket feeds (Kalshi, Polymarket, Opinion), not a periodic snapshot.
Example: “Will the Fed cut rates?” — YES is 32c on Kalshi, NO is 60c on Polymarket. Buy both for 92c, locking in an 8c gross spread. After ~3c in venue fees (Kalshi taker + Polymarket taker), you pocket about 5c per contract guaranteed.

Parameters

min_net_cents
float
default:"0"
Minimum net profit after fees, in cents.
orderbook
boolean
default:"false"
When true, attaches each leg’s live ask ladder (top 25 levels) under orderbook, so you can size an order without a second call.
minutes
integer
deprecated
Deprecated and ignored. The legacy endpoint used it as a staleness window; the live cache is always current, so it has no effect. Accepted only for backwards compatibility.

Example

curl -H "X-API-Key: your_api_key" \
  "https://api.oddpool.com/arbitrage/current?min_net_cents=0.5&orderbook=true"

Response

A JSON array of opportunities, sorted by net_cents (highest first). An empty array means there are no current opportunities at or above your threshold. net_cents is your per-contract profit after all fees. The opportunity tells you the trade directly: buy YES on buy_yes_market, buy NO on buy_no_market. yes_leg / no_leg give the exact (market, identifier, book_side) to hit for each side. gross_cents / fee_cents / net_cents are the top-of-book economics (per contract): net_cents = round((1 − (best_yes_ask + best_no_ask)) × 100) − fees. executable_size and max_profit_dollars are the depth-aware answer to “how much can I actually take, and what’s it worth?” — they walk both legs’ ask ladders together: at each price level they fill the smaller of the two available sizes, add (level_net_after_fees / 100) × size to the profit, and advance until a level pair is no longer profitable after fees (or the ladders run out). So executable_size is the total fillable contracts and max_profit_dollars the summed profit across all profitable levels.
max_profit_dollars is a conservative floor, not a guarantee. It only considers the top 25 levels, so true fillable depth beyond that isn’t counted. Fees are applied per level using the same per-venue rates as net_cents (Kalshi sector taker, Polymarket per-market feeSchedule.rate, Opinion topic rate + floor). It does not model slippage from latency, partial fills, or order-placement minimums — size against executable_size and the attached orderbook, not blindly.
Each venue block includes execution-ready identifiers you can pass directly to the venue’s trading API:
  • Kalshimarket_ticker is the ticker accepted by Kalshi’s trade API.
  • Polymarketcondition_id is the on-chain condition; yes_token_id / no_token_id are the CLOB token IDs for placing orders.
  • Opinionchild_market_id is the categorical child market ID; yes_token_id / no_token_id are the trading-side token IDs.
Prices and order books are real-time; volume and liquidity refresh roughly hourly. Opinion does not expose 24h volume or liquidity, so volume_24h and liquidity are null for Opinion legs. timestamp is when the opportunity was last recomputed.
[
  {
    "event_id": "stanley-cup-2026",
    "event_title": "NHL Stanley Cup Champion 2026",
    "outcome_key": "colorado_avalanche",
    "label": "Colorado Avalanche",
    "timestamp": "2026-05-26T02:21:54.190359",
    "market_type": null,
    "resolution_time": "2026-06-29T19:00:00",
    "kalshi_event_ticker": "KXNHL-26",
    "polymarket_event_slug": "2026-nhl-stanley-cup-champion",
    "opinion_market_id": 345,
    "kalshi": {
      "market_ticker": "KXNHL-26-COL",
      "yes_ask": 0.07, "no_ask": 0.95,
      "volume": 6352005, "volume_24h": 320871,
      "open_interest": 3146772
    },
    "polymarket": {
      "condition_id": "0xf8f63bb47b2a7c2e0c1be3cedf4075079b11c07476d76a9469065b0c4791961a",
      "yes_token_id": "101738487887518832481587379955535423775326921556438741919099866785354159699479",
      "no_token_id": "87978082071653935678874296685430503892266481242311708420787197372467948088235",
      "yes_ask": 0.055, "no_ask": 0.948,
      "volume": 15219511.07, "volume_24h": 215850.28,
      "liquidity": 50818.82
    },
    "opinion": {
      "child_market_id": 5566,
      "yes_token_id": "109494079162951671873858278805080808339824558282001815297323400464995130701684",
      "no_token_id": "74166100071861466695478367383768425561540521028754831523233794115776851950059",
      "yes_ask": 0.21, "no_ask": 0.782,
      "volume": 38765.84, "volume_24h": null, "liquidity": null
    },
    "buy_yes_market": "polymarket",
    "buy_no_market": "opinion",
    "gross_cents": 16.3,
    "fee_cents": 2,
    "net_cents": 14.3,
    "executable_size": 97.87,
    "max_profit_dollars": 13.94,
    "yes_leg": { "market": "polymarket", "identifier": "101738487887518832481587379955535423775326921556438741919099866785354159699479", "book_side": "ask" },
    "no_leg":  { "market": "opinion",    "identifier": "74166100071861466695478367383768425561540521028754831523233794115776851950059", "book_side": "ask" },
    "orderbook": {
      "as_of": "2026-05-26T02:21:47.062741",
      "yes": {
        "market": "polymarket",
        "asks": [
          { "price": 0.055, "size": 42.97 },
          { "price": 0.056, "size": 14989.0 }
        ]
      },
      "no": {
        "market": "opinion",
        "asks": [
          { "price": 0.782, "size": 97.87 }
        ]
      }
    }
  }
]
orderbook is only present when you pass orderbook=true. It carries the top 25 ask levels per leg — ask side only (the price ladder to buy that outcome).