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.

units_contracted is what the hotel holds for you. 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.

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.

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

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}/candidates/{candidate} Get the candidate

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 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.
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.
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.
POST /api/v1/tournaments/{tournament}/candidates/{candidate}/reject Reject a registration

Marks the candidate rejected. 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.
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}/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}/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.
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.
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}/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}/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.
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.
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}/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, round_order, rest, max_per_day, team_busy, no_slot — each of which points at a different remedy. Pass the returned fingerprint to /schedule/apply.

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 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 List standings

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
generation_code string league, knockout, or groups_and_knockout.
teams_number integer
groups_number integer
playoff_rounds_number 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.

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.