Odds Distribution API
This guide is for third-party developers integrating the production HTTP API. All endpoints are JSON GET requests. No request body is required.
This deployment's base URL is:
https://oddsfeed.starluck.cloud/api/v1
No API key or Authorization header is used. Access is controlled by IP allowlisting — your server's public IP address must be allowlisted before match-data endpoints will respond.
Access
- Call the API over HTTPS in production.
- No API key and no
Authorizationheader are required. - Access is controlled by IP allowlisting.
- Your server's public IP address must be allowlisted before match-data access is enabled.
- If the calling IP is not allowed, match endpoints return HTTP 403.
GET /api/v1/health can be used as a connectivity check and does not require an allowlisted IP. Match endpoints do.
Before integration, send the public IP address(es) of the servers that will call the API.
Supported sports
Sport slugs are lowercase and must match exactly.
| Sport | URL slug |
|---|---|
| Cricket | cricket |
| Football | football |
| Tennis | tennis |
| Horse Racing | horse-racing |
| Greyhound Racing | greyhound-racing |
Unsupported slugs (including mixed case such as Cricket) return 400.
Endpoints
| Method | URL | Purpose |
|---|---|---|
| GET | /api/v1/health | Service health |
| GET | /api/v1/{sport}/matches | Available matches for a sport (no full odds) |
| GET | /api/v1/{sport}/matches/{eventId} | One match with its current markets/odds |
{sport} is one of the slugs above. {eventId} is the match's gmid — a positive integer from the match-list response.
There are no query parameters.
Health
Success — HTTP 200
{"status":"ok","redis":"ok"}
Degraded — HTTP 503
{"status":"degraded","redis":"unreachable"}
status is "ok" only when the backend data store is reachable.
curl -sS "https://oddsfeed.starluck.cloud/api/v1/health"
Match list
It returns match/event data only. It does not return the full markets/odds list. Use the single-match endpoint for odds.
The response is a JSON array. Each object is one event. Use gmid as the event ID for the single-match URL.
curl -sS "https://oddsfeed.starluck.cloud/api/v1/cricket/matches"
HTTP 200
[
{
"gmid": 1789048569,
"ename": "India v Australia",
"etid": 4,
"status": "OPEN"
}
]
gmid is the event ID. Use it in /matches/{eventId}.
Typical fields also include ename (event name), etid (sport identifier), and status (for example OPEN). Event objects may include additional metadata such as competition name or in-play flags. Ignore unused fields.
An empty array [] means no matches are currently published for that sport.
Errors
| HTTP | error | When |
|---|---|---|
| 400 | invalid_sport | {sport} is not a supported slug |
| 403 | ip_not_allowed | Calling IP is not allowlisted |
| 429 | rate_limited | Rate limit exceeded |
| 502 | malformed_upstream_data | Upstream catalog could not be read |
| 503 | catalog_unavailable | Match data is not available yet |
| 503 | redis_unavailable | Backend data store unavailable |
| 504 | redis_timeout | Backend data store timed out |
Single match + odds
{eventId} must be a positive integer (the event's gmid). The event must exist in that sport's match list.
The top-level response is always:
{
"sport": "...",
"event_id": "...",
"event": {},
"odds": []
}
| Field | Meaning |
|---|---|
sport | Sport slug from the request |
event_id | Numeric event ID (same value as event.gmid) |
event | The match object (same catalog fields as the list) |
odds | Array of currently available markets |
odds is the complete market list currently held for that event. It can be an empty array when the event exists but no markets are published yet.
curl -sS "https://oddsfeed.starluck.cloud/api/v1/cricket/matches/1789048569"
HTTP 200
{
"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 }]
}
}
]
},
{
"marketId": "8.111",
"marketName": "Bookmaker",
"gtype": "match1",
"status": "OPEN",
"runners": [
{
"selectionId": 48000,
"runnerName": "India",
"status": "ACTIVE",
"ex": {
"availableToBack": [{ "price": 1.97, "size": 100.0 }],
"availableToLay": [{ "price": 2.02, "size": 80.0 }]
}
}
]
}
]
}
Errors
| HTTP | error | When |
|---|---|---|
| 400 | invalid_sport | {sport} is not a supported slug |
| 400 | invalid_event_id | {eventId} is not a positive integer |
| 403 | ip_not_allowed | Calling IP is not allowlisted |
| 404 | event_not_found | Event is not in that sport's match list |
| 404 | odds_not_found | Odds are not available for this match |
| 429 | rate_limited | Rate limit exceeded |
| 502 | malformed_upstream_data | Upstream odds could not be read |
| 503 | catalog_unavailable | Match data is not available yet |
| 503 | redis_unavailable | Backend data store unavailable |
| 504 | redis_timeout | Backend data store timed out |
Odds structure
Identify each market by gtype and marketName. Markets currently returned include:
| gtype | Typical marketName | Shape |
|---|---|---|
match | Match Odds / Exchange | runners with back/lay |
match1 | Bookmaker | runners with back/lay |
fancy / fancy1 | Fancy / session | section ladder |
Other gtype values may appear. Parse unknown markets defensively.
Match Odds and Bookmaker (runners)
- marketNameMarket display name
- marketIdMarket identifier
- gtypeMarket type
- statusMarket status
- runners[]Selections in the market
- runners[].selectionIdSelection identifier
- runners[].runnerNameSelection name
- runners[].statusSelection status
- runners[].ex.availableToBackBack prices (price, size)
- runners[].ex.availableToLayLay prices (price, size)
selectionId may be a string or a number. Bookmaker (match1) prices may also include price1.
Fancy (section)
Fancy markets use section instead of runners. Each section entry has a name (nat), a status (gstatus), and an odds ladder.
Fields not exposed
Certain provider-only fields are omitted from the public API.
Event objects do not include
betfairEventIdfeed_source
Markets do not include
tvtvChannelodd_type
Do not depend on these fields. Additional public fields may be added later; ignore unused keys.
Refresh and usage
- Each response contains the odds currently available at request time.
- The API does not wait for a new upstream update before responding.
- Calling the single-match endpoint keeps that match prioritized for refresh while you continue requesting it.
- Repeated requests extend that active period.
- Continue polling while the match is displayed or otherwise in use.
- Stop polling when the match is no longer needed.
The API does not guarantee real-time odds or a fixed freshness window.
Recommended polling
Poll the single-match endpoint at the frequency required by your application while the match is actively being displayed.
There is no published polling interval and no guaranteed push or real-time update. Reuse HTTP connections where possible.
Errors
Every error body has the same shape:
{
"error": "event_not_found",
"message": "Match not found"
}
| HTTP | error | Meaning | Client action |
|---|---|---|---|
| 400 | invalid_sport | Unsupported sport slug | Use a supported slug |
| 400 | invalid_event_id | Event ID is not a positive integer | Use gmid from the match list |
| 403 | ip_not_allowed | Calling IP is not allowlisted | Confirm the server public IP with the operator |
| 404 | not_found | Unknown URL | Check the path |
| 404 | event_not_found | Match is not in that sport's list | Refresh the match list |
| 404 | odds_not_found | Odds are not available for this match | Retry later or skip the event |
| 429 | rate_limited | Rate limit exceeded | Wait / back off; honour Retry-After if present |
| 500 | internal_error | Unexpected server error | Retry later |
| 502 | malformed_upstream_data | Upstream data could not be read | Retry later |
| 503 | catalog_unavailable | Match data is not available yet | Retry shortly |
| 503 | redis_unavailable | Backend data store unavailable | Retry later |
| 503 | security_config_unavailable | Service is temporarily unavailable | Retry later |
| 504 | redis_timeout | Backend data store timed out | Retry later |
invalid_sport message:
Unsupported sport. Supported sports: cricket, football, tennis, horse-racing, greyhound-racing
Rate limiting
Requests may be rate limited.
- HTTP 429 with
"error": "rate_limited"means the current limit has been exceeded. - Wait and back off before retrying.
- If a
Retry-Afterheader is present, wait that many seconds.
The numeric limit is set by the operator and is not a fixed public contract.
IP allowlist
Before integration, provide the public IP address(es) from which your systems will call the API.
If the IP is not allowed:
HTTP/1.1 403 Forbidden
{
"error": "ip_not_allowed",
"message": "Client address is not allowed"
}
Use a stable egress IP. Calls from an unlisted laptop, NAT, or proxy will be rejected.
Integration flow
- Call the sport match list.
- Read each event's
gmid. - Call the single-match endpoint with that ID.
- Parse
eventandodds. - Poll the single-match endpoint while the match is in use.
- Stop polling when the match is finished or no longer needed.
# 1. List cricket matches
curl -sS "https://oddsfeed.starluck.cloud/api/v1/cricket/matches"
# 2–3. Fetch one match and its odds (replace with a gmid from step 1)
curl -sS "https://oddsfeed.starluck.cloud/api/v1/cricket/matches/1789048569"
JavaScript example
const response = await fetch(
"https://oddsfeed.starluck.cloud/api/v1/cricket/matches/1789048569"
);
const data = await response.json();
On success, data.event_id is the event ID, data.event is the match, and data.odds is the market list.
Client implementation notes
- Reuse HTTP connections where possible.
- Handle 403 as an access problem (IP not allowlisted).
- Handle 429 with backoff; honour
Retry-After. - Handle 503 / 504 as temporary backend failures.
- Handle 404 as an unavailable event, missing odds, or unknown route.
- Do not assume hidden/internal fields exist.
- Allow additional fields for future compatibility.
FAQ
Which sports are supported?
cricket, football, tennis, horse-racing, greyhound-racing.
How do I get an event ID?
Call GET /api/v1/{sport}/matches and use each event's gmid.
Does the match-list endpoint return odds?
No. It returns match/event data only. Use the single-match endpoint for markets and odds.
Does the single-match endpoint return all available markets?
Yes. odds is the complete list of markets currently available for that event. The array may be empty.
Do I need an API key?
No. Access is by IP allowlist.
What IP needs to be allowlisted?
The public IP of the server that will send the HTTP requests.
What does 403 mean?
The calling IP is not allowlisted (ip_not_allowed).
What does 429 mean?
The rate limit has been exceeded (rate_limited). Back off and retry.
What does 404 mean?
The event is not in that sport's list (event_not_found), odds are not available (odds_not_found), or the URL does not exist (not_found).
Should I keep polling?
Yes, while the match is displayed or in use. Stop when it is no longer needed.
Does the API guarantee real-time odds?
No. Responses contain the currently available odds at request time. The API does not wait for a new upstream update before responding.