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
GET
https://www.crossodds.app/api/v1/opportunitiesAuthorization
Bearer xo_live_<key>General
?type
"all" (default: arbs + whales) | "arb" | "whales" | "weather"?limit
integer 1–500, default 500⚡ Arb filters
?sort
"spread" (default) | "quality" | "detected"?minSpread
decimal 0–1, e.g. 0.02 for ≥ 2% spread?maxSpread
decimal 0–1?minQuality
integer 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"?minSize
dollars, e.g. 25000 for ≥ $25k trades?hours
1 | 6 | 12 (default 12)?leaderboardOnly
"true" — only Polymarket top-50 trader trades🌤 Weather filters (type=weather)
?minEdge
decimal 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 IDquestionstringKalshi market questionpolyQuestionstringPolymarket market questionkalshiIdstringKalshi market tickerpolyIdstringPolymarket condition IDclobTokenIdsstring[] | nullPolymarket CLOB token IDs for direct tradingarbTypestring"yes/no" | "no/yes" | "yes/yes" | "no/no": which leg to buy on each platformspreadnumberGross spread (0-1)spreadPctnumberGross spread as a percentagenetSpreadnumber | nullSpread after estimated feesnetSpreadPctnumber | nullNet spread as a percentagequalityScorenumber | nullLLM confidence score (0-100)kalshiOddsMarketOdds{ yesBid, yesAsk, noBid, noAsk }polyOddsMarketOdds{ yesBid, yesAsk, noBid, noAsk }detectedAtstringISO timestamp when spread was first detectedwarningsstring[]LLM-flagged caveats about this pairwhales[ ] fields
FieldTypeDescription
idnumberTrade IDplatformstring"kalshi" | "polymarket"marketIdstringKalshi ticker or Polymarket condition IDtradeIdstringUnique trade identifier from the platformsizenumberRaw trade size — USD for Polymarket, contracts for KalshinotionalnumberTrade value in USD (consistent across platforms)pricenumberPrice paid per share (0–1)sidestring"yes" | "no": which outcome was purchasedtakerSidestring | nullTaker side from Kalshi (null for Polymarket)marketQuestionstring | nullHuman-readable market questionmarketUrlstring | nullDirect link to the markettradeTimestampstringISO timestamp when the trade occurreddetectedAtstringISO timestamp when CrossOdds detected itdisplayNamestring | nullTrader display name (if known)leaderboardRanknumber | nullPolymarket all-time leaderboard rank (null if not top-50)weather[ ] fields (type=weather)
FieldTypeDescription
idnumberWeather edge IDplatformstring"kalshi" | "polymarket"marketIdstringMarket identifierquestionstringMarket question textlocationNamestringWeather station or city (e.g. Central Park NY)metricstringtemperature_max | temperature_min | precipitation | snowfall | wind_speedthresholdstringFormatted threshold (e.g. ">95°F" or "28–29°F")thresholdOpstringgt | gte | lt | lte | betweentargetDatestringYYYY-MM-DD date the market resolvesforecastProbabilitynumberEnsemble forecast probability (0–1)marketYesPricenumberMarket YES ask price (0–1)edgenumberForecast prob - market price (negative = buy NO)absEdgePctnumberAbsolute edge as percentageedgeDirectionstring"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 marketforecastFetchedAtstringISO timestamp of last forecast update04
Errors
StatusMeaning
401Missing, malformed, or revoked API key429Rate limit exceeded — check X-RateLimit-Reset header for retry time500Internal error — retry with exponential backoffRate limit headers on every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.