CompWatch logo
CompWatch

6,159 live competitions

Data Licence API

A REST feed of the UK prize-competition market: every live competition across 414 sites with prices, odds and live sell-through, plus (on higher tiers) derived value data and a full sell-through history archive. JSON by default, CSV on request.

← Tiers & pricing

On this page

Base URL & versioning

All endpoints are served under a single versioned prefix. Paths below are relative to it.

https://compwatch.co.uk/api/v1

Authentication

Every request needs a bearer token sent in the Authorization header. Generate a token from the API Data Access section of your account page (available once your licence is active). The token is shown once — store it securely; regenerating revokes the old one.

curl https://compwatch.co.uk/api/v1/competitions \
  -H "Authorization: Bearer <YOUR_TOKEN>" \
  -H "Accept: application/json"

A valid token without an active licence returns 402; a missing or bad token returns 401.

Tiers & rate limits

Your tier determines which fields and endpoints you can access, and your request budget. Limits are per token.

Tier Price Req/min Req/day Incremental sync Value layer History archive
snapshot £500/mo 30 2,000 — — —
sync £1,500/mo 120 100,000 Yes Yes —
intelligence On application 300 1,000,000 Yes Yes Yes

Exceeding a limit returns 429 Too Many Requests. The value layer = predicted final odds, expected value and cash alternative. The history archive = the per-competition sell-through time-series.

Pagination & formats

List responses are cursor-paginated at up to 200 rows per page. Each response's meta.next_cursor is the cursor for the next page (null on the last page). Pass it back as ?cursor=.

curl "https://compwatch.co.uk/api/v1/competitions?cursor=eyJfcG9pbnRzVG8iO..." \
  -H "Authorization: Bearer <YOUR_TOKEN>"

Responses are JSON by default. Add ?format=csv to the list endpoint for a streamed CSV download (nested objects such as forecast are serialised to JSON within their column).

Endpoints

GET /competitions All tiers

Active competitions (not yet ended), ordered by closing time, tier-enriched.

Query parameters

  • cursor — pagination cursor from meta.next_cursor.
  • format=csv — return a streamed CSV instead of JSON.
  • updated_since=<ISO 8601> — (Sync tier +) return everything changed since a timestamp, including just-closed competitions, ordered by updated_at. Ideal for keeping a local copy in step. Requesting it below the Sync tier returns 403; a malformed timestamp returns 422.
curl "https://compwatch.co.uk/api/v1/competitions?updated_since=2026-09-01T00:00:00Z" \
  -H "Authorization: Bearer <YOUR_TOKEN>"
GET /competitions/{id} All tiers

A single competition by its id (the opaque id returned in list responses).

curl https://compwatch.co.uk/api/v1/competitions/aB3xY \
  -H "Authorization: Bearer <YOUR_TOKEN>"
GET /competitions/{id}/history Intelligence tier

The sell-through time-series for one competition — a series of observations of tickets sold over time. This is the historical data that can't be reconstructed by scraping the live site. Below the Intelligence tier this returns 403.

curl https://compwatch.co.uk/api/v1/competitions/aB3xY/history \
  -H "Authorization: Bearer <YOUR_TOKEN>"
GET /sites All tiers

The site directory with trust ratings (letter grades) and qualitative trust indicators. Numeric trust scores, weights and thresholds are never exposed.

curl https://compwatch.co.uk/api/v1/sites \
  -H "Authorization: Bearer <YOUR_TOKEN>"

Response schema

Competition object

Returned by /competitions and /competitions/{id}. Base fields are on every tier; the value layer is included only on tiers with value-layer access (Sync and above).

FieldTypeTierDescription
id string All Opaque competition id (use in single/history paths).
site string All Site slug (join to /sites).
prize string All Prize / competition title.
category string|null All Prize category name.
url string All Canonical URL of the competition on the operator site.
image_url string|null All Proxied image URL (or null).
price_in_pence integer|null All Ticket price in pence.
currency string All Always "GBP".
ends_at string|null All Closing time (ISO 8601).
tickets_sold integer|null All Tickets sold so far.
total_tickets integer|null All Ticket cap (null if uncapped/unknown).
tickets_available integer|null All Remaining tickets.
percent_sold number|null All Percent of the cap sold.
odds string|null All Current odds of winning at present sales.
odds_if_sold_out string|null All Odds if the competition sells out.
closed boolean All Whether the closing time has passed.
updated_at string All Last update (ISO 8601) — the field updated_since filters on.
forecast.predicted_odds string|null Sync + Model-predicted final odds.
forecast.confidence string|null Sync + Forecast confidence label: "high", "medium" or "low" (how much site-specific history backs it).
ev_per_pound number|null Sync + Expected value per £1 spent.
cash_alternative_in_pence integer|null Sync + Cash alternative to the prize, if offered.
estimated_value_pence integer|null Sync + Estimated prize value.

List responses wrap the array in data and carry a meta object:

History object (Intelligence)

{
  "data": {
    "id": "aB3xY",
    "prize": "…",
    "series": [
      { "observed_at": "…", "tickets_sold": 1200, "total_tickets": 5000,
        "price_in_pence": 199, "ends_at": "…" }
    ]
  },
  "meta": { "points": 1, "tier": "intelligence" }
}

series is ordered oldest-first; each entry is one observation we recorded:

meta.points = the number of observations in series (its length); meta.tier = the tier served.

Site object

Returned by /sites. Fields: slug, name, base_url, company_name, company_founded_year, trust_rating (letter grade only, e.g. "A", "B"), and an indicators object of booleans:

odds_published, transparent_draw, winners_published, free_entry, secure_payments, voluntary_code, player_protection, age_verification, charitable_contributions

Each indicator mirrors a public trust indicator (true = the site meets it). The /sites response isn't paginated; its meta carries count (total sites returned) and generated_at.

Errors

Errors return the appropriate HTTP status with a JSON error message.

StatusMeaning
401Missing or invalid bearer token.
402Token is valid but the account has no active data licence.
403Feature not in your tier (e.g. updated_since below Sync, or history below Intelligence).
404Competition not found.
422Invalid parameter (e.g. a malformed updated_since timestamp).
429Rate limit exceeded for your tier.

Ready to start?

Choose a tier and subscribe, then generate your API token from your account page.

View tiers & subscribe