---
title: "Start scoring a match"
method: PATCH
path: "/v1/matches/{id}/start_scoring"
tags: ["Matches"]
---

# Start scoring a match

`PATCH /v1/matches/{id}/start_scoring`

## Request

- Base URL: `https://api.hify.club`
- URL: `https://api.hify.club/v1/matches/{id}/start_scoring`
- Auth: API key in header `X-User-Token`

Claims the match for the current user, transitions it to in_progress, seeds the initial round tree (set + game), and optionally reassigns the match to the tournament's game on a different court. This is the combined "claim + start + seed rounds" action used by referees.

## Request body

- object
  - `match` object
    - `court_number` integer: Optional — the court the match is actually being played on. When it differs from the match's current court, the match is reassigned to the tournament's game already scheduled on that court for this match's time slot; the current game's court is never changed. Returns 404 if the court does not exist at the facility, and 422 if the tournament has no game on it in that slot, or that game already has another live match.
    - `first_serve_side` 'side_a' | 'side_b' | 'a' | 'b': Optional — which side served first. Persisted on first start_scoring only; not overwritten on subsequent calls.
    - `device_id` string: Optional — the scoring device registering as the match's single writer. A claim from a different device bumps the writer epoch: the previous claim is released so the old device's unsynced events are fenced at ingest (409 stale_claim) instead of interleaving into the new log.

## Response `200`

Match started for scoring

- Match
  - `id` integer
  - `game_id` integer
  - `sequence_number` integer, nullable
  - `round_number` integer, nullable
  - `stage` 'league' | 'quarterfinal' | 'semifinal' | 'knockout' | 'final' | 'third_place': Where the match sits in the tournament
  - `status` 'pending' | 'in_progress' | 'completed'
  - `winner_side` 'side_a' | 'side_b' | 'draw', nullable
  - `first_serve_side` 'side_a' | 'side_b', nullable: Side that served first; set via start_scoring
  - `completion_reason` 'normal' | 'injury' | 'walkover' | 'other', nullable: How the match ended, set from the match_completed event: normal for a match played to its conclusion, injury/walkover/other for an early end. Null until the match completes.
  - `category_label` string, nullable: Display category, e.g. "Open Mixed Doubles"
  - `scoring_config_snapshot` object: The compiled rules the match is scored under, resolved from its scoring format (or its tournament's). Empty when neither names one.
  - `scored_by` object, nullable: The scorer who last claimed the match, read from the newest match_claim regardless of its status. Null when the match was never claimed.
    - `user_id` string, uuid
    - `name` string, nullable: Scorer display name, e.g. "Prajapati D.". Null until the scorer has a first/last name on record.
  - `started_at` string, date-time, nullable: scored_at of the first non-voided score entry; null until the match has been scored.
  - `ended_at` string, date-time, nullable: scored_at of the last non-voided score entry; null until the match has been scored.
  - `duration_seconds` integer, nullable: ended_at minus started_at; null until a second entry exists.
  - `created_at` string, date-time
  - `updated_at` string, date-time
  - `match_participants` MatchParticipant[]
    - `id` integer
    - `match_id` integer
    - `side` 'side_a' | 'side_b'
    - `participant_type` 'User' | 'AnonymousTournamentParticipant'
    - `participant_id` string, uuid
    - `position` string, nullable
  - `team_names` object: Each side's team name; null for a side without a team.
    - `side_a` string, nullable
    - `side_b` string, nullable
  - `match_sets` MatchSet[]
    - `id` integer
    - `match_id` integer
    - `sequence_number` integer
    - `winner_side` 'side_a' | 'side_b', nullable
    - `score` object, nullable
  - `cameras` object[]: Enabled cameras of the arena where the match is played. Included in the show response.
    - `id` integer
    - `in_arena_id` string
  - `arena` object: The arena where the match is played, including the device hostname.
    - `id` integer
    - `name` string
    - `in_facility_id` integer
    - `var_hostname` string, nullable: cloudflare_tunnel_hostname of the arena's device, if any.

## Other responses

- `401`: Unauthorized
- `404`: Match not found, or court_number does not resolve to a court at the facility
- `422`: Invalid state transition, match already claimed, invalid first_serve_side, a court change on a match that is not part of a tournament, the tournament has no game on the requested court in this match's time slot, or another match is already live on the target court's game (starting would corrupt that court's livestream)

---

[API](https://skmtc.dev/hify/apis/hify-apis.md) - [All operations](https://skmtc.dev/hify/apis/hify-apis/llms.txt) - [OpenAPI document](https://skmtc.dev/hify/apis/hify-apis/revisions/b5920403538d?raw)
