Programmatic access to cross-platform event prices and arbs.
Send your API key as an HTTP Bearer token. Keys start with obk_.
curl https://www.oddsbridge.app/api/v1/events \ -H "Authorization: Bearer obk_your_key_here"
Per-minute throttle plus a daily ceiling. Both reset on their own clock. Every response includes the headers below — read them and back off when Remaining-Minute approaches zero.
| Tier | Per minute | Per day |
|---|---|---|
| free | 60 | 100 |
| trader | 600 | 10 000 |
| pro | 3 000 | 1 000 000 |
During private beta all tiers are free of charge — pricing activates once we ship the self-serve dashboard.
/api/v1/eventsList matched events across Polymarket, Kalshi, and sportsbooks.
sport — basketball, soccer, tennis, baseball, hockey, mma, american_football, …league — exact league string (e.g. NBA, EPL)min_gap — float, percentage points; only events with at least one outcome above this gaplimit — int, default 100, max 500offset — int, default 0/api/v1/events/{id}Single event detail. {id} accepts the event slug or canonical id. Polymarket and Kalshi prices are enriched with order-book depth at $1k / $5k / $25k stake sizes.
/api/v1/events/{id}/quotesLightweight variant of the detail endpoint — only outcomes + per-platform prices + depth. Drops settlement / volume metadata. Use this when polling a single market.
/api/v1/arbsCurrently-detected arbitrage opportunities, sorted by profit margin descending. Returns an empty array when no arbs clear your filters.
min_edge — minimum profit margin in % (default 1.0)min_liquidity — exclude arbs with thin legs (default true)executable_only — only return arbs whose every leg fills cleanly given live order-book depth + per-book stake limits. Each surviving arb gets an executability object with per-leg detail (default false)sport — filter by Sportlimit — int, default 100, max 500/api/v1/streamLong-lived Server-Sent Events stream. Frames: connected, arb, heartbeat, error. Per-connection dedupe — each arb fires once per stream. Browser clients can pass ?token=obk_… since EventSource can't set headers.
/api/v1/alerts/api/v1/alerts/{id}Register webhook alerts on cross-platform arbs. Each alert has filters (minEdgePct, sport, minLiquidity, executableOnly) and a target URL with kind in discord | telegram | generic. Tier ceilings: free 1, trader 50, pro 1000. Cron evaluator fires every 30 min; per-(alert, event) cooldown defaults to 6h. Manage from the /account/api dashboard or via curl.
/api/v1/meReturns the authenticated key's tier, owner, current rate-limit counters, and active-alerts usage. Cheap call — no data joins, just KV reads.
{
"data": [ ... ],
"meta": {
"total": 332,
"limit": 100,
"offset": 0,
"rateLimit": {
"limitMinute": "60",
"remainingMinute": "59",
"remainingDay": "99"
}
}
}Errors: { "error": { "code": "...", "message": "..." } } with HTTP 4xx/5xx. Common codes: missing_bearer, invalid_key, rate_limited, not_found.
No SDK to install yet — the public surface is plain REST + SSE, so the standard library is enough.
import os, json, urllib.request
BASE = "https://www.oddsbridge.app/api/v1"
KEY = os.environ["ODDSBRIDGE_KEY"] # obk_...
def get(path, **params):
qs = "&".join(f"{k}={v}" for k, v in params.items() if v is not None)
req = urllib.request.Request(
f"{BASE}/{path}" + (f"?{qs}" if qs else ""),
headers={"Authorization": f"Bearer {KEY}"},
)
with urllib.request.urlopen(req, timeout=10) as r:
return json.load(r)
# 1. Pull every cross-platform arb ≥ 2% with executable verdict
hits = get("arbs", min_edge=2, executable_only="true", limit=50)
for h in hits["data"]:
print(f"+{h['profitMarginPct']}% {h['eventTitle']} ({h['eventSlug']})")
# 2. Stream new arbs over SSE (uses sseclient-py if you want a nicer API)
import urllib.request as _u
req = _u.Request(f"{BASE}/stream",
headers={"Authorization": f"Bearer {KEY}"})
with _u.urlopen(req) as r:
for line in r:
line = line.decode("utf-8", "replace").strip()
if line.startswith("event: arb"):
data_line = next(r).decode("utf-8", "replace").strip()
if data_line.startswith("data: "):
evt = json.loads(data_line[6:])
print("ARB", evt["event"]["title"], evt["profitMarginPct"], "%")
# 3. Register a webhook alert that fires on > 3% NFL arbs
import urllib.request, json
req = urllib.request.Request(
f"{BASE}/alerts",
method="POST",
headers={
"Authorization": f"Bearer {KEY}",
"Content-Type": "application/json",
},
data=json.dumps({
"name": "NFL ≥ 3%",
"filters": {"minEdgePct": 3, "sport": "american_football",
"minLiquidity": True, "executableOnly": True},
"webhook": {"url": os.environ["MY_DISCORD_WEBHOOK"], "kind": "discord"},
}).encode("utf-8"),
)
with urllib.request.urlopen(req) as r:
print(json.load(r))A native pip install oddsbridge wrapper ships once a few customers ask for it.
Email api@oddsbridge.app with your name, project, and the volume you expect. We aim to respond within 24h during private beta. Once you have your key, manage it at /account/api.