API v1.0.0

MyCup API

Tournaments, teams, fixtures, results and standings — read and write. Download the OpenAPI 3.1 document Download the Postman collection to generate a client.

One API over everything MyCup does, for three audiences.

Platform credentials reach the whole estate and are issued to MyCup staff. Partner credentials are attached to an explicit list of tournaments; one credential can serve many. Public publishable keys are read-only and safe to embed in a front-end.

Platform and partner credentials use the client_credentials grant: POST your client_id and client_secret to /api/v1/oauth/token and send the returned access token as a bearer. Public keys are presented directly in the X-MyCup-Key header.

The rules are the panel's rules

The API is a second front-end, not a second back-end. Every restriction it applies is read from the same service the MyCup panel reads, so the two cannot drift:

  • Scopes narrow, they never widen. Every scope also requires the tournament permission behind it, so a credential can be narrower than any human role and never wider.
  • Plan limits answer 402 with the plan you would need, not 403.
  • A finished tournament freezes its structure and keeps its record editable: you can still correct a score or a kickoff time, but not add a team.
  • The public surface mirrors the website, page-visibility included. A page the organiser switched off returns 404 here too.

Conventions

Responses are {"data": …}, with meta and links on collections. Times are ISO-8601 with an offset. Errors carry a stable error.code — branch on that, never on the message, which is localised. Unsafe requests accept an Idempotency-Key header, which matters most on the destructive ones: regenerating a match list refuses with 409 and a list of what would be lost unless you pass confirm_destructive.

Quickstart

Exchange your credentials, then call an endpoint with the token:

# 1. Get a token (valid one hour by default)
curl -X POST https://mycup.me/api/v1/oauth/token \
  -H 'Content-Type: application/json' \
  -d '{"grant_type":"client_credentials","client_id":"mc_cl_…","client_secret":"mc_sk_…"}'

# 2. Use it
curl https://mycup.me/api/v1/tournaments/<url_key>/matches \
  -H 'Authorization: Bearer <access_token>'

# A publishable key needs no exchange
curl https://mycup.me/api/v1/public/tournaments/<url_key>/standings \
  -H 'X-MyCup-Key: mc_pk_…'

Errors

Every refusal has the same shape. Branch on error.code, which is stable; error.message is localised to your Accept-Language and will change.

{
  "error": {
    "code": "plan_limit_reached",
    "message": "This tournament's plan allows 16 participants.",
    "details": { "limit": 16, "current": 16, "required_plan": "Pro" }
  }
}
StatusMeans
401No credential, or one that has been revoked or has expired.
402Not on this tournament's plan, or a cap is full. details names the plan you need.
403The credential lacks the scope, the permission, or access to this tournament.
404Not found — or, publicly, a page this tournament does not publish.
409Conflicts with the tournament's state: finished, roster locked, or a destructive action awaiting confirmation.
422Validation failed. details.fields names each failing field.
429Rate limited. Retry-After says when to try again.

Authentication

Exchanging credentials for an access token.

GET /api/v1/me Describe the calling credential and the tournaments it reaches

Authentication

Bearer token
POST /api/v1/oauth/revoke Revoke the presented access token

Authentication

Bearer token
POST /api/v1/oauth/token Exchange credentials for an access token

The client_credentials grant, and the only grant. Credentials may travel in the body or as HTTP Basic. An unknown client_id and a wrong secret return the same error on purpose.

Authentication

None — this is where credentials are exchanged

Request body

FieldTypeDescription
grant_type string
client_id string
client_secret string
scope string Optional space-separated narrowing. Must be a subset of the grant.

Public

Read-only tournament data, authenticated with a publishable key. Mirrors the public website, page-visibility rules included: a page the organiser switched off returns 404 here too.

GET /api/v1/public/tournaments/{tournament} Get the tournament

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/public/tournaments/{tournament}/announcements List announcements

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/public/tournaments/{tournament}/assistants Top assist providers

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/public/tournaments/{tournament}/divisions List divisions

Returns an empty list for a tournament with one division or none — the same rule the website follows, so a front-end built on this API does not sprout a filter with one option in it.

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/public/tournaments/{tournament}/documents List documents

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/public/tournaments/{tournament}/matchdays List matchdays

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/public/tournaments/{tournament}/matches List fixtures

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
date query A calendar day in the tournament's own timezone.
from query Start of a date range (inclusive).
to query End of a date range (inclusive).
team query Matches involving this team, home or away.
division query Limit to one division.
phase query Limit to one phase.
matchday query Limit to one matchday.
status query not_started, in_progress or finished.
include query events
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/public/tournaments/{tournament}/matches/{match} Get the match

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
match * path Match id.
GET /api/v1/public/tournaments/{tournament}/phases List phases

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/public/tournaments/{tournament}/phases/{phase}/standings Standings for one phase

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
phase * path Phase id.
GET /api/v1/public/tournaments/{tournament}/players/{player} Get the player

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
player * path Player id.
GET /api/v1/public/tournaments/{tournament}/scorers Top scorers

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/public/tournaments/{tournament}/sponsors List sponsors

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/public/tournaments/{tournament}/staff/{staff} Get the staff member

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
staff * path Staff id.
GET /api/v1/public/tournaments/{tournament}/standings Standings for every phase

One call rather than discovering the phases and fanning out. Each table carries its tiebreaker chain, because a table sorted by rules the client cannot see eventually gets re-sorted wrongly.

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/public/tournaments/{tournament}/structure The tournament structure

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/public/tournaments/{tournament}/summary The end-of-tournament recap

Champions and podium come from the winners the organiser set in the Website editor, never inferred from standings — a custom bracket's champion is a decision, and deriving it from a table has been wrong often enough to be a rule. Returns 404 until the recap is published.

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/public/tournaments/{tournament}/teams List teams

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/public/tournaments/{tournament}/teams/{team} Get the team

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
GET /api/v1/public/tournaments/{tournament}/teams/{team}/players List a team's players

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
GET /api/v1/public/tournaments/{tournament}/teams/{team}/staff List a team's staff

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
GET /api/v1/public/tournaments/{tournament}/venues List venues

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/public/tournaments/{tournament}/venues/{venue} Get the venue

Authentication

Publishable key — X-MyCup-Key

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
venue * path Venue id.

Partner

Full read and write access to the tournaments a credential is attached to.

GET /api/v1/tournaments/{tournament} Get the tournament

Authentication

Bearer token

Scopes — any one of

tournaments:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
PATCH /api/v1/tournaments/{tournament} Update the tournament

Authentication

Bearer token

Scopes — any one of

tournaments:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/accommodation-bookings One group, in one accommodation, for one range of nights

check_out is the morning they leave, so the last night charged is the day before it; nights publishes that count rather than leaving it to be inferred.

CANCELLED bookings are returned by default. Their rooms went back to the allotment when they were cancelled, but the row stays because it is the list of who needs re-housing — filter on status if you only want live ones.

beds is capacity, not people. Compare it against the group's headcount: if the group is larger, somebody has nowhere to sleep.

Authentication

Bearer token

Scopes — any one of

hospitality:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
accommodation query Only stays at this accommodation.
group query Only stays by this group.
status query confirmed, pending or cancelled.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/tournaments/{tournament}/accommodation-bookings/{booking} Get the accommodation booking

Authentication

Bearer token

Scopes — any one of

hospitality:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
booking * path Booking id.
GET /api/v1/tournaments/{tournament}/accommodation-bookings/{booking}/rooming The rooming list for one booking

⚠️ ID NUMBERS AND DATES OF BIRTH ARE DELIBERATELY NOT RETURNED.

A rooming list holds passport numbers and dates of birth, very often of children. Inside MyCup the ID number is stored encrypted and both are purged on a schedule once the tournament is over. An API field would be a third copy leaving the building on every poll, with no consent story and no retention story.

What is published instead is the SHAPE of the list and its COMPLETENESS: which room, who is in it, and is_complete — false when a passport number or date of birth is still missing, which is the thing an integration is chasing. is_complete is the same predicate the organiser sees, so the two cannot disagree about which list is ready.

The identifying data continues to leave by the one audited route it already had: the organiser downloading the sheet and sending it to the hotel that asked for it.

Authentication

Bearer token

Scopes — any one of

hospitality:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
booking * path Booking id.
GET /api/v1/tournaments/{tournament}/accommodations Hotels, hostels and schools, with the room types they are holding

The whole Hospitality surface (accommodation and meals) is READ ONLY and requires hospitality:read.

Unlike the finance surface next door, the READS here are plan-gated too. A balance is a debt a club was already told about; a hotel contract — which accommodation, at what rate, through which named contact — is the commercial information the plan sells access to.

Each accommodation carries a STAY WINDOW: check_in is the first night it holds rooms for the tournament and check_out the morning after the last one (half-open, like a booking). Outside the window the accommodation holds nothing. Both are null on an accommodation that has not been dated yet, which keeps the pre-window behaviour (its room types count on every night).

units_contracted is the "Rooms held" of a room type: what the accommodation holds on EVERY night of its window, unless a night has an exception (a different number agreed for that night). Exceptions are not listed here because they only matter per night — /availability applies them.

bed_capacity is set on a school or pavilion sold by the bed rather than by the room (it then has no room types); null otherwise. bed_price is its rate per bed per night, when one is set.

What is LEFT is not here, because it is only meaningful for a date: ask /availability.

Authentication

Bearer token

Scopes — any one of

hospitality:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/tournaments/{tournament}/accommodations/{accommodation} Get the accommodation

Authentication

Bearer token

Scopes — any one of

hospitality:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
accommodation * path Accommodation id.
GET /api/v1/tournaments/{tournament}/accommodations/{accommodation}/availability What is left of each room type, night by night

Counted live by AccommodationInventory, the one place a remaining-unit count is worked out, so this can never disagree with the organiser's screen.

The range is HALF-OPEN: to is the morning people leave, so the last night counted is the day before it — the same convention a booking uses. remaining_across is the TIGHTEST night in the range, which is what decides whether a stay fits: a room free on three nights of four is not a room you can book for four.

Each night's held count respects the accommodation's stay window and its per-night exceptions: a night outside check_in–check_out holds 0, so a booking reaching past the window shows up as a negative number on those nights.

A negative number is a real answer, not an error. Booking past a hotel's allotment is allowed on purpose and warned about rather than blocked.

A school or pavilion sold by the bed has no room types: room_types is empty and beds carries its bed_capacity, the beds left per night, and remaining_across. beds is null for an accommodation sold by the room.

The range is CAPPED AT 90 NIGHTS. It drives a night-by-night walk, so an uncapped ?from=2020-01-01&to=2030-01-01 is ~3,650 nights times room types in one response. A longer range is a 422, not a truncated answer — 90 nights is longer than any festival this surface was built for.

Authentication

Bearer token

Scopes — any one of

hospitality:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
accommodation * path Accommodation id.
from query REQUIRED. First night, YYYY-MM-DD.
to query REQUIRED. Check-out day, YYYY-MM-DD — exclusive, so the last night counted is the day before it. At most 90 nights after `from`; longer ranges are rejected with 422.
GET /api/v1/tournaments/{tournament}/announcements List announcements

Authentication

Bearer token

Scopes — any one of

website:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/announcements Create an announcement

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PATCH /api/v1/tournaments/{tournament}/announcements/{announcement} Update the announcement

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
announcement * path Announcement id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/announcements/{announcement} Delete the announcement

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
announcement * path Announcement id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/assistants List assistants

Authentication

Bearer token

Scopes — any one of

results:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/tournaments/{tournament}/booking-forms Proforma invoices raised for participants

READ ONLY. Sending a booking form claims a document number, freezes every price, writes real debt to a participant's balance and emails a PDF in the organiser's name — four irreversible things in one step, in the organiser's own document series — so there is no write route and therefore no write scope.

A DRAFT has no number: it genuinely has none until it is sent, which is what keeps the series gapless. issuer and client are the blocks frozen at send and are null before it.

⚠️ An instalment's percent is a FRACTION of 1 — half is 0.5. percent_display carries the same value as the number an organiser typed (50), for rendering.

Not plan-gated, for the same reason reading a balance is not.

Authentication

Bearer token

Scopes — any one of

finances:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team query Only documents raised for this participant.
status query draft, sent, accepted or cancelled.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/tournaments/{tournament}/booking-forms/{document} Get the booking form

Authentication

Bearer token

Scopes — any one of

finances:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
document * path Document id.
GET /api/v1/tournaments/{tournament}/candidates List candidates

Every registration with its sales fields: source, owner, next follow-up, headcount, travel dates, billing, lost reason and last activity. The money keys — value, expected_revenue, collected, collected_minor and package — are ABSENT (not null) unless the credential holds finances:read and the tournament has the Finances plan.

Authentication

Bearer token

Scopes — any one of

candidates:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
status query pending, under_review, info_requested, approved, converted, rejected or withdrawn.
search query Part of the name or email.
division query A division id, or `none`.
country query ISO-2 code (e.g. PT), or `none`.
source query A lead source id or name (GET /lead-sources), or `none`. 422 when unknown.
owner query An owner's user id, or `none`.
follow_up query `overdue`, `today`, `week` (today + 6 days), `due` (today or earlier) or `none`, in the tournament's time zone.
created_from query YYYY-MM-DD, inclusive.
created_to query YYYY-MM-DD, inclusive.
has_managers query `true`: only registrations with a team manager; `false`: only those without.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/tournaments/{tournament}/candidates/{candidate} Get the candidate

One registration with its sales fields. As on the list, the money keys are absent without finances:read and the Finances plan.

Authentication

Bearer token

Scopes — any one of

candidates:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
candidate * path Candidate id.
PATCH /api/v1/tournaments/{tournament}/candidates/{candidate} Update a registration

Contact details, division and the sales fields. value.source is accepted, sent or draft (a booking form), manual (expected_revenue), estimate (the package) or none. source and lost_reason take an id or a name (case-insensitive; 422 when unknown). owner_user_id must be a member of the tournament (422). Setting status to rejected or withdrawn requires lost_reason (422); any other status clears it. converted cannot be set here — use /convert. A candidate that is already converted is a participant: changing its status answers 409 candidate_already_converted.

Authentication

Bearer token

Scopes — any one of

candidates:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
candidate * path Candidate id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
name string
contact_name string
email string
phone string
country_code string
tournament_division_id string
status string
source string Lead source id or name.
owner_user_id integer
next_follow_up_on string
pax object {players, staff, companions}, each 0-999 or null.
arrival_on string
departure_on string On or after arrival_on.
billing object {name, address, vat}.
lost_reason string Lost reason id or name.
note string Saved to the status history with a status change.
expected_revenue number The group's expected total in the tournament's currency, typed by hand (null clears it). It values the lead until a booking form exists. Money: needs `finances:write` (403) and the Finances plan (402).
DELETE /api/v1/tournaments/{tournament}/candidates/{candidate} Delete the candidate

Authentication

Bearer token

Scopes — any one of

candidates:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
candidate * path Candidate id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/candidates/{candidate}/activities A registration's activity

Logged calls, emails, meetings and notes plus what the system recorded (status changes with their note, owner changes, and — with finances:read — booking forms, payments and reminders), newest first. limit defaults to 30.

Authentication

Bearer token

Scopes — any one of

candidates:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
candidate * path Candidate id.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/candidates/{candidate}/activities Log an activity

A call, email, meeting or note. next_follow_up_on sets the next follow-up in the same transaction.

Authentication

Bearer token

Scopes — any one of

candidates:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
candidate * path Candidate id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
type string
body string
occurred_at string
next_follow_up_on string
POST /api/v1/tournaments/{tournament}/candidates/{candidate}/convert Convert a registration into a participant

Creates the team, copies the logo into the team's storage and sends the confirmation email, in one transaction. Refused with 402 if the plan's participant cap is already reached.

Authentication

Bearer token

Scopes — any one of

candidates:write teams:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
candidate * path Candidate id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PUT /api/v1/tournaments/{tournament}/candidates/{candidate}/package Set a registration's package

Customise the fees this lead is valued at: lines of {fee_id, quantity} (quantity only for per-person fees; null follows the headcount). lines: null goes back to the default package. Needs finances:write and the Finances plan.

Authentication

Bearer token

Scopes — any one of

finances:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
candidate * path Candidate id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
lines array
POST /api/v1/tournaments/{tournament}/candidates/{candidate}/reject Reject a registration

Marks the candidate rejected, with WHY: lost_reason (an id or a name from GET /lost-reasons, case-insensitive) is required and feeds the Lost reasons breakdown — 422 without it. A candidate that has already been converted cannot be rejected — delete the participant instead.

Authentication

Bearer token

Scopes — any one of

candidates:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
candidate * path Candidate id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
lost_reason string Id or name of a lost reason.
note string Saved to the status history.
GET /api/v1/tournaments/{tournament}/custom-attributes List custom attributes

Authentication

Bearer token

Scopes — any one of

custom-attributes:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/custom-attributes Create a custom attribute

Authentication

Bearer token

Scopes — any one of

custom-attributes:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/custom-attributes/{attribute} Get the custom attribute

Authentication

Bearer token

Scopes — any one of

custom-attributes:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
attribute * path Attribute id.
PATCH /api/v1/tournaments/{tournament}/custom-attributes/{attribute} Update the custom attribute

Authentication

Bearer token

Scopes — any one of

custom-attributes:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
attribute * path Attribute id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/custom-attributes/{attribute} Delete the custom attribute

Authentication

Bearer token

Scopes — any one of

custom-attributes:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
attribute * path Attribute id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/division-groups List division groups

Authentication

Bearer token

Scopes — any one of

divisions:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/division-groups Create a division group

Authentication

Bearer token

Scopes — any one of

divisions:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PUT /api/v1/tournaments/{tournament}/division-groups/settings Update the division groups setting

Authentication

Bearer token

Scopes — any one of

divisions:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PATCH /api/v1/tournaments/{tournament}/division-groups/{group} Update the division group

Authentication

Bearer token

Scopes — any one of

divisions:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
group * path Group id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/division-groups/{group} Delete the division group

Authentication

Bearer token

Scopes — any one of

divisions:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
group * path Group id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/divisions List divisions

Authentication

Bearer token

Scopes — any one of

divisions:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/divisions Create a division

Authentication

Bearer token

Scopes — any one of

divisions:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/divisions/{division} Get the division

Authentication

Bearer token

Scopes — any one of

divisions:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
division * path Division id.
PATCH /api/v1/tournaments/{tournament}/divisions/{division} Update the division

Authentication

Bearer token

Scopes — any one of

divisions:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
division * path Division id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/divisions/{division} Delete the division

Authentication

Bearer token

Scopes — any one of

divisions:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
division * path Division id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
POST /api/v1/tournaments/{tournament}/divisions/{division}/logo Upload the division logo

Authentication

Bearer token

Scopes — any one of

divisions:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
division * path Division id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

multipart/form-data with a single file part — png, jpg or webp, up to 2 MB. Resized to a 1200 px longest edge on upload.

DELETE /api/v1/tournaments/{tournament}/divisions/{division}/logo Remove the division logo

Authentication

Bearer token

Scopes — any one of

divisions:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
division * path Division id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/divisions/{division}/structure One division's structure

The form-data shape PUT /divisions/{division}/structure expects, for this division only.

Authentication

Bearer token

Scopes — any one of

structure:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
division * path Division id.
PUT /api/v1/tournaments/{tournament}/divisions/{division}/structure Replace one division's structure

The way to build a tournament that has divisions. Phases are stamped with the division and only that division's phases missing from the payload are removed, so its siblings are untouched. PUT /structure is tournament-wide: it assigns no division and clears every phase the payload leaves out.

Does NOT regenerate matches. Call POST /matches/generate explicitly.

Authentication

Bearer token

Scopes — any one of

structure:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
division * path Division id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
phases array Stages in order, each `{type: group_stage|knockout, data: {...}}`. Read the shape from GET /divisions/{division}/structure.
GET /api/v1/tournaments/{tournament}/documents List documents

Authentication

Bearer token

Scopes — any one of

website:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/documents Publish a document link

Links only. Uploaded files remain a panel action: they live on a private disk and are served through a controller that re-checks the plan and the page setting on every request.

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PATCH /api/v1/tournaments/{tournament}/documents/{document} Update the document

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
document * path Document id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/documents/{document} Delete the document

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
document * path Document id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/fees Every charge template this tournament uses

pricing_mode decides what the amount is PER, and changes what the fee means entirely. flat bills its amount once; per_person bills it per head and is NOT directly applicable — it belongs on a booking form, where the pax figure is stated. directly_applicable is the same answer as a boolean, for clients that would rather branch on it than on the enum.

Authentication

Bearer token

Scopes — any one of

finances:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/fees Create a fee

A fee carries its deadline as an OFFSET (due_days, counted from the day each participant is billed) or a FIXED DATE (due_on), never both — sending one clears the other. Sending neither means this fee has no deadline, and a charge with no deadline is never chased automatically.

Authentication

Bearer token

Scopes — any one of

finances:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/fees/{fee} Get the fee

Authentication

Bearer token

Scopes — any one of

finances:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
fee * path Fee id.
PATCH /api/v1/tournaments/{tournament}/fees/{fee} Update the fee

Authentication

Bearer token

Scopes — any one of

finances:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
fee * path Fee id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/fees/{fee} Delete the fee

Authentication

Bearer token

Scopes — any one of

finances:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
fee * path Fee id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
POST /api/v1/tournaments/{tournament}/fees/{fee}/apply Raise this fee as a charge against participants

Goes through FeeApplier, which locks the fee row, refuses to bill a participant it has already billed for this fee, and resolves the deadline through the one method that knows the offset-vs-fixed-date distinction.

Returns how many charges were created and how many participants were skipped because they already carried one.

Authentication

Bearer token

Scopes — any one of

finances:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
fee * path Fee id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
target string
division_id string Required when target is `division`.
team_ids array Required when target is `selection`.
occurred_on string Billing date. Defaults to today in the tournament's own timezone.
GET /api/v1/tournaments/{tournament}/finance-balances What each participant owes

Computed by FinanceLedger, the only place this arithmetic lives. All amounts are MINOR UNITS (integer cents) as stored — no float ever touches a balance.

Reading a balance is NOT plan-gated, unlike every finance write: an organiser whose plan lapsed must still be able to see what they are owed.

Authentication

Bearer token

Scopes — any one of

finances:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/tournaments/{tournament}/finance-entries List finance entries

Authentication

Bearer token

Scopes — any one of

finances:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/finance-entries Record a charge, payment or refund

Entries created here are CONFIRMED: a credential acting for the organiser is recording a decision already made. The pending state exists for a club's self-reported payment, which arrives through the participant panel and cannot be created from this surface.

Authentication

Bearer token

Scopes — any one of

finances:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/finance-entries/{entry} Get the finance entry

Authentication

Bearer token

Scopes — any one of

finances:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
entry * path Entry id.
PATCH /api/v1/tournaments/{tournament}/finance-entries/{entry} Update the finance entry

Authentication

Bearer token

Scopes — any one of

finances:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
entry * path Entry id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/finance-entries/{entry} Delete the finance entry

Authentication

Bearer token

Scopes — any one of

finances:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
entry * path Entry id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
POST /api/v1/tournaments/{tournament}/finish Create a finish

Authentication

Bearer token

Scopes — any one of

tournaments:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/grounds/{ground}/availability List grounds availability

Authentication

Bearer token

Scopes — any one of

venues:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
ground * path Ground id.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/grounds/{ground}/availability Declare when a venue is free

Writing a window schedules NOTHING. MatchScheduler is the only thing that writes a kickoff time, so opening hours can be declared without any fixture moving until auto-fill is asked for.

slot_minutes is required and is the single source of truth for how long a match occupies this venue. Sport config (periods x duration) drives the match-editor clock and deliberately does not feed scheduling.

Authentication

Bearer token

Scopes — any one of

venues:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
ground * path Ground id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PATCH /api/v1/tournaments/{tournament}/grounds/{ground}/availability/{availability} Update the grounds availability

Authentication

Bearer token

Scopes — any one of

venues:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
ground * path Ground id.
availability * path Availability id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/grounds/{ground}/availability/{availability} Delete the grounds availability

Authentication

Bearer token

Scopes — any one of

venues:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
ground * path Ground id.
availability * path Availability id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
POST /api/v1/tournaments/{tournament}/groups/{group}/tie-decisions Record how level teams were separated

For a FINISHED group whose teams are level on points and every tiebreaker (listed in the group's unsettled_ties on GET /standings): record the penalty shootout, drawing of lots or organiser decision that separated them, best placed first. The standings, the next round's slots and the public site follow it at once.

Refusals: 422 when an id is not a team of this group; 409 teams_not_level when the teams are not a current tie (the group is still being played, or a corrected score changed who is level), with the group's current ties in details.ties (each with team_ids, from, to and the decision_id already recorded for it, or null); 409 next_round_played when the new order would change who holds a next-round place that has already been played. Sending the same teams in another order changes the decision. Returns 201 for a new decision, 200 when one was changed.

Authentication

Bearer token

Scopes — any one of

results:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
group * path Group id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
method string
ordered_team_ids array Every tied team, best placed first.
score string Shootout score, e.g. "3:2". Ignored for other methods.
note string
DELETE /api/v1/tournaments/{tournament}/groups/{group}/tie-decisions/{decision} Remove a tie decision

The tie reopens. A next-round place already filled with one of the tied teams keeps that team until a new decision is recorded, so no played match loses its team.

Authentication

Bearer token

Scopes — any one of

results:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
group * path Group id.
decision * path Decision id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/hospitality-groups Who is travelling, as the units that need beds

⚠️ A GROUP IS NOT A TEAM. A club of 18 can arrive as three groups — the squad in a hostel, the coaches in a hotel, twenty parents in family rooms — and referees are a group belonging to no club at all. team_id is therefore nullable by design; it is what links a group's costs to a participant's balance.

Called a group here because that is the word the panel, the emails and the documentation use. The model is named Party only to avoid colliding with a group STAGE.

Authentication

Bearer token

Scopes — any one of

hospitality:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team query Only groups linked to this participant.
type query One of team, team_guests, officials, individual.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/tournaments/{tournament}/hospitality-groups/{group} Get the hospitality group

Authentication

Bearer token

Scopes — any one of

hospitality:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
group * path Group id.
GET /api/v1/tournaments/{tournament}/lead-sources List lead sources

Shared across the seasons of a series. Archived ones are included and flagged.

Authentication

Bearer token

Scopes — any one of

candidates:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/tournaments/{tournament}/library/clubs List the club library

The LIBRARY is one entry per club, player and staff member across every season of this tournament. Each season's row points at its entry through library_id (on teams, players and staff in partner responses only — never on the public surface, because it links one child's records across seasons).

The library fills itself: a next season copies its rows already linked, and a row added later links to its entry when exactly one entry matches, becomes a new entry when none does, and is left unlinked only when the match is ambiguous.

seasons lists the tournaments (id) each entry appears in, oldest first.

A credential attached to SOME seasons sees the library through them only: an entry is listed when it has a row in a season the credential reaches, and seasons names only those. Linking to an entry it could not list is refused like another tournament's entry (422).

Authentication

Bearer token

Scopes — any one of

teams:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
search query Only entries whose name contains every word.
per_page query Page size, at most 100.
GET /api/v1/tournaments/{tournament}/library/players List the player library

See the club library. People carry birth_year (the year only, enough to tell namesakes apart). Anonymised people are left out.

Authentication

Bearer token

Scopes — any one of

players:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
search query Only entries whose name contains every word.
per_page query Page size, at most 100.
GET /api/v1/tournaments/{tournament}/library/players/duplicates Likely duplicate players in the library

Groups of two or more entries with the same name whose birth dates do not disagree, minus pairs marked as different people. A suggestion, never an automatic merge: two children of one name at one club are real.

Authentication

Bearer token

Scopes — any one of

players:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
POST /api/v1/tournaments/{tournament}/library/players/{entry}/distinct Mark two players as different people

The pair is never suggested as a duplicate again. Returns 403 tournament_not_in_scope when either person also has a row in a season this credential does not reach.

Authentication

Bearer token

Scopes — any one of

players:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
entry * path Entry id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
from string The other library entry.
POST /api/v1/tournaments/{tournament}/library/players/{entry}/merge Merge a duplicate player into another

Every season row of the duplicate (the path entry) now points at into, blanks on into are filled from the duplicate, and the duplicate is deleted. Only the library changes: numbers, goals, lineups and documents stay exactly as each season recorded them. Returns 403 tournament_not_in_scope when either person also has a row in a season this credential does not reach.

Authentication

Bearer token

Scopes — any one of

players:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
entry * path Entry id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
into string The library entry to keep.
GET /api/v1/tournaments/{tournament}/library/staff List the staff library

See the club library. Anonymised people are left out.

Authentication

Bearer token

Scopes — any one of

staff:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
search query Only entries whose name contains every word.
per_page query Page size, at most 100.
POST /api/v1/tournaments/{tournament}/logo Upload the tournament logo

Authentication

Bearer token

Scopes — any one of

tournaments:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

multipart/form-data with a single file part — png, jpg or webp, up to 2 MB. Resized to a 1200 px longest edge on upload.

DELETE /api/v1/tournaments/{tournament}/logo Remove the tournament logo

Authentication

Bearer token

Scopes — any one of

tournaments:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/lost-reasons List lost reasons

Shared across the seasons of a series. Archived ones are included and flagged.

Authentication

Bearer token

Scopes — any one of

candidates:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/tournaments/{tournament}/matches List fixtures

Authentication

Bearer token

Scopes — any one of

matches:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
date query A calendar day in the tournament's own timezone.
team query Matches involving this team, home or away.
phase query Limit to one phase.
matchday query Limit to one matchday.
venue query Limit to one venue.
status query not_started, in_progress or finished.
unscheduled query true returns only matches with no kickoff time.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/matches/generate Generate the fixture list

DESTRUCTIVE. Existing matches are soft-deleted and rebuilt from the current team slots, taking their events, lineups and referee assignments with them. If anything would be lost the call is refused with 409 destructive_confirmation_required listing what would go; repeat with confirm_destructive: true.

There is no endpoint for creating a single match: matches exist because a structure was generated, and a hand-made fixture would belong to no group and count towards no table.

Authentication

Bearer token

Scopes — any one of

matches:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
phase_id string Limit to one phase. Omit for the whole tournament.
shuffle_teams boolean
confirm_destructive boolean
GET /api/v1/tournaments/{tournament}/matches/{match} Get the match

Authentication

Bearer token

Scopes — any one of

matches:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
match * path Match id.
PATCH /api/v1/tournaments/{tournament}/matches/{match} Move or restate a fixture

Kickoff time, venue, status and description. Set is_schedule_locked to pin a match so auto-fill, regeneration and "clear schedule" leave it alone.

Authentication

Bearer token

Scopes — any one of

matches:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
match * path Match id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/matches/{match} Delete the match

Authentication

Bearer token

Scopes — any one of

matches:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
match * path Match id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/matches/{match}/events List a match's events

Authentication

Bearer token

Scopes — any one of

results:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
match * path Match id.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/matches/{match}/events Record a match event

A goal, card or substitution as its own row, so a live-scoring integration can post one the moment it happens instead of resubmitting the whole match. event_code is validated against this SPORT's event list — a handball tournament genuinely has no yellow-red card.

Authentication

Bearer token

Scopes — any one of

results:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
match * path Match id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PATCH /api/v1/tournaments/{tournament}/matches/{match}/events/{event} Update the event

Authentication

Bearer token

Scopes — any one of

results:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
match * path Match id.
event * path Event id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/matches/{match}/events/{event} Delete the event

Authentication

Bearer token

Scopes — any one of

results:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
match * path Match id.
event * path Event id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PUT /api/v1/tournaments/{tournament}/matches/{match}/result Record a match result

Scores, extra time, penalties and technical results. A set-scored sport must send sets and is refused if it sends home_score — the match score there is SETS WON, derived from the per-set rows.

Separate from PATCH /matches/{match}, which moves a fixture: a score is governed by the results capability, a kickoff time by the schedule one, and a finished tournament still allows both.

Authentication

Bearer token

Scopes — any one of

results:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
match * path Match id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
status integer 1 not started, 2 finished, 3 in progress.
home_score integer
away_score integer
additional_time_played boolean
penalties_played boolean
sets array
GET /api/v1/tournaments/{tournament}/meal-services Sittings, and how many of each group is eating

⚠️ headcount is TYPED by the organiser, never derived from a roster. Clubs arrive late and miss a dinner, families booked half board and eat in town, and Sunday's squad is nine players because the rest went home after the semi-final. A client that recomputes these from group sizes will disagree with the number the caterer was given — which is the number that gets cooked and paid for.

total_headcount is the figure a caterer asks for.

Authentication

Bearer token

Scopes — any one of

hospitality:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
date query A single calendar day, YYYY-MM-DD.
type query breakfast, lunch, dinner, snack or other.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/tournaments/{tournament}/meal-services/{meal} Get the meal service

Authentication

Bearer token

Scopes — any one of

hospitality:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
meal * path Meal id.
PUT /api/v1/tournaments/{tournament}/phases/{phase}/first-day Set a stage's first day

The earliest day auto-fill may place this stage on, for tournaments played over separate match days (qualifiers one Sunday, the main event the next). The day carries forward: every later stage of the same division starts no earlier, and the stages before it are spread over the days before it. date must be a day that has venue time slots; send null to clear it. Returns the stored schedule_not_before and the effective_first_day, which can be later when an earlier stage carries a later day.

Refusals: 404 when the stage is not this tournament's; 422 when date is not a day with time slots.

Authentication

Bearer token

Scopes — any one of

schedule:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
phase * path Phase id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
date string YYYY-MM-DD, a day with time slots; null clears it.
GET /api/v1/tournaments/{tournament}/plan The tournament's plan, its caps and what remains

Read this to refuse locally instead of discovering a cap through a 402 halfway through an import.

Authentication

Bearer token

Scopes — any one of

plan:read tournaments:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/tournaments/{tournament}/referees List referees

Authentication

Bearer token

Scopes — any one of

referees:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/referees Create a referee

Authentication

Bearer token

Scopes — any one of

referees:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/referees/{referee} Get the referee

Authentication

Bearer token

Scopes — any one of

referees:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
referee * path Referee id.
PATCH /api/v1/tournaments/{tournament}/referees/{referee} Update the referee

Authentication

Bearer token

Scopes — any one of

referees:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
referee * path Referee id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/referees/{referee} Delete the referee

Authentication

Bearer token

Scopes — any one of

referees:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
referee * path Referee id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
POST /api/v1/tournaments/{tournament}/referees/{referee}/photo Upload the referee photo

Authentication

Bearer token

Scopes — any one of

referees:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
referee * path Referee id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

multipart/form-data with a single file part — png, jpg or webp, up to 2 MB. Resized to a 1200 px longest edge on upload.

DELETE /api/v1/tournaments/{tournament}/referees/{referee}/photo Remove the referee photo

Authentication

Bearer token

Scopes — any one of

referees:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
referee * path Referee id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
POST /api/v1/tournaments/{tournament}/reopen Create a reopen

Authentication

Bearer token

Scopes — any one of

tournaments:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/sales/pacing Sales pacing

Cumulative confirmed teams and revenue by days before kick-off, this season and up to three earlier seasons of the series. Seasons are identified by tournament uuid. An earlier season keeps its revenue only when this credential reaches that tournament and it has the Finances plan; otherwise its revenue_minor points are 0 and revenue_hidden is true (the teams line stays). Needs the Finances plan.

Authentication

Bearer token

Scopes — any one of

finances:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/tournaments/{tournament}/sales/summary Sales summary

Leads, conversion (converted out of decided) and, in minor units, pipeline, confirmed, collected and lost — the figures on the Candidates page. Takes the same filters as GET /candidates, so the totals describe exactly that list (e.g. one division, one country, one source). Needs the Finances plan.

Authentication

Bearer token

Scopes — any one of

finances:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
status query pending, under_review, info_requested, approved, converted, rejected or withdrawn.
search query Part of the name or email.
division query A division id, or `none`.
country query ISO-2 code (e.g. PT), or `none`.
source query A lead source id or name (GET /lead-sources), or `none`. 422 when unknown.
owner query An owner's user id, or `none`.
follow_up query `overdue`, `today`, `week` (today + 6 days), `due` (today or earlier) or `none`, in the tournament's time zone.
created_from query YYYY-MM-DD, inclusive.
created_to query YYYY-MM-DD, inclusive.
has_managers query `true`: only registrations with a team manager; `false`: only those without.
POST /api/v1/tournaments/{tournament}/schedule/apply Apply a proposed schedule

Recomputes the proposal server-side and accepts only your fingerprint as proof that nothing moved in between. A stale fingerprint is refused rather than allowed to double-book a pitch.

Authentication

Bearer token

Scopes — any one of

schedule:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
fingerprint string
GET /api/v1/tournaments/{tournament}/schedule/conflicts List scheduling clashes

Two matches on one venue at one time, or a team in two places at once. matches_in_conflict counts MATCHES, not conflicts, which is the question an organiser is actually asking.

Authentication

Bearer token

Scopes — any one of

schedule:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
POST /api/v1/tournaments/{tournament}/schedule/propose Propose a venue-aware schedule

WRITES NOTHING. Returns the placements plus every match it could not seat WITH A REASON — division_venue, division, stage_day, round_order, rest, max_per_day, team_busy, no_slot — each of which points at a different remedy. stage_day means no free slot from the day the stage is set to start (PUT /phases/{phase}/first-day). Pass the returned fingerprint to /schedule/apply; changing a stage's first day makes it stale.

Authentication

Bearer token

Scopes — any one of

schedule:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/scorers Top scorers

Authentication

Bearer token

Scopes — any one of

results:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/tournaments/{tournament}/seasons List the seasons of this tournament

Every season, oldest first, including this one. is_current marks the season the tournament is on; reachable says whether THIS credential is attached to that season, since a credential reaches only the seasons it was given. A partner credential is given a season automatically when that season is started from one it already reaches. A tournament with no other seasons returns itself alone.

Authentication

Bearer token

Scopes — any one of

tournaments:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/tournaments/{tournament}/sponsors List sponsors

Authentication

Bearer token

Scopes — any one of

website:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/sponsors Create a sponsor

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PATCH /api/v1/tournaments/{tournament}/sponsors/{sponsor} Update the sponsor

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
sponsor * path Sponsor id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/sponsors/{sponsor} Delete the sponsor

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
sponsor * path Sponsor id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
POST /api/v1/tournaments/{tournament}/sponsors/{sponsor}/logo Upload the sponsor logo

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
sponsor * path Sponsor id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

multipart/form-data with a single file part — png, jpg or webp, up to 2 MB. Resized to a 1200 px longest edge on upload.

DELETE /api/v1/tournaments/{tournament}/sponsors/{sponsor}/logo Remove the sponsor logo

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
sponsor * path Sponsor id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/standings Standings for every phase

Authentication

Bearer token

Scopes — any one of

results:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/tournaments/{tournament}/statistics List statistics

Authentication

Bearer token

Scopes — any one of

statistics:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/tournaments/{tournament}/structure The tournament structure

Authentication

Bearer token

Scopes — any one of

structure:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
PUT /api/v1/tournaments/{tournament}/structure Replace the tournament structure

Does NOT regenerate matches. Call POST /matches/generate explicitly, so adjusting one group cannot silently destroy a weekend of results.

Authentication

Bearer token

Scopes — any one of

structure:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
POST /api/v1/tournaments/{tournament}/structure/preview Preview a structure without saving it

Turns "8 teams, 2 groups, knockout from the quarters" into the same form-data shape PUT /structure expects, so an organiser can see what they are about to commit to before anything is written.

Authentication

Bearer token

Scopes — any one of

structure:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
type integer 1 league, 2 knockout, 3 groups and knockout.
number_of_teams integer
number_of_groups integer
number_of_teams_per_group integer
number_of_knockout_teams integer
GET /api/v1/tournaments/{tournament}/team-forms List team forms

Authentication

Bearer token

Scopes — any one of

forms:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/team-forms Create a team form

Authentication

Bearer token

Scopes — any one of

forms:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/team-forms/{form} Get the team form

Authentication

Bearer token

Scopes — any one of

forms:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
form * path Form id.
PATCH /api/v1/tournaments/{tournament}/team-forms/{form} Update a form

fields replaces the whole set when present. Omitting it leaves the fields alone, so renaming a form does not require resending every field; sending an empty array really does clear them.

Because it REPLACES rather than merges, two clients doing read-modify-write silently overwrite each other. Send expected_version (the version from your last read) to be refused with 409 form_modified instead of losing the other edit. It is a content hash, not a timestamp: updated_at is second-precision and cannot detect a same-second change.

Authentication

Bearer token

Scopes — any one of

forms:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
form * path Form id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/team-forms/{form} Delete the team form

Authentication

Bearer token

Scopes — any one of

forms:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
form * path Form id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/team-forms/{form}/responses Every participant's answers to this form

Read-only. A response is the participant's own statement, made in their panel; an organiser credential that could write one would answer on the club's behalf and leave no trace that it had.

Answers are keyed by FIELD ID, never by label — a label is editable text, and keying on it would re-point every historical answer the first time somebody fixes a typo.

Authentication

Bearer token

Scopes — any one of

forms:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
form * path Form id.
GET /api/v1/tournaments/{tournament}/teams List teams

Authentication

Bearer token

Scopes — any one of

teams:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/teams Create a team

Authentication

Bearer token

Scopes — any one of

teams:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/teams/{team} Get the team

Authentication

Bearer token

Scopes — any one of

teams:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
PATCH /api/v1/tournaments/{tournament}/teams/{team} Update the team

Authentication

Bearer token

Scopes — any one of

teams:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/teams/{team} Delete the team

Authentication

Bearer token

Scopes — any one of

teams:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PUT /api/v1/tournaments/{tournament}/teams/{team}/library Link a team to its club library entry

Sets which library entry this season's team is. library_id is an entry of this tournament's library, "new" for a new entry, or null to unlink. An entry nothing points at any more is removed. Returns 409 not_a_season when the tournament has no library.

Authentication

Bearer token

Scopes — any one of

teams:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
library_id string A club library id, "new", or null to unlink.
POST /api/v1/tournaments/{tournament}/teams/{team}/logo Upload the team logo

Authentication

Bearer token

Scopes — any one of

teams:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

multipart/form-data with a single file part — png, jpg or webp, up to 2 MB. Resized to a 1200 px longest edge on upload.

DELETE /api/v1/tournaments/{tournament}/teams/{team}/logo Remove the team logo

Authentication

Bearer token

Scopes — any one of

teams:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
POST /api/v1/tournaments/{tournament}/teams/{team}/photo Upload the team photo

Authentication

Bearer token

Scopes — any one of

teams:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

multipart/form-data with a single file part — png, jpg or webp, up to 2 MB. Resized to a 1200 px longest edge on upload.

DELETE /api/v1/tournaments/{tournament}/teams/{team}/photo Remove the team photo

Authentication

Bearer token

Scopes — any one of

teams:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/teams/{team}/players List a team's players

Authentication

Bearer token

Scopes — any one of

players:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/teams/{team}/players Create a player

Authentication

Bearer token

Scopes — any one of

players:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PATCH /api/v1/tournaments/{tournament}/teams/{team}/players/{player} Update the player

Authentication

Bearer token

Scopes — any one of

players:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
player * path Player id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/teams/{team}/players/{player} Delete the player

Authentication

Bearer token

Scopes — any one of

players:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
player * path Player id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PUT /api/v1/tournaments/{tournament}/teams/{team}/players/{player}/library Link a player to their library entry

As for teams: an entry id, "new", or null to unlink.

Authentication

Bearer token

Scopes — any one of

players:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
player * path Player id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
library_id string A player library id, "new", or null to unlink.
POST /api/v1/tournaments/{tournament}/teams/{team}/players/{player}/photo Upload the player photo

Authentication

Bearer token

Scopes — any one of

players:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
player * path Player id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

multipart/form-data with a single file part — png, jpg or webp, up to 2 MB. Resized to a 1200 px longest edge on upload.

DELETE /api/v1/tournaments/{tournament}/teams/{team}/players/{player}/photo Remove the player photo

Authentication

Bearer token

Scopes — any one of

players:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
player * path Player id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/teams/{team}/staff List a team's staff

Authentication

Bearer token

Scopes — any one of

staff:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/teams/{team}/staff Create a staff member

Authentication

Bearer token

Scopes — any one of

staff:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PATCH /api/v1/tournaments/{tournament}/teams/{team}/staff/{staff} Update the staff member

Authentication

Bearer token

Scopes — any one of

staff:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
staff * path Staff id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/teams/{team}/staff/{staff} Delete the staff member

Authentication

Bearer token

Scopes — any one of

staff:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
staff * path Staff id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PUT /api/v1/tournaments/{tournament}/teams/{team}/staff/{staff}/library Link a staff member to their library entry

As for teams: an entry id, "new", or null to unlink.

Authentication

Bearer token

Scopes — any one of

staff:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
staff * path Staff id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
library_id string A staff library id, "new", or null to unlink.
POST /api/v1/tournaments/{tournament}/teams/{team}/staff/{staff}/photo Upload the staff member photo

Authentication

Bearer token

Scopes — any one of

staff:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
staff * path Staff id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

multipart/form-data with a single file part — png, jpg or webp, up to 2 MB. Resized to a 1200 px longest edge on upload.

DELETE /api/v1/tournaments/{tournament}/teams/{team}/staff/{staff}/photo Remove the staff member photo

Authentication

Bearer token

Scopes — any one of

staff:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
team * path Team id.
staff * path Staff id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/venues List venues

Authentication

Bearer token

Scopes — any one of

venues:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/venues Create a venue

Authentication

Bearer token

Scopes — any one of

venues:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/venues/{venue} Get the venue

Authentication

Bearer token

Scopes — any one of

venues:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
venue * path Venue id.
PATCH /api/v1/tournaments/{tournament}/venues/{venue} Update the venue

Authentication

Bearer token

Scopes — any one of

venues:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
venue * path Venue id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/venues/{venue} Delete the venue

Authentication

Bearer token

Scopes — any one of

venues:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
venue * path Venue id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
POST /api/v1/tournaments/{tournament}/venues/{venue}/logo Upload the venue logo

Authentication

Bearer token

Scopes — any one of

venues:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
venue * path Venue id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

multipart/form-data with a single file part — png, jpg or webp, up to 2 MB. Resized to a 1200 px longest edge on upload.

DELETE /api/v1/tournaments/{tournament}/venues/{venue}/logo Remove the venue logo

Authentication

Bearer token

Scopes — any one of

venues:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
venue * path Venue id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/website How the website looks

The live theme, hero image and banners, plus what can be chosen: each archetype with the presets that belong to it, and the lifecycle states a home layout exists for.

Authentication

Bearer token

Scopes — any one of

website:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
GET /api/v1/tournaments/{tournament}/website/banners List the home banners

Authentication

Bearer token

Scopes — any one of

website:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/tournaments/{tournament}/website/banners Add a home banner

multipart/form-data with a file part (png, jpg or webp, up to 5 MB) and an optional url the banner links to. Appended after the existing banners; at most 6, then 409 banner_limit_reached. The banners block must also be enabled in the layout to show. Needs a plan with images.

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/website/banners/{position} Remove a home banner

position is the 1-based position GET /website/banners reports. Later banners move up one.

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
position * path Position id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/website/blocks List the blocks that have settings

Each block with its fields, their current values and what they accept. Field keys are the ones PATCH /website/blocks/{block} takes. Blocks that only show live tournament data have no settings and are not listed.

Authentication

Bearer token

Scopes — any one of

website:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
PATCH /api/v1/tournaments/{tournament}/website/blocks/{block} Change a block's content

Send any of the block's fields by key; fields left out are untouched. Live at once and shared by every lifecycle state. A field marked writable: false is a file: use POST /website/hero-image or POST /website/banners. Rich text is sanitised.

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
block * path Block id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
{field key} string One entry per field, typed as GET /website/blocks describes it.
POST /api/v1/tournaments/{tournament}/website/hero-image Upload the hero background image

multipart/form-data with one file part: png, jpg or webp, up to 5 MB, capped at 1920px on its long edge. Replaces the previous image. Needs a plan with images.

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/tournaments/{tournament}/website/hero-image Remove the hero background image

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/website/layout The home page layout

The blocks of the home page in order, each on or off. A layout exists per lifecycle state; pass ?state= for one other than the state the tournament is in now.

Authentication

Bearer token

Scopes — any one of

website:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
PUT /api/v1/tournaments/{tournament}/website/layout Arrange the home page

Live at once, for one lifecycle state (state, default: the current one). Only order and on/off are taken. Blocks named move to the front in the order given; the rest keep their order behind them. The hero stays first, and cards and sections each stay in one run.

Clears that state's unpublished layout draft in the editor, so the draft cannot put the old layout back.

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
state string
blocks array Each `{type, enabled?}`.
GET /api/v1/tournaments/{tournament}/website/pages Get the website page

Authentication

Bearer token

Scopes — any one of

website:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
PATCH /api/v1/tournaments/{tournament}/website/pages Update the website page

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/tournaments/{tournament}/website/summary Get the website summary

Authentication

Bearer token

Scopes — any one of

website:read platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
PUT /api/v1/tournaments/{tournament}/website/summary Update the website summary

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PATCH /api/v1/tournaments/{tournament}/website/theme Change the theme

Live at once. A preset belongs to an archetype, so switching archetype lands on that archetype's default preset unless a preset valid for it is sent too. The custom preset needs all three colours as #rrggbb and is refused when body text or the accent would be unreadable on the background.

For a season in a series the look is shared by every season: the credential must reach all of them, otherwise 403 with reason: series_brand_shared.

Authentication

Bearer token

Scopes — any one of

website:write platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
archetype string classic or broadcast. See GET /website.
preset string
background_color string With preset `custom`.
primary_color string With preset `custom`.
secondary_color string With preset `custom`.

Platform

Estate-wide access. MyCup staff credentials only.

GET /api/v1/admin/announcements List announcements

Authentication

Bearer token

Scopes — any one of

platform:content:read

Parameters

NameInDescription
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/admin/announcements Create an announcement

Authentication

Bearer token

Scopes — any one of

platform:content:write

Parameters

NameInDescription
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
PATCH /api/v1/admin/announcements/{announcement} Update the announcement

Authentication

Bearer token

Scopes — any one of

platform:content:write

Parameters

NameInDescription
announcement * path Announcement id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/admin/announcements/{announcement} Delete the announcement

Authentication

Bearer token

Scopes — any one of

platform:content:write

Parameters

NameInDescription
announcement * path Announcement id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/api-clients List api clients

Authentication

Bearer token

Scopes — any one of

platform:api-clients:read

Parameters

NameInDescription
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/admin/api-clients Create an api client

Authentication

Bearer token

Scopes — any one of

platform:api-clients:write

Parameters

NameInDescription
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/api-clients/{client} Get the api client

Authentication

Bearer token

Scopes — any one of

platform:api-clients:read

Parameters

NameInDescription
client * path Client id.
PATCH /api/v1/admin/api-clients/{client} Update the api client

Authentication

Bearer token

Scopes — any one of

platform:api-clients:write

Parameters

NameInDescription
client * path Client id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/admin/api-clients/{client} Delete the api client

Authentication

Bearer token

Scopes — any one of

platform:api-clients:write

Parameters

NameInDescription
client * path Client id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
POST /api/v1/admin/api-clients/{client}/revoke Revoke the credential

Authentication

Bearer token

Scopes — any one of

platform:api-clients:write

Parameters

NameInDescription
client * path Client id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
POST /api/v1/admin/api-clients/{client}/rotate Rotate the credential secret

Authentication

Bearer token

Scopes — any one of

platform:api-clients:write

Parameters

NameInDescription
client * path Client id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/blog-posts List blog posts

Authentication

Bearer token

Scopes — any one of

platform:content:read

Parameters

NameInDescription
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/admin/blog-posts Create a blog post

Authentication

Bearer token

Scopes — any one of

platform:content:write

Parameters

NameInDescription
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/blog-posts/{post} Get the blog post

Authentication

Bearer token

Scopes — any one of

platform:content:read

Parameters

NameInDescription
post * path Post id.
PATCH /api/v1/admin/blog-posts/{post} Update the blog post

Authentication

Bearer token

Scopes — any one of

platform:content:write

Parameters

NameInDescription
post * path Post id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/admin/blog-posts/{post} Delete the blog post

Authentication

Bearer token

Scopes — any one of

platform:content:write

Parameters

NameInDescription
post * path Post id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/discount-codes List discount codes

Authentication

Bearer token

Scopes — any one of

platform:billing:read

Parameters

NameInDescription
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/admin/discount-codes Create a discount code

Authentication

Bearer token

Scopes — any one of

platform:billing:write

Parameters

NameInDescription
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/admin/discount-codes/{code} Delete the discount code

Authentication

Bearer token

Scopes — any one of

platform:billing:write

Parameters

NameInDescription
code * path Code id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/discounts List discounts

Authentication

Bearer token

Scopes — any one of

platform:billing:read

Parameters

NameInDescription
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/admin/discounts Create a discount

Authentication

Bearer token

Scopes — any one of

platform:billing:write

Parameters

NameInDescription
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/discounts/{discount} Get the discount

Authentication

Bearer token

Scopes — any one of

platform:billing:read

Parameters

NameInDescription
discount * path Discount id.
PATCH /api/v1/admin/discounts/{discount} Update the discount

Authentication

Bearer token

Scopes — any one of

platform:billing:write

Parameters

NameInDescription
discount * path Discount id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/admin/discounts/{discount} Delete the discount

Authentication

Bearer token

Scopes — any one of

platform:billing:write

Parameters

NameInDescription
discount * path Discount id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/invoices List invoices

Authentication

Bearer token

Scopes — any one of

platform:billing:read

Parameters

NameInDescription
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/admin/metrics Estate-wide numbers

Tournaments, users, one-time orders and revenue. Revenue is what was actually CHARGED (after discounts), not list price.

Subscription metrics (MRR, churn, active subscriptions) are inherited from SaaSykit and describe recurring revenue MyCup does not have. They are returned only with include_subscription_metrics=1, and labelled as not applicable.

Authentication

Bearer token

Scopes — any one of

platform:metrics

Parameters

NameInDescription
since query Only count records created on or after this date.
include_subscription_metrics query Include the inherited, not-applicable subscription block.
GET /api/v1/admin/one-time-products List one time products

Authentication

Bearer token

Scopes — any one of

platform:billing:read

Parameters

NameInDescription
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/admin/one-time-products Create an one time product

Authentication

Bearer token

Scopes — any one of

platform:billing:write

Parameters

NameInDescription
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/one-time-products/{product} Get the one time product

Authentication

Bearer token

Scopes — any one of

platform:billing:read

Parameters

NameInDescription
product * path Product id.
PATCH /api/v1/admin/one-time-products/{product} Update the one time product

Authentication

Bearer token

Scopes — any one of

platform:billing:write

Parameters

NameInDescription
product * path Product id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/admin/one-time-products/{product} Withdraw a plan from sale

⚠️ Returns 200 with the updated product, not 204. This is the only DELETE on the API that does — everywhere else DELETE means 204 and gone.

It deactivates rather than deletes: every order that ever bought this plan still points at it, and PlanManager reads the product behind a purchase to decide what that tournament is entitled to today, so destroying one would strip features from tournaments that paid for them. The body is returned so a caller can see is_active and is_visible are now false.

Authentication

Bearer token

Scopes — any one of

platform:billing:write

Parameters

NameInDescription
product * path Product id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/orders List orders

Authentication

Bearer token

Scopes — any one of

platform:billing:read

Parameters

NameInDescription
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/admin/roadmap-items List roadmap items

Authentication

Bearer token

Scopes — any one of

platform:content:read

Parameters

NameInDescription
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/admin/roadmap-items Create a roadmap item

Authentication

Bearer token

Scopes — any one of

platform:content:write

Parameters

NameInDescription
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/roadmap-items/{item} Get the roadmap item

Authentication

Bearer token

Scopes — any one of

platform:content:read

Parameters

NameInDescription
item * path Item id.
PATCH /api/v1/admin/roadmap-items/{item} Update the roadmap item

Authentication

Bearer token

Scopes — any one of

platform:content:write

Parameters

NameInDescription
item * path Item id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/admin/roadmap-items/{item} Delete the roadmap item

Authentication

Bearer token

Scopes — any one of

platform:content:write

Parameters

NameInDescription
item * path Item id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/roles List roles

Authentication

Bearer token

Scopes — any one of

platform:users:read

Parameters

NameInDescription
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/admin/roles Create a role

Gated on platform:users:write, not a scope of its own: a credential that can edit roles can grant itself, in effect, anything a user can do.

Permissions are ATTACHED, never created — the permission list is defined by the code that checks it, and inventing a new string here would produce a role granting something nothing will ever ask about. A tenant_id makes this a tournament role rather than a platform one.

Authentication

Bearer token

Scopes — any one of

platform:users:write

Parameters

NameInDescription
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/roles/{role} Get the role

Authentication

Bearer token

Scopes — any one of

platform:users:read

Parameters

NameInDescription
role * path Role id.
PATCH /api/v1/admin/roles/{role} Update the role

Authentication

Bearer token

Scopes — any one of

platform:users:write

Parameters

NameInDescription
role * path Role id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/admin/roles/{role} Delete the role

Authentication

Bearer token

Scopes — any one of

platform:users:write

Parameters

NameInDescription
role * path Role id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/tournaments List tournaments

Authentication

Bearer token

Scopes — any one of

platform:tournaments:read

Parameters

NameInDescription
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/admin/tournaments Create a tournament

Goes through the signup funnel's own path, so the tournament arrives with its owner role, its setup-progress rows and its smart-defaulted settings.

Authentication

Bearer token

Scopes — any one of

platform:tournaments:write

Parameters

NameInDescription
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.

Request body

FieldTypeDescription
owner_user_id integer The account that will own it.
name string
sport_code string
time_zone string
country_code string
GET /api/v1/admin/tournaments/{tournament} Get the tournament

Authentication

Bearer token

Scopes — any one of

platform:tournaments:read

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
PATCH /api/v1/admin/tournaments/{tournament} Update the tournament

Authentication

Bearer token

Scopes — any one of

platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/admin/tournaments/{tournament} Delete the tournament

Authentication

Bearer token

Scopes — any one of

platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
POST /api/v1/admin/tournaments/{tournament}/restore Restore the tournament

Authentication

Bearer token

Scopes — any one of

platform:tournaments:write

Parameters

NameInDescription
tournament * path The tournament, by uuid or url_key. Numeric ids are deliberately not accepted.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/transactions List transactions

Authentication

Bearer token

Scopes — any one of

platform:billing:read

Parameters

NameInDescription
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
GET /api/v1/admin/users List users

Authentication

Bearer token

Scopes — any one of

platform:users:read

Parameters

NameInDescription
page query Page number.
per_page query Page size, clamped to 100 rather than refused.
POST /api/v1/admin/users Create a user account

Goes through UserService, which hashes the password (or generates one nobody knows when none is given), records the signup and fires Registered so verification mail goes out. Omitting password and leaving send_invitation true is the intended path for an account somebody else is creating.

Authentication

Bearer token

Scopes — any one of

platform:users:write

Parameters

NameInDescription
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
GET /api/v1/admin/users/{user} Get the user

Authentication

Bearer token

Scopes — any one of

platform:users:read

Parameters

NameInDescription
user * path User id.
PATCH /api/v1/admin/users/{user} Update the user

Authentication

Bearer token

Scopes — any one of

platform:users:write

Parameters

NameInDescription
user * path User id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.
DELETE /api/v1/admin/users/{user} Soft-delete a user account

Refused with 409 user_has_tournaments while the user still administers a tournament, because removing them can leave a live tournament with nobody able to administer it. The delete is soft: orders and invoices must outlive the account for accounting reasons.

Authentication

Bearer token

Scopes — any one of

platform:users:write

Parameters

NameInDescription
user * path User id.
Idempotency-Key header Replay-safe retries. The same key with the same body returns the first response; with a different body it is refused.