Integrations · Public documentation

CueTracker API

Build dashboards, reports and club tools with the functionality available in CueTracker today.

Current API v1Bearer authentication
CueTracker API v1 is read-only.

The six GET operations below are supported. API keys cannot create, update or delete CueTracker data.

Get started

  1. Sign in to CueTracker with a saved account.
  2. Open an owned club, choose Settings, then expand API settings.
  3. Create a named API key and copy it immediately. The complete key is shown once.
  4. Send the key in the Authorization header on every request.

Keys begin with ct_live_. Treat them like passwords: keep them out of source control, screenshots and logs. You can revoke a key from the same Club Settings menu.

HTTP authentication
Authorization: Bearer ct_live_your_key_here
Request example
GET /api/v1/clubs HTTP/1.1
Host: 8ball.cuetracker.app
Authorization: Bearer ct_live_your_key_here
Accept: application/json

Plans and access

PlanRead operationsWrite operations
ProAll six GET operationsNot supported
EliteAll six GET operationsNot supported

Every key is read-only and tied to the account that created it. An account can keep up to five active keys, and each active key must have a unique name. A key can access only clubs currently owned by that account. Saved keys remain listed after a plan downgrade, but requests are disabled until the account again has API access. Revoked keys and keys belonging to deleted accounts are rejected.

What you can build

CueTracker already includes venue displays, live scoring, fixtures, player statistics, leaderboards and reports. The API is for clubs that want to present that same data differently, calculate something CueTracker does not currently calculate, combine it with another system, or build a workflow tailored to their venue. CueTracker remains the source of truth while your integration receives a read-only copy.

Your own design

Replace CueTracker’s layout with your club’s preferred branding, accessibility choices, sponsor panels, broadcast graphics or information hierarchy.

Club website integration

Place selected results, fixtures or player records inside an existing website so members do not need to visit a separate results page.

Custom awards and handicaps

Calculate a club-specific grading, handicap, points race, qualification rule or end-of-season award that is not part of CueTracker’s built-in statistics.

Committee and sponsor packs

Combine match data with attendance, membership, bar, sponsorship or accounting data to prepare reports for committees, sponsors or grant applications.

Multi-club analysis

Compare several clubs owned by the same account, build an association-wide summary, or identify participation and scheduling trends across venues.

Private archive and data lab

Copy permitted records into a private warehouse for long-term analysis, experimental visualisations, forecasting or an independent backup of exported results.

Print and signage workflows

Generate a custom honour board, presentation-night booklet, sponsor slideshow, draw sheet or accessibility-focused display from current club data.

Bots and staff tools

Answer a club-specific question in a private bot, pre-fill an operations sheet, or surface exactly the few figures a volunteer needs for their role.

If CueTracker’s built-in page already suits the job, use it—the API does not require you to rebuild existing features. Use the API when you need a different presentation, extra calculation or connection to another tool. It is designed for snapshots and periodic refreshes; a dashboard commonly refreshes every 30–60 seconds and backs off after an error. For immediate event-driven actions—lights, announcements and live automations—use MQTT instead of repeatedly polling.

API v1 endpoints

GET/api/v1/clubs

All clubs owned by the key’s account, with calculated statistics.

GET/api/v1/clubs/:id

One owned club, its statistics and its latest 100 match summaries.

GET/api/v1/clubs/:id/matches

Cursor-paginated live and completed match history.

GET/api/v1/clubs/:id/players/:playerId

One local player’s statistics, optionally scoped by date.

GET/api/v1/clubs/:id/leaderboard

A server-ranked player leaderboard.

GET/api/v1/clubs/:id/fixtures

Scheduled or completed scheduled-match fixtures.

List owned clubs

Returns club identity and statistics for every club owned by the API-key account.

200 response
{
  "data": [
    {
      "id": "club-id",
      "name": "Example Club",
      "code": "ABC123",
      "stats": {
        "playerCount": 18,
        "fixtureCount": 3,
        "matchCount": 96,
        "matchesPlayed": 88,
        "framesPlayed": 214,
        "players": []
      }
    }
  ]
}

Get one owned club

The response contains the same club identity and statistics plus up to 100 recent match summaries. There is no pagination.

200 response shape
{
  "data": {
    "id": "club-id",
    "name": "Example Club",
    "code": "ABC123",
    "stats": { "playerCount": 18, "players": [] },
    "matches": [
      {
        "id": "match-id",
        "status": "finished",
        "format": "singles",
        "teams": {
          "A": { "name": "Craig" },
          "B": { "name": "Taylor" }
        },
        "score": { "A": 3, "B": 2 },
        "winner": "A"
      }
    ]
  }
}

Paginated match history

GET /api/v1/clubs/:id/matches accepts since, until, status (live, finished or cancelled), limit (25 by default, 100 maximum) and an opaque cursor. Dates filter the match start time and are inclusive. Pass pagination.nextCursor unchanged to obtain the next page; never construct or edit a cursor.

200 response shape
{
  "data": [{
    "id": "match-id",
    "name": "Friday Final",
    "format": "singles",
    "table": "Table 1",
    "startedAt": "2026-09-10T12:00:00.000Z",
    "finishedAt": "2026-09-10T13:15:00.000Z",
    "status": "finished",
    "players": [{ "id": "player-id", "name": "Craig" }],
    "winner": "Craig",
    "frameScores": [{ "frame": 1, "winner": "Craig", "score": { "A": 1, "B": 0 } }]
  }],
  "pagination": { "nextCursor": null, "hasMore": false }
}

Player statistics

GET /api/v1/clubs/:id/players/:playerId returns the same statistics fields used by stats.players[], plus playerId. Optional inclusive since and until values filter by completed-match time.

Leaderboard

GET /api/v1/clubs/:id/leaderboard accepts since, until, sortBy (winRate, matches or highRun) and limit. Each entry includes a one-based rank, player ID and the full calculated player-statistics shape.

Fixtures

GET /api/v1/clubs/:id/fixtures accepts inclusive from and to timestamps plus status (scheduled by default, or completed). With no from, scheduled results start from the current time. All returned timestamps are ISO 8601 UTC.

Returned fields

Club statistics

FieldMeaning
playerCountActive local players in the club.
fixtureCountRecorded fixtures.
matchCountAll match records.
matchesPlayedCompleted matches included in statistics.
framesPlayedCompleted frames.
playersCalculated statistics for players with recorded performance. Frames marked VOID STAT FRAME are excluded unless corrected by an Owner or Admin.

Player statistics

  • name
  • key
  • matches
  • wins
  • framesWon
  • framesLost
  • pots
  • visits
  • highRun
  • highRunCount
  • masterBreaks
  • masterFirstVisits
  • winRate
  • frameWinRate
  • avgPotsPerVisit

Match summaries

A summary can include match ID and code, name, table and table count, status, format, best-of configuration, teams and players, current or final score, frame history and frame statistics quality, shot-clock configuration, prize details, competition reference, winner, and start, scheduled, updated and end timestamps. Fields vary with match type and state; clients should tolerate absent optional fields.

Tools and code examples

Store the API key in an environment variable or a tool’s secret/authorization store. Do not put a key in a public Git repository, a shared screenshot or JavaScript delivered to a visitor’s browser. A public-facing dashboard should call CueTracker from its own small server or serverless function.

curl

Useful for a quick test on macOS, Linux, Windows Terminal, CI jobs and small shell scripts.

List clubs with curl
export CUETRACKER_API_KEY='ct_live_your_key_here'

curl --fail --silent --show-error \
  --header "Authorization: Bearer $CUETRACKER_API_KEY" \
  --header "Accept: application/json" \
  https://8ball.cuetracker.app/api/v1/clubs

HTTPie

HTTPie is convenient for readable command-line requests and inspecting response headers.

Top five by win rate
http GET \
  "https://8ball.cuetracker.app/api/v1/clubs/CLUB_ID/leaderboard?sortBy=winRate&limit=5" \
  "Authorization:Bearer $CUETRACKER_API_KEY"

JavaScript / Node.js

This example uses the built-in fetch available in current Node.js releases and produces rows suitable for a private dashboard.

Node.js leaderboard request
const baseUrl = 'https://8ball.cuetracker.app';
const clubId = process.env.CUETRACKER_CLUB_ID;
const key = process.env.CUETRACKER_API_KEY;

const response = await fetch(
  `${baseUrl}/api/v1/clubs/${clubId}/leaderboard?sortBy=matches&limit=10`,
  { headers: { Authorization: `Bearer ${key}` } }
);

if (!response.ok) throw new Error(`CueTracker returned ${response.status}`);
const { data } = await response.json();
console.table(data.map(row => ({
  rank: row.rank,
  player: row.name,
  matches: row.matches,
  wins: row.wins
})));

Python

A practical starting point for scheduled reports, CSV exports or sending prepared data into a BI system.

Python match-history request
import os
import requests

base_url = "https://8ball.cuetracker.app"
club_id = os.environ["CUETRACKER_CLUB_ID"]
headers = {"Authorization": f"Bearer {os.environ['CUETRACKER_API_KEY']}"}
params = {"status": "finished", "limit": 100}

response = requests.get(
    f"{base_url}/api/v1/clubs/{club_id}/matches",
    headers=headers,
    params=params,
    timeout=20,
)
response.raise_for_status()
page = response.json()

for match in page["data"]:
    print(match["finishedAt"], match["name"], match["winner"])

# If page["pagination"]["hasMore"] is true, send nextCursor back
# unchanged as the cursor query parameter for the next request.

Postman, Insomnia and Bruno

  1. Create a GET request using one of the documented endpoint URLs.
  2. Choose Bearer Token authorization and store the key in a private environment variable, not in the shared request definition.
  3. Add query parameters in the tool’s Params panel, then send the request and inspect the JSON response and rate-limit headers.
  4. Save separate environments for staging and production so test requests cannot accidentally target live club data.

Node-RED, Home Assistant, Excel and BI tools

Node-RED’s HTTP Request node can call the API on a timer, then transform the JSON into a dashboard or report. Home Assistant can use a REST sensor for a small periodic total, although MQTT is better for immediate match events. Excel Power Query and Power BI can consume JSON through a controlled query or gateway. Keep the bearer key in the tool’s credential store or an intermediate service rather than embedding it in a publicly shared workbook.

PowerShell examples

PowerShell works well for Windows scheduled tasks and club reports. Store the key in an environment variable so it does not appear in the script.

List clubs
$env:CUETRACKER_API_KEY = 'ct_live_your_key_here'
$baseUrl = 'https://8ball.cuetracker.app'
$headers = @{ Authorization = "Bearer $env:CUETRACKER_API_KEY" }

$clubs = Invoke-RestMethod `
  -Method Get `
  -Uri "$baseUrl/api/v1/clubs" `
  -Headers $headers

$clubs.data | Select-Object name, code, id
Get a club and its recent matches
$clubId = $clubs.data[0].id
$club = Invoke-RestMethod `
  -Method Get `
  -Uri "$baseUrl/api/v1/clubs/$clubId" `
  -Headers $headers

$club.data.matches |
  Select-Object -First 10 status, matchName, score, endedAt

The repository also includes a longer CueTracker-ApiExamples.ps1 example for club, player and recent-match reporting.

HTTP errors and rate limits

Every response from the four extended read endpoints includes X-RateLimit-Remaining and X-RateLimit-Reset. The reset value is a Unix timestamp in seconds. They allow 120 requests per API key and source address in a rolling one-minute window.

StatusWhen it is returned
400Invalid or unsupported query input.
401Missing, invalid or revoked API key.
403The account plan does not currently include API access.
404The requested club, player or read operation is unavailable to the API key.
429The extended read-endpoint request limit has been reached.
Extended read endpoint error shape
{ "error": { "code": "INVALID_CURSOR", "message": "cursor is invalid or belongs to a different API key." } }

The original two club GET operations retain their existing { "error": "message" } shape so current integrations are not broken.

Current limitations

  • All operations are read-only and keys can access owned clubs only.
  • The club-detail response contains only its latest 100 match summaries; use the match-history endpoint for cursor pagination.
  • There are no competition or frame-detail endpoints.
  • Match creation, scoring, player changes and settings changes are not available through the API.
  • MQTT publishing is configured separately in an Elite club’s Settings; it is not an API endpoint. Saved MQTT configuration remains after a downgrade but publishing is disabled. See the MQTT guide.
  • Webhooks are not part of API v1.