Developer API

Build on the CrossOdds feed

One REST endpoint. Live arbitrage opportunities, whale trade signals, and weather edge alerts across Kalshi and Polymarket — ready for your bots, alerts, and trading dashboards.

60 req / min·Up to 10 keys·Arb + whale + weather filtering
01

Endpoint

GEThttps://www.crossodds.app/api/v1/opportunities
AuthorizationBearer xo_live_<key>

General

?type"all" (default: arbs + whales) | "arb" | "whales" | "weather"
?limitinteger 1–500, default 500

⚡ Arb filters

?sort"spread" (default) | "quality" | "detected"
?minSpreaddecimal 0–1, e.g. 0.02 for ≥ 2% spread
?maxSpreaddecimal 0–1
?minQualityinteger 0–100, e.g. 75 for high-confidence only
?arbType"yes/no" | "no/yes" | "yes/yes" | "no/no"

🐋 Whale filters

?platform"kalshi" | "polymarket"
?side"yes" | "no"
?minSizedollars, e.g. 25000 for ≥ $25k trades
?hours1 | 6 | 12 (default 12)
?leaderboardOnly"true" — only Polymarket top-50 trader trades

🌤 Weather filters (type=weather)

?minEdgedecimal 0–1, default 0.05. e.g. 0.10 for ≥ 10% edge
?weatherPlatform"kalshi" | "polymarket"
?metric"temperature_max" | "temperature_min" | "precipitation" | "snowfall" | "wind_speed"
?direction"buy_yes" | "buy_no"
02

Examples

curl
# Arb opportunities only
curl "https://www.crossodds.app/api/v1/opportunities?type=arb" \
  -H "Authorization: Bearer xo_live_<your-key>"

# Whale trades only — large Polymarket trades in last 6 hours
curl "https://www.crossodds.app/api/v1/opportunities?type=whales&platform=polymarket&minSize=25000&hours=6" \
  -H "Authorization: Bearer xo_live_<your-key>"

# Weather edges — forecast vs. market mispricing
curl "https://www.crossodds.app/api/v1/opportunities?type=weather&minEdge=0.10" \
  -H "Authorization: Bearer xo_live_<your-key>"

# Arbs + whales (default) — high-confidence arbs + top-50 leaderboard whales
curl "https://www.crossodds.app/api/v1/opportunities?minQuality=80&leaderboardOnly=true" \
  -H "Authorization: Bearer xo_live_<your-key>"
python
import httpx

# Arb opportunities only, sorted by confidence
arb_data = httpx.get(
    "https://www.crossodds.app/api/v1/opportunities",
    headers={"Authorization": "Bearer xo_live_<your-key>"},
    params={"type": "arb", "sort": "quality", "minQuality": 75},
).json()
arbs = arb_data["arbs"]

# Whale trades only
whale_data = httpx.get(
    "https://www.crossodds.app/api/v1/opportunities",
    headers={"Authorization": "Bearer xo_live_<your-key>"},
    params={"type": "whales", "platform": "polymarket", "minSize": 10000, "hours": 6},
).json()
whales = whale_data["whales"]

# Weather edges — ensemble forecast vs. market odds
weather_data = httpx.get(
    "https://www.crossodds.app/api/v1/opportunities",
    headers={"Authorization": "Bearer xo_live_<your-key>"},
    params={"type": "weather", "minEdge": 0.10, "metric": "temperature_max"},
).json()
edges = weather_data["weather"]
javascript
// Arb only — highest spread first
const arbs = await fetch(
  "https://www.crossodds.app/api/v1/opportunities?type=arb&sort=spread",
  { headers: { Authorization: "Bearer xo_live_<your-key>" } }
).then(r => r.json()).then(d => d.arbs);

// Whale only — top-50 leaderboard trades
const whales = await fetch(
  "https://www.crossodds.app/api/v1/opportunities?type=whales&leaderboardOnly=true",
  { headers: { Authorization: "Bearer xo_live_<your-key>" } }
).then(r => r.json()).then(d => d.whales);

// Weather edges — forecast mispricing
const edges = await fetch(
  "https://www.crossodds.app/api/v1/opportunities?type=weather&minEdge=0.10",
  { headers: { Authorization: "Bearer xo_live_<your-key>" } }
).then(r => r.json()).then(d => d.weather);
03

Response

JSON object with two keys: arbs (arbitrage opportunities, sorted by spread) and whales (large trades from the last 12h, sorted by recency).

json
{
  "arbs": [
    {
      "id": 1842,
      "question": "Will the Fed cut rates in June?",
      "polyQuestion": "Federal Reserve rate cut - June 2025?",
      "kalshiId": "FED-25JUN-RATECUT",
      "polyId": "0x9f2b...",
      "arbType": "yes/no",
      "spreadPct": 3.4,
      "netSpreadPct": 2.8,
      "qualityScore": 91.0,
      "kalshiOdds": { "yesBid": 0.61, "yesAsk": 0.63, "noBid": 0.37, "noAsk": 0.39 },
      "polyOdds":   { "yesBid": 0.35, "yesAsk": 0.37, "noBid": 0.63, "noAsk": 0.65 },
      "clobTokenIds": ["71321...", "29847..."],
      "detectedAt": "2025-06-01T14:22:31Z",
      "warnings": []
    }
  ],
  "whales": [
    {
      "id": 908,
      "platform": "polymarket",
      "marketId": "0xabc123...",
      "tradeId": "0xtxhash...",
      "size": 75000,
      "price": 0.38,
      "side": "yes",
      "takerSide": null,
      "marketQuestion": "Will the Fed cut rates in June?",
      "marketUrl": "https://polymarket.com/event/fed-rate-cut-june",
      "tradeTimestamp": "2025-06-01T13:55:00Z",
      "detectedAt": "2025-06-01T13:55:12Z"
    }
  ],
  "weather": [
    {
      "id": 312,
      "platform": "kalshi",
      "marketId": "KXHIGHNY-26APR10-T68",
      "question": "Will the high temperature in NYC exceed 68°F on April 10?",
      "locationName": "New York City, Central Park",
      "metric": "temperature_max",
      "threshold": ">68°F",
      "thresholdValue": 68,
      "thresholdValueUpper": null,
      "thresholdUnit": "F",
      "thresholdOp": "gt",
      "targetDate": "2026-04-10",
      "resolutionSource": "NOAA",
      "marketUrl": "https://kalshi.com/markets/KXHIGHNY",
      "marketYesPrice": 0.42,
      "marketNoPrice": 0.58,
      "forecastProbability": 0.634,
      "edge": 0.214,
      "edgePct": 21.4,
      "absEdge": 0.214,
      "absEdgePct": 21.4,
      "edgeDirection": "buy_yes",
      "ensembleModel": "gfs_seamless,ecmwf_ifs04",
      "ensembleMembers": 82,
      "forecastSource": "Open-Meteo Ensemble",
      "detectedAt": "2026-04-04T12:30:00Z",
      "forecastFetchedAt": "2026-04-04T12:29:45Z"
    }
  ]
}

arbs[ ] fields

FieldTypeDescription
idnumberOpportunity ID
questionstringKalshi market question
polyQuestionstringPolymarket market question
kalshiIdstringKalshi market ticker
polyIdstringPolymarket condition ID
clobTokenIdsstring[] | nullPolymarket CLOB token IDs for direct trading
arbTypestring"yes/no" | "no/yes" | "yes/yes" | "no/no": which leg to buy on each platform
spreadnumberGross spread (0-1)
spreadPctnumberGross spread as a percentage
netSpreadnumber | nullSpread after estimated fees
netSpreadPctnumber | nullNet spread as a percentage
qualityScorenumber | nullLLM confidence score (0-100)
kalshiOddsMarketOdds{ yesBid, yesAsk, noBid, noAsk }
polyOddsMarketOdds{ yesBid, yesAsk, noBid, noAsk }
detectedAtstringISO timestamp when spread was first detected
warningsstring[]LLM-flagged caveats about this pair

whales[ ] fields

FieldTypeDescription
idnumberTrade ID
platformstring"kalshi" | "polymarket"
marketIdstringKalshi ticker or Polymarket condition ID
tradeIdstringUnique trade identifier from the platform
sizenumberRaw trade size — USD for Polymarket, contracts for Kalshi
notionalnumberTrade value in USD (consistent across platforms)
pricenumberPrice paid per share (0–1)
sidestring"yes" | "no": which outcome was purchased
takerSidestring | nullTaker side from Kalshi (null for Polymarket)
marketQuestionstring | nullHuman-readable market question
marketUrlstring | nullDirect link to the market
tradeTimestampstringISO timestamp when the trade occurred
detectedAtstringISO timestamp when CrossOdds detected it
displayNamestring | nullTrader display name (if known)
leaderboardRanknumber | nullPolymarket all-time leaderboard rank (null if not top-50)

weather[ ] fields (type=weather)

FieldTypeDescription
idnumberWeather edge ID
platformstring"kalshi" | "polymarket"
marketIdstringMarket identifier
questionstringMarket question text
locationNamestringWeather station or city (e.g. Central Park NY)
metricstringtemperature_max | temperature_min | precipitation | snowfall | wind_speed
thresholdstringFormatted threshold (e.g. ">95°F" or "28–29°F")
thresholdOpstringgt | gte | lt | lte | between
targetDatestringYYYY-MM-DD date the market resolves
forecastProbabilitynumberEnsemble forecast probability (0–1)
marketYesPricenumberMarket YES ask price (0–1)
edgenumberForecast prob - market price (negative = buy NO)
absEdgePctnumberAbsolute edge as percentage
edgeDirectionstring"buy_yes" | "buy_no"
ensembleModelstring | nullModel names (e.g. gfs+ecmwf)
ensembleMembersnumber | nullNumber of ensemble members (~80)
resolutionSourcestring | nullData source for resolution (NOAA, NWS, etc.)
marketUrlstring | nullDirect link to the market
forecastFetchedAtstringISO timestamp of last forecast update
04

Errors

StatusMeaning
401Missing, malformed, or revoked API key
429Rate limit exceeded — check X-RateLimit-Reset header for retry time
500Internal error — retry with exponential backoff

Rate limit headers on every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.