CTBAPI Betting API Reference

Published by

A REST API for placing racing bets on the exchange without touching the platform by hand. You authenticate, list the meetings and races on offer, pick your runners, and submit win and place bets at the stake, ticket price and limits you set. The requests and responses below are illustrative examples.

Last updated

Reference. The requests and responses below are illustrative examples. Access is provisioned per client once an account is opened and funded, and your key is scoped to that single account. Request access to get started.

Overview

The betting API turns a full bet-placement run into a short sequence of HTTP calls. It mirrors exactly what the platform does by hand: pick a country and pool, drill into a meeting and race, choose one or more runners, then place win and/or place bets with a stake, a ticket price and an accepted limit range. The API confirms each bet and returns a receipt you can poll for its status.

Base URL

https://api.ctbapi.com/v1

All endpoints are relative to this base URL. Access is provisioned per client, and your issued key is scoped to a single funded account.

Conventions

Authentication

Every request carries your API key as a bearer token. The key maps to a single funded account on the backend; the underlying platform credentials never leave the server and are never exposed through the API.

curl https://api.ctbapi.com/v1/meetings \
  -H "Authorization: Bearer $CTBAPI_KEY"

Keep the key server-side. A missing or invalid key returns 401 unauthorized.

The placement flow

  1. List meetings for a country, discipline and pool.
  2. List races within the chosen meeting.
  3. List runners for the chosen race.
  4. Place bets: win and/or place, with stake, ticket price and limits.
  5. Read the receipt to confirm the bet was matched.

Endpoints at a glance

Betting API endpoints
MethodPathPurpose
GET/v1/meetingsList meetings by country, discipline, pool
GET/v1/meetings/{id}/racesList races in a meeting
GET/v1/races/{id}/runnersList runners in a race
POST/v1/betsPlace win and/or place bets
GET/v1/bets/{id}Read a bet's status and receipt

List meetings

GET /v1/meetings. Filter by country, discipline (horse, harness or greyhound) and pool (for example S-TAB or NSW).

curl "https://api.ctbapi.com/v1/meetings?country=AU&discipline=horse&pool=NSW" \
  -H "Authorization: Bearer $CTBAPI_KEY"
{
  "data": [
    {
      "meeting_id": "mtg_au_randwick_20260920",
      "country": "AU",
      "discipline": "horse",
      "pool": "NSW",
      "venue": "Randwick",
      "date": "2026-09-20",
      "races": 9
    }
  ]
}

List races

GET /v1/meetings/{meeting_id}/races. Returns the races in the meeting with their scheduled start times and status.

curl "https://api.ctbapi.com/v1/meetings/mtg_au_randwick_20260920/races" \
  -H "Authorization: Bearer $CTBAPI_KEY"
{
  "data": [
    { "race_id": "rce_randwick_r5", "number": 5, "start": "2026-09-20T06:40:00Z", "status": "open" },
    { "race_id": "rce_randwick_r6", "number": 6, "start": "2026-09-20T07:15:00Z", "status": "open" }
  ]
}

List runners

GET /v1/races/{race_id}/runners. Returns the runners for the race, each with its number and current best price.

curl "https://api.ctbapi.com/v1/races/rce_randwick_r5/runners" \
  -H "Authorization: Bearer $CTBAPI_KEY"
{
  "data": [
    { "runner_id": "run_r5_07", "number": 7, "name": "Northern Light", "best_price": "4.50" },
    { "runner_id": "run_r5_03", "number": 3, "name": "Coastal Runner", "best_price": "6.00" }
  ]
}

Place bets

POST /v1/bets is the core call. One request can carry both a win and a place bet on the same runner. The fields map directly to a manual placement:

The example below places a 10 win / 10 place bet at a ticket price of 4.50, accepting a limit range of 30 to 120.

curl -X POST https://api.ctbapi.com/v1/bets \
  -H "Authorization: Bearer $CTBAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "race_id": "rce_randwick_r5",
    "runner_id": "run_r5_07",
    "bets": [
      { "type": "win",   "stake": "10.00" },
      { "type": "place", "stake": "10.00" }
    ],
    "ticket_price": "4.50",
    "limit": { "min": "30.00", "max": "120.00" }
  }'
{
  "bet_id": "bet_8a1f6c2d",
  "status": "submitted",
  "race_id": "rce_randwick_r5",
  "runner_id": "run_r5_07",
  "legs": [
    { "type": "win",   "stake": "10.00", "matched": "0.00" },
    { "type": "place", "stake": "10.00", "matched": "0.00" }
  ],
  "ticket_price": "4.50",
  "submitted_at": "2026-09-20T06:31:12Z"
}

Read the receipt

GET /v1/bets/{bet_id}. Poll this to watch the bet move from submitted to matched (fully or partly) or voided, and to read the matched amounts.

curl "https://api.ctbapi.com/v1/bets/bet_8a1f6c2d" \
  -H "Authorization: Bearer $CTBAPI_KEY"
{
  "bet_id": "bet_8a1f6c2d",
  "status": "matched",
  "legs": [
    { "type": "win",   "stake": "10.00", "matched": "10.00", "price": "4.50" },
    { "type": "place", "stake": "10.00", "matched": "10.00", "price": "1.80" }
  ],
  "matched_at": "2026-09-20T06:31:14Z"
}

Bet status values

Errors

Errors use standard HTTP status codes with a JSON body carrying a stable code and a human-readable message.

{
  "error": {
    "code": "insufficient_funds",
    "message": "Account balance is below the requested stake."
  }
}
Common error codes
StatusCodeMeaning
401unauthorizedMissing or invalid API key
404not_foundUnknown meeting, race, runner or bet
409race_closedThe race is no longer accepting bets
422insufficient_fundsAccount balance below the stake
429rate_limitedToo many requests; retry after the header delay

Getting access

Live keys are issued once an account is opened and funded, so the API has a balance to bet from. To be provisioned, start with the request form, or reach us on Telegram. For how accounts are opened and funded, see about CTBAPI and the USDT deposits guide.

CTBAPI is not affiliated with or endorsed by any betting platform. Betting involves risk and you can lose money. See our responsible gambling page.