TAB APItab.com.au ↗
Retrieve horse racing meetings, race cards, fixed odds, and results from TAB Australia. Covers thoroughbred, harness, and greyhound racing across all states.
What is the TAB API?
The TAB.com.au API exposes 5 endpoints covering Australian racing meetings, race cards, fixed odds, and results. Use get_racing_meetings_by_date to pull all meetings for a given day filtered by jurisdiction, or hit get_next_to_jump_races for a live feed of upcoming races across all venues and race types without specifying any parameters.
curl -X GET 'https://api.parse.bot/scraper/5137d70d-0c2b-4de4-a5a9-1554bd34c3e9/get_racing_meetings_by_date' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace tab-com-au-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""
TAB Australia API Client
Horse racing data, sports betting odds, and account information from TAB.com.au
Get your API key from: https://parse.bot/settings
"""
import os
import requests
from typing import Optional, Any, Dict, List
from datetime import datetime
class ParseClient:
"""Client for interacting with the TAB Australia API via Parse."""
def __init__(self, api_key: Optional[str] = None):
"""
Initialize the Parse API client.
Args:
api_key: API key for authentication. If not provided, reads from PARSE_API_KEY env var.
"""
self.base_url = "https://api.parse.bot"
self.scraper_id = "38bc6ea2-d123-477f-bf57-9b9312f634d8"
self.api_key = api_key or os.getenv("PARSE_API_KEY")
self.session_id: Optional[str] = None
self.encryption_key: Optional[str] = None
if not self.api_key:
raise ValueError("API key must be provided or set as PARSE_API_KEY environment variable")
def _call(
self,
endpoint: str,
method: str = "POST",
**params
) -> Dict[str, Any]:
"""
Make an API call to the Parse scraper.
Args:
endpoint: The endpoint name (e.g., "get_racing_meetings_by_date")
method: HTTP method ("GET" or "POST")
**params: Parameters to pass to the endpoint
Returns:
Response data as a dictionary
Raises:
requests.exceptions.RequestException: If the API call fails
"""
url = f"{self.base_url}/scraper/{self.scraper_id}/{endpoint}"
headers = {
"X-API-Key": self.api_key,
"Content-Type": "application/json"
}
# Add session info if available
if self.session_id:
params["sessionId"] = self.session_id
if self.encryption_key:
params["encryptionKey"] = self.encryption_key
try:
if method == "GET":
response = requests.get(url, headers=headers, params=params)
elif method == "POST":
response = requests.post(url, headers=headers, json=params)
else:
raise ValueError(f"Unsupported HTTP method: {method}")
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"API Error calling {endpoint}: {e}")
raise
def login(self, username: str, password: str) -> Dict[str, Any]:
"""
Authenticate a user to obtain a session token.
Args:
username: Account username
password: Account password
Returns:
Response containing accessToken and user info
"""
response = self._call(
"login",
method="POST",
username=username,
password=password
)
# Store session info for subsequent calls
if "accessToken" in response:
self.session_id = response.get("accessToken")
return response
def get_racing_meetings_by_date(
self,
date: Optional[str] = None,
jurisdiction: str = "NSW"
) -> List[Dict[str, Any]]:
"""
Retrieve all racing meetings for a given date.
Args:
date: Date in YYYY-MM-DD format. Defaults to today.
jurisdiction: State jurisdiction code (NSW, VIC, QLD, etc.)
Returns:
List of meeting objects
"""
params = {"jurisdiction": jurisdiction}
if date:
params["date"] = date
response = self._call(
"get_racing_meetings_by_date",
method="GET",
**params
)
return response.get("meetings", [])
def get_next_to_jump_races(self) -> List[Dict[str, Any]]:
"""
Retrieve the next races to jump across all venues and race types.
Returns:
List of race objects with startTime and raceName
"""
response = self._call(
"get_next_to_jump_races",
method="GET"
)
return response.get("races", [])
def get_race_card(
self,
date: str,
venue_code: str,
venue: str,
race_number: int,
race_type: str
) -> Dict[str, Any]:
"""
Retrieve full race card/details for a specific race.
Args:
date: Race date (YYYY-MM-DD)
venue_code: Venue code
venue: Venue name slug
race_number: Race number
race_type: Race type (thoroughbred, harness, greyhound)
Returns:
Race card with raceName and runners list
"""
return self._call(
"get_race_card",
method="GET",
date=date,
venue_code=venue_code,
venue=venue,
race_number=race_number,
race_type=race_type
)
def get_race_fixed_odds(
self,
date: str,
venue_code: str,
venue: str,
race_number: int,
race_type: str
) -> List[Dict[str, Any]]:
"""
Retrieve current fixed odds for a specific race.
Args:
date: Race date (YYYY-MM-DD)
venue_code: Venue code
venue: Venue name slug
race_number: Race number
race_type: Race type
Returns:
List of fixed odds with runnerNumber, winPrice, and placePrice
"""
response = self._call(
"get_race_fixed_odds",
method="GET",
date=date,
venue_code=venue_code,
venue=venue,
race_number=race_number,
race_type=race_type
)
return response.get("fixedOdds", [])
def get_race_results(
self,
date: str,
venue_code: str,
venue: str,
race_number: int,
race_type: str
) -> Dict[str, Any]:
"""
Retrieve final results for a completed race.
Args:
date: Race date (YYYY-MM-DD)
venue_code: Venue code
venue: Venue name slug
race_number: Race number
race_type: Race type
Returns:
Results with finishing positions and dividends
"""
return self._call(
"get_race_results",
method="GET",
date=date,
venue_code=venue_code,
venue=venue,
race_number=race_number,
race_type=race_type
)
def get_account_balance(self) -> float:
"""
Retrieve the authenticated user's account balance.
Requires prior login.
Returns:
Available balance as a float
"""
response = self._call(
"get_account_balance",
method="GET"
)
return response.get("availableBalance", 0.0)
if __name__ == "__main__":
# Initialize client with API key from environment
client = ParseClient()
print("=" * 60)
print("TAB Australia Racing API - Practical Workflow Example")
print("=" * 60)
# Step 1: Check upcoming races
print("\n[1] Getting next races to jump...")
next_races = client.get_next_to_jump_races()
if next_races:
upcoming_race = next_races[0]
print(f" Next race: {upcoming_race.get('raceName')} at {upcoming_race.get('startTime')}")
# Step 2: Get today's meetings
print("\n[2] Getting today's racing meetings (NSW)...")
today = datetime.now().strftime("%Y-%m-%d")
meetings = client.get_racing_meetings_by_date(date=today, jurisdiction="NSW")
if meetings:
print(f" Found {len(meetings)} meetings:")
for meeting in meetings[:3]: # Show first 3
print(f" - {meeting.get('meetingName')} ({meeting.get('venueCode')})")
# Step 3: Get race card for first meeting
if meetings:
first_meeting = meetings[0]
venue_code = first_meeting.get("venueCode", "R")
venue_slug = first_meeting.get("meetingName", "RANDWICK").lower()
print(f"\n[3] Getting race card for Race 1 at {first_meeting.get('meetingName')}...")
try:
race_card = client.get_race_card(
date=today,
venue_code=venue_code,
venue=venue_slug,
race_number=1,
race_type="R"
)
race_name = race_card.get("raceName", "Race 1")
runners = race_card.get("runners", [])
print(f" Race: {race_name}")
print(f" Runners ({len(runners)}):")
for runner in runners[:5]: # Show first 5 runners
print(f" - #{runner.get('number')}: {runner.get('name')}")
# Step 4: Get odds for this race
print(f"\n[4] Getting fixed odds for Race 1...")
odds = client.get_race_fixed_odds(
date=today,
venue_code=venue_code,
venue=venue_slug,
race_number=1,
race_type="R"
)
print(f" Found {len(odds)} odds entries:")
for odd in odds[:3]: # Show first 3
runner_num = odd.get("runnerNumber")
win_price = odd.get("winPrice")
place_price = odd.get("placePrice")
print(f" - Runner {runner_num}: Win ${win_price:.2f}, Place ${place_price:.2f}")
except Exception as e:
print(f" (Unable to fetch detailed race info: {e})")
# Step 5: Authentication flow (commented out without valid credentials)
print("\n[5] Authentication Example (requires valid credentials):")
print(" To access account balance, login with:")
print(" >>> client.login(username='your_username', password='your_password')")
print(" >>> balance = client.get_account_balance()")
print(" >>> print(f'Account Balance: ${balance:.2f}')")
print("\n" + "=" * 60)
print("Workflow completed successfully!")
print("=" * 60)Retrieve all racing meetings for a given date across all race types.
| Param | Type | Description |
|---|---|---|
| date | string | Date in YYYY-MM-DD format. Defaults to today. |
| jurisdiction | string | State jurisdiction code (NSW, VIC, QLD, etc.) |
{
"type": "object",
"fields": {
"meetings": "array"
},
"sample": {
"meetings": [
{
"raceType": "R",
"venueCode": "R",
"meetingName": "RANDWICK"
}
]
}
}About the TAB API
Racing Meetings and Next to Jump
get_racing_meetings_by_date returns a meetings array for any date in YYYY-MM-DD format, optionally filtered by a state jurisdiction code (NSW, VIC, QLD, etc.). Omit the date parameter and it defaults to today. get_next_to_jump_races takes no inputs and returns a races array reflecting the current queue of imminent races across all venues — useful for real-time dashboards or alert systems that need to react to race start times without polling a full meeting list.
Race Cards and Fixed Odds
Both get_race_card and get_race_fixed_odds require four identifying parameters — date, venue (as a name slug), venue_code, and race_number — plus a race_type of thoroughbred, harness, or greyhound. get_race_card returns a runners array and a raceName string, giving you the full field for a specific race. get_race_fixed_odds returns a fixedOdds array reflecting current TAB-listed odds for each runner in that race.
Race Results
get_race_results uses the same five-parameter signature and returns a results array alongside a dividends object once a race is complete. The dividends object covers payout data for the applicable bet types for that race. This endpoint is only meaningful after a race has been run — querying a future race will not return result data.
Coverage Notes
The API covers the three race types TAB supports: thoroughbred, harness, and greyhound racing. All endpoints that target a specific race share a consistent parameter set, so venue and date references are interchangeable across the race card, odds, and results calls for the same event.
The TAB API is a managed, monitored endpoint for tab.com.au — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when tab.com.au changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official tab.com.au API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Build a race-day dashboard that lists all Australian meetings by state using
get_racing_meetings_by_datefiltered by jurisdiction code - Power a 'next to jump' widget on a betting or sports news site using the
get_next_to_jump_racesendpoint - Display full race fields including runner names by fetching the
runnersarray fromget_race_card - Track current fixed odds movements for a specific race by polling
get_race_fixed_oddson a schedule - Record historical race outcomes and dividends by querying
get_race_resultsafter each race completes - Build a multi-race comparison tool for greyhound or harness races by iterating race numbers across a venue
- Alert users when a monitored runner's odds change by comparing successive
fixedOddsarray responses
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does TAB.com.au have an official developer API?+
What does get_race_fixed_odds return, and how current is the data?+
fixedOdds array for the specified race, reflecting TAB's current fixed-price odds for each runner. Odds on TAB can change up to race start, so the freshness of the data depends on when you call the endpoint. For live odds tracking, periodic polling is the appropriate approach.Does the API cover sports betting markets, not just racing?+
Can I retrieve results and dividends for exotic bets like trifectas or first fours?+
get_race_results returns a dividends object that reflects payout data for the applicable bet types for that race. The specific bet types included in the dividends object depend on what TAB settles for each race. If you need to filter or expand dividend coverage beyond what the current endpoint returns, you can fork the API on Parse and revise the endpoint logic.Do I need both venue and venue_code to query a specific race?+
get_race_card, get_race_fixed_odds, and get_race_results all require both the venue slug and the venue_code alongside the date, race_type, and race_number. You can obtain the venue slug and code from the meetings array returned by get_racing_meetings_by_date.