Developer docs
Connect once. Get only what you bought.
Partners authenticate with an API key. Access is limited by module grants (odds / video packs) issued in admin — not by inventing req/hour hobby tiers.
Hosts
api.oddsrail.comRESTws.oddsrail.comWebSocketplay.oddsrail.comPlay / HLS proxydocs.oddsrail.comThis siteadmin.oddsrail.comKeys & grants (ops)Authentication
Keys look like or_live_…. Pass on every partner request:
Authorization: Bearer or_live_…
# or
X-Api-Key: or_live_…
Inspect your grants:
GET https://api.oddsrail.com/v1/me
Authorization: Bearer or_live_…
{
"ok": true,
"key": {
"id": "…",
"mode": "full",
"modules": ["odds_football", "video_football"],
"oddsSports": ["soccer", "cyber-football"],
"videoSports": ["soccer", "cyber-football"],
"scopes": ["feed:read", "ws:feed", "stream:read", "ws:stream", "play:read"]
}
}
Module grants
When a partner buys packs on the constructor, ops create (or later
auto-provision) a key with those modules. The API then
returns only sports from those packs.
odds_*→ odds sports on REST +liveWSvideo_*→ stream flag +streamsWS + play- No odds modules →
403 NO_ODDS_MODULESon/v1/events - Sport outside grant → omitted from feed; video outside grant →
stream.available=false
Modes (api_ws / ws_stream / full)
set scopes. Modules set coverage. Prefer modules for every paid key.
REST
Live events
GET https://api.oddsrail.com/v1/events?locale=en&limit=40
Authorization: Bearer or_live_…
Requires scope feed:read. Response events are already filtered by the key’s odds packs.
Public demo (no key)
GET https://api.oddsrail.com/v1/demo/live?locale=en&limit=6
GET https://api.oddsrail.com/v1/demo/stream
GET https://api.oddsrail.com/v1/meta/plans
WebSocket
wss://ws.oddsrail.com/v1/ws?locale=en&api_key=or_live_…
Or connect without a key (public demo), then:
{ "type": "auth", "apiKey": "or_live_…" }
{ "type": "subscribe", "channels": ["live", "streams"], "locale": "en", "limit": 24 }
liveneedsws:feed(orfeed:read)streamsneedsws:stream(orstream:read)- Snapshots / ticks only include granted sports
Play
Demo player: https://play.oddsrail.com/v1/demo/player/{id}
(also used on the marketing site). Partner play follows the same
proxy once the event is in a granted video sport — stream URLs appear
on events with stream.available=true.
Checkout (USDT TRC-20)
Same wallet + unique-amount matching as imba.bet deposits. Partner
taps Pay USDT on the site → exact payAmount
→ send TRC-20 → monitor credits → API key + cabinet link.
POST https://api.oddsrail.com/v1/checkout
{ "modules": ["odds_football", "video_football"], "billingPeriod": "month"|"year" }
GET https://api.oddsrail.com/v1/checkout/{id}
GET https://api.oddsrail.com/v1/cabinet?t=or_cab_…
POST /v1/checkout {
"kind":"renew"|"upgrade",
"cabinetToken":"or_cab_…",
"modules":[...],
"billingPeriod":"month"|"year"
}
Month = 30 days. Year = 365 days at 10× monthly (2 months free).
After period end: 3-day grace (API still works), then soft-lock
→ 402 SUBSCRIPTION_EXPIRED until renew.
Cabinet: Connect snippets, rotate key, renew month/year, upgrade packs.
Client panel & Sportsbook silos
Portal: oddsrail.com/panel.
Sportsbooks use the imba engine under Oddsrail brand —
hosts are always *.oddsrail.com (never imba.bet in customer URLs).
Provision job writes silo config + advances to SANDBOX_READY.
Real-money LIVE is compliance-gated.
POST /v1/auth/register { "email", "password", "name?" }
POST /v1/auth/login
GET /v1/auth/me
GET /v1/panel/overview
POST /v1/panel/link-cabinet { "token": "or_cab_…" }
POST /v1/panel/instances { "name", "slug?" }
# → status PROVISIONING → SANDBOX_READY
# artifacts: data/silos/{slug}/imba.env + compose.silo.yml
Ops
- Self-serve checkout is preferred (auto key + grants + cabinet link).
- Client panel for account / BK stubs / billing history.
- Manual fallback: admin → API keys → Grants.
- Admin → Billing: MRR, renew-soon, suspended, recent orders.
GET /admin/api/metricsfor the same snapshot.