Sports API · Overview

Sports API · v1

Sports API

The Sports API gives you sports, their events, and the odds of each event. You only read data: every route is a GET, and the answer is the latest data HZURA has at that moment.

Overview

In short: ask which sports you can use, pick one, list its events, then ask for one event to get its odds. Keep asking for that event while you show it, to stay up to date.

Results are not a separate route. When a market is settled, its status on the event says so.

Sport keys are lowercase and must match exactly (cricket, not Cricket). The keys are cricket, football, tennis, horse-racing and greyhound-racing. You only get the ones enabled for your account.

sport
A key from GET /api/v1/sports, used in place of {sport}.
event ID
The event's gmid, a whole number, used in place of {eventId}.
odds
The odds list on the single-event answer. There is no separate odds address.
MethodPathWhat it gives you
GET/api/v1/healthWhether the API is up. No key needed.
GET/api/v1/sportsThe sports you can use.
GET/api/v1/{sport}/eventsThe events of one sport, without odds.
GET/api/v1/{sport}/events/{eventId}One event and its odds.

None of these routes take query parameters.

Health

  • Public endpoint
  • No API key
  • Not rate limited

Endpoint

GET/api/v1/health

Check that the API is up.

Read status. ok with HTTP 200 means the API is working normally. degraded with HTTP 503 means part of the service is not answering right now; try again shortly. This answer does not use the usual error format.

Authentication

None. No key and no IP check.

Request

This endpoint does not take parameters or a request body.

Response

200The API is working.

JSON
{
  "status": "ok",
  "redis": "ok"
}

503Part of the service is not answering.

JSON
{
  "status": "degraded",
  "redis": "unreachable"
}

Example request

curl
curl -sS "https://api.hzura.com/api/v1/health"

Sports

  • API key required
  • Rate limited

Endpoint

GET/api/v1/sports

The sports you can use, always in the same order.

key is what you put in place of {sport} in the other addresses. name is the label to show people.

You only get the sports enabled for your account. If none are, the answer is { "sports": [] }.

Authentication

Your API key, sent from a server on your IP allow-list. See Authentication.

Request

Headers

FieldTypeRequiredDescription
Authorization—NoBearer YOUR_API_KEY.
X-Api-Key—NoAnother way to send the key. Not used when Authorization: Bearer is present.

Response

200Every sport enabled for your account.

JSON
{
  "sports": [
    { "key": "cricket", "name": "Cricket" },
    { "key": "football", "name": "Football" },
    { "key": "tennis", "name": "Tennis" },
    { "key": "horse-racing", "name": "Horse Racing" },
    { "key": "greyhound-racing", "name": "Greyhound Racing" }
  ]
}

Example request

curl
curl -sS "https://api.hzura.com/api/v1/sports" \
  -H "Authorization: Bearer YOUR_API_KEY"

Errors

HTTPerrorWhen
403ip_not_allowedAccess refused: check your key and server IP address.
429rate_limitedToo many requests. Wait for Retry-After.
503security_config_unavailableAccess could not be checked right now. Try again shortly.

Events

  • API key required
  • Rate limited

Endpoint

GET/api/v1/{sport}/events

The current events of one sport, without odds.

The answer is a JSON list. Each event's gmid is its id; use it in place of {eventId}. You will usually see gmid, ename (event name), etid and status. Events can carry more fields; ignore the ones you do not use.

No events right now is an empty list []. If events for this sport are not ready yet, you get 503 catalog_unavailable; try again shortly.

Authentication

Your API key, sent from a server on your IP allow-list. See Authentication.

Request

Parameters

FieldTypeInRequiredDescription
sportstringpathYesA sport key from GET /api/v1/sports.

Response

200The events of this sport.

JSON
[
  {
    "gmid": 1789048569,
    "ename": "India v Australia",
    "etid": 4,
    "status": "OPEN"
  }
]

Example request

curl
curl -sS "https://api.hzura.com/api/v1/cricket/events" \
  -H "Authorization: Bearer YOUR_API_KEY"

Errors

HTTPerrorWhen
400invalid_sportThis sport key does not exist.
403ip_not_allowedAccess refused: check your key and server IP address.
403sport_not_allowedThis sport is not enabled for your account.
429rate_limitedToo many requests. Wait for Retry-After.
503security_config_unavailableAccess could not be checked right now.
502malformed_upstream_dataThe event data could not be read. Try again shortly.
503catalog_unavailableEvents for this sport are not ready yet.
503redis_unavailableTemporarily unavailable. Try again shortly.
504redis_timeoutTook too long to answer. Try again shortly.

Event Details

  • API key required
  • Rate limited

Endpoint

GET/api/v1/{sport}/events/{eventId}

One event and its odds.

{eventId} is the event's gmid from the events list: a whole number above zero, at most 20 digits.

odds lists every market the event has right now. It can be empty when the event has no markets yet. If the event has no odds at all, you get 404 odds_not_found.

Asking for an event keeps its odds refreshed more often. Keep asking while the event is on screen, and stop when it is not.

Authentication

Your API key, sent from a server on your IP allow-list. See Authentication.

Request

Parameters

FieldTypeInRequiredDescription
sportstringpathYesA sport key from GET /api/v1/sports.
eventIdintegerpathYesThe event's gmid from the events list.

Response

200The event and its markets.

JSON
{
  "sport": "cricket",
  "event_id": 1789048569,
  "event": {
    "gmid": 1789048569,
    "ename": "India v Australia",
    "etid": 4,
    "status": "OPEN"
  },
  "odds": [
    {
      "marketId": "1.234",
      "marketName": "Match Odds",
      "gtype": "match",
      "status": "OPEN",
      "runners": [
        {
          "selectionId": "47999",
          "runnerName": "India",
          "status": "ACTIVE",
          "ex": {
            "availableToBack": [{ "price": 1.75, "size": 50.0 }],
            "availableToLay": [{ "price": 1.76, "size": 40.0 }]
          }
        }
      ]
    }
  ]
}

Example request

curl
curl -sS "https://api.hzura.com/api/v1/cricket/events/1789048569" \
  -H "Authorization: Bearer YOUR_API_KEY"

Errors

HTTPerrorWhen
400invalid_sportThis sport key does not exist.
400invalid_event_idThe event id is not a whole number above zero.
403ip_not_allowedAccess refused: check your key and server IP address.
403sport_not_allowedThis sport is not enabled for your account.
404event_not_foundNo event with this id in this sport.
404odds_not_foundThe event has no odds yet.
429rate_limitedToo many requests. Wait for Retry-After.
503security_config_unavailableAccess could not be checked right now.
502malformed_upstream_dataThe event or odds could not be read. Try again shortly.
503catalog_unavailableEvents for this sport are not ready yet.
503redis_unavailableTemporarily unavailable. Try again shortly.
504redis_timeoutTook too long to answer. Try again shortly.
FieldMeaning
sportThe sport key you asked for.
event_idThe event id. Same as event.gmid.
eventThe event, as in the events list.
oddsThe event's markets right now.

Odds

Odds are the odds list on GET /api/v1/{sport}/events/{eventId}. Each item is one market. Tell markets apart by gtype (the market type) and marketName.

Prices are decimal odds. size is how much can be staked at that price. New market types can appear, so handle ones you do not know without breaking.

gtypeUsual marketNameShape
matchMatch Odds / Exchangerunners with back and lay prices
match1Bookmakerrunners with back and lay prices
fancy / fancy1Fancy / sessionsection list
marketName
The market's name to show.
marketId
The market's id.
gtype
The market type.
status
The market's state, including settled when the result is known.
runners[].selectionId
The selection's id. It can be text or a number.
runners[].runnerName
The selection's name.
runners[].status
The selection's state.
runners[].ex.availableToBack
Back prices, each { price, size }.
runners[].ex.availableToLay
Lay prices, each { price, size }.

Bookmaker (match1) prices can also have price1. Fancy markets use section instead of runners: each entry has a name (nat), a state (gstatus) and its own odds list.

Results

There is no separate results route. Results appear on the same event: a settled market shows it in its status, and selections in theirs where available.

Staying up to date

  • Every answer is the latest data HZURA has when you ask. The API never makes you wait for a fresh update.
  • There is no push or live stream. To stay current, ask again.
  • Asking again can return the same data if nothing has changed.
  • Ask for GET /api/v1/{sport}/events/{eventId} as often as your screen needs while the event is shown. Reuse your HTTP connections.

Rate limits

/api/v1/sports and both event routes count towards one limit for your account. Health has no limit. Your limit is set for your account; ask HZURA if you need more.

When you reach it you get 429 rate_limited with a Retry-After header: the number of seconds to wait. Requests sent while you are limited still count, so do wait.

Integration example

  1. Call GET /api/v1/sports and pick a key.
  2. Call GET /api/v1/{sport}/events.
  3. Pick an event and take its gmid.
  4. Call GET /api/v1/{sport}/events/{eventId} and read odds.
  5. Call it again regularly while the event is on screen.
JavaScript
const base = "https://api.hzura.com/api/v1";
const headers = {
  Authorization: "Bearer YOUR_API_KEY",
  Accept: "application/json",
};

const sports = await fetch(`${base}/sports`, { headers }).then((r) => r.json());
const sportKey = sports.sports[0].key;

const events = await fetch(`${base}/${sportKey}/events`, { headers }).then((r) => r.json());
const eventId = events[0].gmid;

const response = await fetch(`${base}/${sportKey}/events/${eventId}`, { headers });
const data = await response.json();

data.event is the event and data.odds its markets. You can try the same calls in the API playground. Run your own code on a server whose IP address is on your allow-list.