ESKape Sportsbook Feed for developers

Football odds and risk management, by API — on your odds or ours

A self-service subscription for licensed betting operators and the platforms that serve them. Register, get a key, and take the whole pre-match catalogue of a match from our own price — or send us your 1X2 and Over/Under 2.5 for the match and get your catalogue, priced from your odds. REST and JSON, one key; live updates over SignalR on the paid plans.

Not for private individuals and not a betting site. No bets are taken here. The output is information for your trading; you set your prices, margin and limits and you answer to your players and your regulator.

Plans

Loading the plans…

Quotas are hard limits: over them a request is refused with 429, nothing is charged. The free plan can be extended on request. Competitions in own-price mode are those whose data sources permit it.

Register

Business-to-business only, not for businesses established in the United Kingdom. We record the company, its country, its licence or registration number, a contact email and the version of the terms you accept. We do not verify the licence automatically; a paid plan is enabled after we have.

Quick start

1. Today's fixtures in your competitions

curl -H "X-Api-Key: $KEY" "https://eskape.pro/api/fixtures/daily?date=2026-10-24"

2. Our catalogue for a match (~140 markets)

curl -H "X-Api-Key: $KEY" "https://eskape.pro/api/fixtures/odds-snapshot?date=2026-10-24&home=Levski%20Sofia&away=CSKA%20Sofia"

3. Your odds, our maths — send your 1X2 and Over/Under 2.5, then ask for the catalogue again

curl -X PUT -H "X-Api-Key: $KEY" -H "Content-Type: application/json" https://eskape.pro/api/fixtures/quote \
  -d '{"homeTeamName":"Levski Sofia","awayTeamName":"CSKA Sofia","date":"2026-10-24",
       "homeWinDecimal":2.10,"drawDecimal":3.40,"awayWinDecimal":3.60,"overDecimal":1.95,"underDecimal":1.90}'

The quote prices the match for 60 minutes or until you send a newer one; without a fresh quote you get our price. Sending the same quote twice is harmless (idempotent). Your quote is never shown to anyone else and never stored on disk.

4. Live updates — SignalR instead of polling (paid plans)

const c = new signalR.HubConnectionBuilder()
  .withUrl("https://eskape.pro/hubs/feed-odds", { accessTokenFactory: () => KEY })
  .withAutomaticReconnect().build();
c.on("fixtureOdds", snapshot => render(snapshot));
await c.start();
await c.invoke("SubscribeFixture", "2026-10-24", "Levski Sofia", "CSKA Sofia");
c.onreconnected(() => c.invoke("SubscribeFixture", "2026-10-24", "Levski Sofia", "CSKA Sofia"));

The connection counts as one request; the updates do not. After a reconnect, subscribe to your fixtures again.

The full reference: OpenAPI document (import it into Postman or generate a client). Same-game combinations: POST /api/betbuilder/quote. Binary contracts: GET /api/fixtures/binary. Settlement after full time: GET /api/settlement.

Code samples

import requests

KEY = "esk_..."
BASE = "https://eskape.pro"
H = {"X-Api-Key": KEY}

fixtures = requests.get(f"{BASE}/api/fixtures/daily", params={"date": "2026-10-24"}, headers=H).json()
first = fixtures[0]

# Your odds for the match, then your catalogue
requests.put(f"{BASE}/api/fixtures/quote", headers=H, json={
    "homeTeamName": first["homeTeamName"], "awayTeamName": first["awayTeamName"], "date": "2026-10-24",
    "homeWinDecimal": 2.10, "drawDecimal": 3.40, "awayWinDecimal": 3.60, "overDecimal": 1.95, "underDecimal": 1.90,
}).raise_for_status()
r = requests.get(f"{BASE}/api/fixtures/odds-snapshot", headers=H,
                 params={"date": "2026-10-24", "home": first["homeTeamName"], "away": first["awayTeamName"]})
r.raise_for_status()
print(r.headers.get("X-RateLimit-Remaining"), "requests left today")
for market in r.json()["markets"]:
    print(market["marketCode"], [(s["key"], s["publishedOdds"]) for s in market["selections"]])

My subscription

Paste your key to see your plan, today's usage and your statistics. The key is sent only to this server, in the header, and is not stored by this page.

Limits and errors

StatusWhenWhat to do
401missing or unknown keysend X-Api-Key; a rotated key stops after its overlap
403subscription pending, suspended or ended; a fixture outside your plan's competitions (a competition of the paid plans says so); an endpoint not in the subscription; the live hub on a plan without it (realtime-not-in-plan); your own odds on more fixtures a day than the plan allowsread detail; write to us
429 + Retry-Afterover the plan's requests a minute (minute-quota-exceeded), a day (daily-quota-exceeded) or a month (monthly-quota-exceeded); more requests a minute outside the quota than fair use allows (fair-use-exceeded, the body says how many)wait Retry-After seconds; follow X-RateLimit-Remaining and X-RateLimit-Reset (seconds until the window that runs out first resets: 00:00 UTC, or the first day of the next month); the day's fixture list and your standing (/api/subscriptions/me) are outside the quota, and refused requests are not counted; on a paid plan, use the live hub instead of polling
400 / 404 / 409invalid input; fixture not listed for that date; settlement before full timethe body says why

A refused key, plan or quota is application/problem+json (RFC 9457): { "type", "title", "status", "detail", "code", "requestId", "error" }; other refusals (400, 404, 409, a fixture outside your plan) are RFC 9110 problem details with status and detail. Quote requestId (also the X-Request-Id header) when you write to us. Compatible changes (new fields) come without notice; a breaking change gets a new path (/api/v2/…) and at least 90 days' notice with Deprecation and Sunset headers.

Try the maths without a key: the demo sportsbook and GET /api/demo/match?home=2.1&draw=3.4&away=3.6&over=1.95&under=1.9. Service health: GET /health/live.