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
keyfromGET /api/v1/sports, used in place of{sport}. - event ID
- The event's
gmid, a whole number, used in place of{eventId}. - odds
- The
oddslist on the single-event answer. There is no separate odds address.
| Method | Path | What it gives you |
|---|---|---|
| GET | /api/v1/health | Whether the API is up. No key needed. |
| GET | /api/v1/sports | The sports you can use. |
| GET | /api/v1/{sport}/events | The 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
/api/v1/healthCheck 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.
{
"status": "ok",
"redis": "ok"
}503Part of the service is not answering.
{
"status": "degraded",
"redis": "unreachable"
}Example request
curl -sS "https://api.hzura.com/api/v1/health"Sports
- API key required
- Rate limited
Endpoint
/api/v1/sportsThe 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
| Field | Type | Required | Description |
|---|---|---|---|
| Authorization | — | No | Bearer YOUR_API_KEY. |
| X-Api-Key | — | No | Another way to send the key. Not used when Authorization: Bearer is present. |
Response
200Every sport enabled for your account.
{
"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 -sS "https://api.hzura.com/api/v1/sports" \
-H "Authorization: Bearer YOUR_API_KEY"GET /api/v1/sports HTTP/1.1
Host: api.hzura.com
Authorization: Bearer YOUR_API_KEY
Accept: application/jsonErrors
| HTTP | error | When |
|---|---|---|
| 403 | ip_not_allowed | Access refused: check your key and server IP address. |
| 429 | rate_limited | Too many requests. Wait for Retry-After. |
| 503 | security_config_unavailable | Access could not be checked right now. Try again shortly. |
Events
- API key required
- Rate limited
Endpoint
/api/v1/{sport}/eventsThe 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
| Field | Type | In | Required | Description |
|---|---|---|---|---|
| sport | string | path | Yes | A sport key from GET /api/v1/sports. |
Response
200The events of this sport.
[
{
"gmid": 1789048569,
"ename": "India v Australia",
"etid": 4,
"status": "OPEN"
}
]Example request
curl -sS "https://api.hzura.com/api/v1/cricket/events" \
-H "Authorization: Bearer YOUR_API_KEY"Errors
| HTTP | error | When |
|---|---|---|
| 400 | invalid_sport | This sport key does not exist. |
| 403 | ip_not_allowed | Access refused: check your key and server IP address. |
| 403 | sport_not_allowed | This sport is not enabled for your account. |
| 429 | rate_limited | Too many requests. Wait for Retry-After. |
| 503 | security_config_unavailable | Access could not be checked right now. |
| 502 | malformed_upstream_data | The event data could not be read. Try again shortly. |
| 503 | catalog_unavailable | Events for this sport are not ready yet. |
| 503 | redis_unavailable | Temporarily unavailable. Try again shortly. |
| 504 | redis_timeout | Took too long to answer. Try again shortly. |
Event Details
- API key required
- Rate limited
Endpoint
/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
| Field | Type | In | Required | Description |
|---|---|---|---|---|
| sport | string | path | Yes | A sport key from GET /api/v1/sports. |
| eventId | integer | path | Yes | The event's gmid from the events list. |
Response
200The event and its markets.
{
"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 -sS "https://api.hzura.com/api/v1/cricket/events/1789048569" \
-H "Authorization: Bearer YOUR_API_KEY"Errors
| HTTP | error | When |
|---|---|---|
| 400 | invalid_sport | This sport key does not exist. |
| 400 | invalid_event_id | The event id is not a whole number above zero. |
| 403 | ip_not_allowed | Access refused: check your key and server IP address. |
| 403 | sport_not_allowed | This sport is not enabled for your account. |
| 404 | event_not_found | No event with this id in this sport. |
| 404 | odds_not_found | The event has no odds yet. |
| 429 | rate_limited | Too many requests. Wait for Retry-After. |
| 503 | security_config_unavailable | Access could not be checked right now. |
| 502 | malformed_upstream_data | The event or odds could not be read. Try again shortly. |
| 503 | catalog_unavailable | Events for this sport are not ready yet. |
| 503 | redis_unavailable | Temporarily unavailable. Try again shortly. |
| 504 | redis_timeout | Took too long to answer. Try again shortly. |
| Field | Meaning |
|---|---|
sport | The sport key you asked for. |
event_id | The event id. Same as event.gmid. |
event | The event, as in the events list. |
odds | The 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.
| gtype | Usual marketName | Shape |
|---|---|---|
match | Match Odds / Exchange | runners with back and lay prices |
match1 | Bookmaker | runners with back and lay prices |
fancy / fancy1 | Fancy / session | section 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
- Call
GET /api/v1/sportsand pick akey. - Call
GET /api/v1/{sport}/events. - Pick an event and take its
gmid. - Call
GET /api/v1/{sport}/events/{eventId}and readodds. - Call it again regularly while the event is on screen.
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.