---
title: "Submit a video"
method: POST
path: "/api/v1/videos"
tags: ["Videos"]
---

# Submit a video

`POST /api/v1/videos`

Submit a video from your backend using `x-api-key` and the `League` header
(`glory-league` for Glory League). Keep the API key on your server. The JWT used
to open Stats Breakdown is not a substitute for these API headers.

### Choose a submission flow

- **One-shot (Glory League):** include `home_team_name`, `away_team_name`,
  `home_team_color`, and `away_team_color` together. For a new video with an
  available credit, the API copies the source into Mux, charges one video credit,
  and starts processing. The response is HTTP `200` with `status: "processing"`;
  Stats Breakdown skips the Video Info form. No separate call to
  `POST /api/v1/videos/{video_uuid}/info` is required.
- **Two-phase (Glory League):** submit the video before all four game-info fields
  are available. For a new video with an available credit, the API copies the
  source into Mux, reserves one credit without spending it, and returns HTTP
  `200` with `status: "pending"`. Later, provide all four fields through
  `POST /api/v1/videos/{video_uuid}/info`, either from your backend with the
  required endpoint permission or through the Stats Breakdown form. That step
  charges the reserved credit and starts processing. Cancelling before info is
  submitted releases the reservation; cancellation after processing starts does
  not refund the credit.

### Quota and retries

- **No available video quota:** HTTP `200`, `status: "payment_required"`. No
  submission is created and no source URL check or Mux ingest is performed.
  After purchasing credits, repeat `POST /api/v1/videos` with the same
  `video_uuid`. `/info` cannot create the missing submission.
- **Existing `video_uuid`:** HTTP `200` with the existing status. This is a
  read-only retry: it does not check the source URL, reserve/charge another
  credit, create another Mux asset, or overwrite game info or `return_url`.
  Repeating this POST with additional fields does not complete a pending
  submission; use `/api/v1/videos/{video_uuid}/info` instead.
- Malformed input, authentication/authorization failures, inaccessible video
  sources, and service errors still return the appropriate non-200 status.
  HTTP `200` means a recognized routing outcome, not that processing has finished.

### Follow progress

Open the existing Stats Breakdown URL or call
`GET /api/v1/videos/{video_uuid}/status`. The status response reports
`info_required: true` while a pending submission still needs game info. This
flag is returned by `/status`, not by this submit response. Completion and failure
can also be received through separately registered `video.completed` and
`video.failed` webhooks.

When `VIDEO_ENDPOINTS_LIVE` is false, this endpoint returns a preview response
without creating a submission or starting processing.

## Headers

- `x-api-key` string, required — Required API key issued by Preciser.
- `League` string, required — Required tenant/database selector, for example pitchbio-master.

## Request body

- union — JSON body for POST /api/v1/videos, including Glory League's two flows. Send video_url, the billing user_id UUID, and a stable video_uuid. For a new Glory League video with available credit, both team names and both jersey colors start processing immediately and charge one credit (one-shot). Otherwise, missing game info leaves the submission pending with one credit reserved until POST /api/v1/videos/{video_uuid}/info (two-phase). Existing video_uuid retries do not update game info or charge again. No available quota returns payment_required without creating a submission. See the request-body examples and field descriptions for supported colors and optional return_url, metadata, and rosters.
  - object
    - `video_uuid` string, uuid, nullable — Client-provided video UUID (auto-generated if omitted)
    - `org_id` string, nullable — Optional organization id retained for future organization-level billing. It is not the billing key while billing is per user.
    - `org_name` string, nullable — Optional organization or account display name retained for future organization-level billing.
    - `jwt` string, nullable — Short-lived token Glory League issued for this user; stored for reference when the account is first seen.
    - `user_id` string, uuid, nullable, required — Glory League user UUID. This is the current billing key: the user's wallet is charged and topped up using this value. New integrations must send it; org_id-only requests remain accepted temporarily for backward compatibility.
    - `video_url` string, required — Downloadable HTTP(S) source URL. The API copies this source into Mux and uses the Mux rendition for all subsequent processing.
    - `video_mode` 'instant' | 'accuracy' — Processing mode for the submitted video. Glory League submissions default to 'accuracy' when omitted.
    - `return_url` string, uri, nullable — Optional absolute HTTPS URL to return the user to after a successful Stripe credits purchase. It is bound to this user and video UUID.
    - `home_team_uuid` string, uuid, nullable — Home team UUID (optional for URL-only submissions)
    - `home_team_name` string — Home team name
    - `home_team_score` integer, nullable — Home team score
    - `home_team_roster` GLRosterItem[], nullable — Home team roster
      - `jersey_number` string, required — Player jersey number
    - `away_team_uuid` string, uuid, nullable — Away team UUID (optional for URL-only submissions)
    - `away_team_name` string — Away team name
    - `away_team_score` integer, nullable — Away team score
    - `away_team_roster` GLRosterItem[], nullable — Away team roster
      - `jersey_number` string, required — Player jersey number
    - `billing_tier` string, nullable — Billing tier identifier
    - `game_date` string, nullable — Game date (YYYY-MM-DD)
    - `description` string — Game/venue description
    - `home_team_color` string — Jersey color as 3- or 6-digit HEX (with or without '#') or a supported case-insensitive jersey-palette name: white, black, red, blue, navy, sky blue, dark green, green, yellow, gold, orange, purple, maroon, gray, charcoal, brown, pink, teal, silver, beige. Names use the DMS jersey palette, not CSS values (e.g. blue/royal blue = #4169E1, green = #31A531, gray/grey/light gray = #D3D3D3). Normalized to #RRGGBB.
    - `away_team_color` string — Jersey color as 3- or 6-digit HEX (with or without '#') or a supported case-insensitive jersey-palette name: white, black, red, blue, navy, sky blue, dark green, green, yellow, gold, orange, purple, maroon, gray, charcoal, brown, pink, teal, silver, beige. Names use the DMS jersey palette, not CSS values (e.g. blue/royal blue = #4169E1, green = #31A531, gray/grey/light gray = #D3D3D3). Normalized to #RRGGBB.
  - object
    - `video_uuid` string, uuid, nullable — Client-provided video UUID (auto-generated if omitted)
    - `org_id` string, nullable, required — Optional organization id retained for future organization-level billing. It is not the billing key while billing is per user.
    - `org_name` string, nullable — Optional organization or account display name retained for future organization-level billing.
    - `jwt` string, nullable — Short-lived token Glory League issued for this user; stored for reference when the account is first seen.
    - `user_id` string, uuid, nullable — Glory League user UUID. This is the current billing key: the user's wallet is charged and topped up using this value. New integrations must send it; org_id-only requests remain accepted temporarily for backward compatibility.
    - `video_url` string, required — Downloadable HTTP(S) source URL. The API copies this source into Mux and uses the Mux rendition for all subsequent processing.
    - `video_mode` 'instant' | 'accuracy' — Processing mode for the submitted video. Glory League submissions default to 'accuracy' when omitted.
    - `return_url` string, uri, nullable — Optional absolute HTTPS URL to return the user to after a successful Stripe credits purchase. It is bound to this user and video UUID.
    - `home_team_uuid` string, uuid, nullable — Home team UUID (optional for URL-only submissions)
    - `home_team_name` string — Home team name
    - `home_team_score` integer, nullable — Home team score
    - `home_team_roster` GLRosterItem[], nullable — Home team roster
      - `jersey_number` string, required — Player jersey number
    - `away_team_uuid` string, uuid, nullable — Away team UUID (optional for URL-only submissions)
    - `away_team_name` string — Away team name
    - `away_team_score` integer, nullable — Away team score
    - `away_team_roster` GLRosterItem[], nullable — Away team roster
      - `jersey_number` string, required — Player jersey number
    - `billing_tier` string, nullable — Billing tier identifier
    - `game_date` string, nullable — Game date (YYYY-MM-DD)
    - `description` string — Game/venue description
    - `home_team_color` string — Jersey color as 3- or 6-digit HEX (with or without '#') or a supported case-insensitive jersey-palette name: white, black, red, blue, navy, sky blue, dark green, green, yellow, gold, orange, purple, maroon, gray, charcoal, brown, pink, teal, silver, beige. Names use the DMS jersey palette, not CSS values (e.g. blue/royal blue = #4169E1, green = #31A531, gray/grey/light gray = #D3D3D3). Normalized to #RRGGBB.
    - `away_team_color` string — Jersey color as 3- or 6-digit HEX (with or without '#') or a supported case-insensitive jersey-palette name: white, black, red, blue, navy, sky blue, dark green, green, yellow, gold, orange, purple, maroon, gray, charcoal, brown, pink, teal, silver, beige. Names use the DMS jersey palette, not CSS values (e.g. blue/royal blue = #4169E1, green = #31A531, gray/grey/light gray = #D3D3D3). Normalized to #RRGGBB.

## Response `200`

Successful Response

- GLVideoSubmitResponse — Response schema for Glory League video submission.
  - `success` boolean, required — Whether the submission was successful
  - `video_uuid` string, required — Stable video identifier for status/results calls. Echoes the caller's video_uuid, or contains the server-generated UUID when it was omitted.
  - `message` string, required — Status message
  - `status` string, required — Current processing/routing status. `payment_required` means no submission was created and Stats Breakdown should show checkout.
  - `created_at` string, date-time, required — Timestamp of submission

## Other responses

- `422` — Validation Error

## Changes

- **2026-09-03** `24ef9111adac` — 1 info
  - added the new optional request property `video_mode`
- **2026-08-27** `9b0abde08b06` — 4 breaking, 2 info
  - the `header` request parameter `League` became required
  - the `header` request parameter `x-api-key` became required
  - `header` request parameter `League` list-of-types was narrowed by removing types `null`
  - `header` request parameter `x-api-key` list-of-types was narrowed by removing types `null`
  - …2 more
- **2026-08-26** `edd51549cfb6` — 1 info
  - added the new optional request property `return_url`
- **2026-08-12** `16e2b6a1c2bb` — 1 breaking, 7 info
  - the `user_id/anyOf[subschema #1]/` request property format changed from no format to `uuid`
  - added `subschema #1, subschema #2` to the request body `anyOf` list
  - the request property `org_id` became optional
  - the request property `org_name` became optional
  - …4 more

[Change history](https://skmtc.dev/preciser/apis/preciser-data-management-api/changes/api/v1/videos/post.md)

---

[API](https://skmtc.dev/preciser/apis/preciser-data-management-api.md) · [All operations](https://skmtc.dev/preciser/apis/preciser-data-management-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/preciser/preciser-data-management-api/revisions/24ef9111adac/schema)
