Sports API · Overview

Sports API · v1

Sports API

The HZURA Sports API provides sports, events, and event odds through HTTP GET endpoints. Customers authenticate with an API key, or with a legacy public-IP policy. GET /api/v1/health is public and is not rate limited.

Overview

The API returns the sports enabled for this client (key and display name), the published events for one sport, and one event plus its odds. It does not scrape providers and does not wait for a new upstream update before responding.

Result information, when the feed provides it, is on market status in the event-odds response. There is no separate settlement endpoint.

Sport keys are lowercase and must match exactly. Cricket is not cricket. Supported keys are cricket, football, tennis, horse-racing, and greyhound-racing. A client only receives the subset its policy allows.

sport
A key from GET /api/v1/sports, used as {sport}.
event ID
The event gmid, a positive integer used as {eventId}.
odds
The odds array on the single-event response. There is no separate odds URL.
MethodPathPurpose
GET/api/v1/healthService health. No API key or IP policy.
GET/api/v1/sportsSports enabled for this client.
GET/api/v1/{sport}/eventsPublished events. No full odds.
GET/api/v1/{sport}/events/{eventId}One event and its markets.

There are no query parameters on these routes. GET /metrics is an operator endpoint and is not part of this client API.

Health

  • Public endpoint
  • No API key
  • Not rate limited

Endpoint

GET/api/v1/health

Confirm the API is up and both stores used by this route answer.

status is ok and redis is ok only when both the odds store and the platform store answer. If either does not, the status is 503 and the body is { "status": "degraded", "redis": "unreachable" }. This is not the { error, message } document.

Authentication

None. No API key and no IP policy.

Request

This endpoint does not take parameters or a request body.

Response

200Both data stores answered.

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

503A data store did not answer. This is still the health document, not an error code.

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

Example request

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

Sports

  • API key or legacy IP
  • Rate limited

Endpoint

GET/api/v1/sports

Sports this API client may use, in a stable order.

key is the {sport} path segment. name is the display label. Numeric provider sport ids are not included.

A client limited to cricket and football receives only those objects, still in canonical order. An enabled client with no usable sports receives { "sports": [] }.

Authentication

API key plus calling IP, or a legacy IP policy. See Authentication.

Request

Headers

FieldTypeRequiredDescription
Authorization—NoBearer API key for admin-managed customers.
X-Api-Key—NoAlternative API key header. Ignored when Bearer is present.

Response

200Every sport currently enabled for this client.

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_allowedCaller is not allowed.
429rate_limitedClient budget for this window is used.
503security_config_unavailableAccess policy could not be read.

Events

  • API key or legacy IP
  • Rate limited

Endpoint

GET/api/v1/{sport}/events

Currently published events for one sport. No full odds.

The response is a JSON array. Use each object's gmid as {eventId}. Catalog rows are passed through after internal fields are removed. Typical fields include gmid, ename, etid, and status. Additional metadata may be present. Ignore unused fields.

A published catalog with no rows is []. A catalog that has not been published is 503 catalog_unavailable, not an empty array.

Authentication

API key plus calling IP, or a legacy IP policy. See Authentication.

Request

Parameters

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

Response

200Event catalog for the 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_sport{sport} is not a supported key.
403ip_not_allowedCaller is not allowed.
403sport_not_allowedThe sport is valid but not enabled for this client.
429rate_limitedRate limit exceeded.
503security_config_unavailableAccess policy could not be read.
502malformed_upstream_dataThe stored catalog could not be read.
503catalog_unavailableEvent data is not published yet.
503redis_unavailableThe data store is unavailable.
504redis_timeoutThe data store timed out.

Event Details

  • API key or legacy IP
  • Rate limited

Endpoint

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

One event and its current markets.

{eventId} must be a positive integer, the event's gmid, at most 20 digits. The event must exist in that sport's catalog.

odds is the complete market list currently held for the event. It can be an empty array when the event exists but no markets are published. If the odds payload itself is missing, the API returns 404 odds_not_found instead of an empty array.

Calling this route records interest in the event so it stays prioritized for upstream refresh. Keep polling while the event is on screen. Stop when it is not.

Authentication

API key plus calling IP, or a legacy IP policy. See Authentication.

Request

Parameters

FieldTypeInRequiredDescription
sportstringpathYesSport key from GET /api/v1/sports.
eventIdintegerpathYesPositive integer gmid from the event list.

Response

200Event row plus 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_sport{sport} is not a supported key.
400invalid_event_id{eventId} is not a positive integer.
403ip_not_allowedCaller is not allowed.
403sport_not_allowedSport is not enabled for this client.
404event_not_foundEvent is not in that sport's catalog.
404odds_not_foundNo odds payload is stored for this event.
429rate_limitedRate limit exceeded.
503security_config_unavailableAccess policy could not be read.
502malformed_upstream_dataThe event or odds payload could not be read.
503catalog_unavailableEvent data is not published yet.
503redis_unavailableThe data store is unavailable.
504redis_timeoutThe data store timed out.
FieldMeaning
sportSport key from the request.
event_idNumeric event id. Same value as event.gmid.
eventCatalog object for that event.
oddsArray of currently available markets.

Odds

Event odds are the odds array from GET /api/v1/{sport}/events/{eventId}. Markets are not reshaped. After a few internal fields are removed, each element is the upstream market object. Identify a market by gtype and marketName.

Prices are decimal. size is the available stake at that price, as provided upstream. Other gtype values may appear. Parse unknown markets defensively.

gtypeTypical marketNameShape
matchMatch Odds / Exchangerunners with back and lay prices
match1Bookmakerrunners with back and lay prices
fancy / fancy1Fancy / sessionsection ladder
marketName
Market display name.
marketId
Market identifier.
gtype
Market type.
status
Market status, including a settled state when the feed sends one.
runners[].selectionId
Selection id. It may be a string or a number.
runners[].runnerName
Selection name.
runners[].status
Selection status.
runners[].ex.availableToBack
Back prices as { price, size }.
runners[].ex.availableToLay
Lay prices as { price, size }.

Bookmaker (match1) prices may also include price1. Fancy markets use section instead of runners. Each section entry has a name (nat), a status (gstatus), and an odds ladder.

Results

There is no result or settlement endpoint in this version. Settlement state is on the same event-odds response. Market status, and selection status where present, reflects the current upstream state.

Data updates

  • Each response is the catalog or odds cached at request time.
  • The API does not wait for a new upstream update.
  • There is no push feed, no hard real-time guarantee, and no published freshness window.
  • A later poll may return the same payload if upstream has not changed.
  • Poll GET /api/v1/{sport}/events/{eventId} while the event is in use, at the frequency the UI needs. Reuse HTTP connections.

Fields not exposed

These provider-only fields are removed before the response is sent. Do not depend on them. Additional public fields may appear later; ignore unused keys.

ObjectOmitted
EventbetfairEventId, feed_source
Markettv, tvChannel, odd_type

Rate limits and access

/api/v1/sports and both event routes share the caller's sportsbook limit. Health is not rate limited. API-key accounts are limited per customer. Legacy IP clients are limited per public IP. The request count and window are per client and are not a fixed public contract.

HTTP 429 uses rate_limited and a Retry-After header with the seconds remaining in the current window. Rejected requests still count.

Integration example

  1. Call GET /api/v1/sports and choose a key.
  2. Call GET /api/v1/{sport}/events.
  3. Take an event gmid.
  4. Call GET /api/v1/{sport}/events/{eventId} and read odds.
  5. Poll that URL while the event is in use.
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();

On success, data.event_id is the event id, data.event is the catalog object, and data.odds is the market list. The API playground can exercise the same reads. Production calls still require an API key, when one was issued, and a calling IP that matches the configured CIDR.