Skip to content

API overview

Product boundary

The API is a primary product. It must be designed and implemented by the team as HTTP endpoints. Generated database endpoints must not be used as the application API. Supabase may provide managed authentication, but application data must pass through the handwritten backend.

Initial conventions

  • Base path: /api/v1
  • Format: JSON unless returning a documented dataset file
  • Stable identifiers: opaque, immutable, non-recycled string identifiers
  • Pagination: cursor pagination for Basic collection endpoints
  • Filtering: explicit documented camelCase query parameters
  • Sorting: endpoint-specific whitelisted fields with deterministic tie-breaking
  • Errors: consistent machine-readable code, safe message, and optional field or event details
  • Authentication: established provider/library for users; separate API-consumer credentials when introduced
  • Versioning: URI major version only; v1 is supported at /api/v1, confirmed by the API-Version: v1 response header, and unsupported major versions return 404 UNSUPPORTED_API_VERSION

The version-controlled API contract is published in the OpenAPI specification.

ADR-016 defines the implemented canonical cricket-resource hierarchy with optional API-key identification. Requester-owned consumer access remains follow-up issue #822.

Live development API

The deployed development backend is hosted on Azure Container Apps:

The deployment guides and Sprint evidence retain the deployment/acceptance trail. Availability is verified as part of milestone close-out rather than inferred from this documentation page.

See API versioning and deprecation for compatibility, deprecation and retirement rules.

See Shared API Contracts for the complete identifier, response, error, filtering, sorting, date/time, event-ordering, and pagination conventions.

Interactive API Explorer

The public frontend exposes an interactive API Explorer at /api. It loads the authoritative /openapi.yaml document from the backend at runtime rather than keeping a frontend copy of the contract. The page identifies v1 as the currently supported API major version and exposes the contract-defined bearer-token and consumer API-key authorization controls.

Implemented operations are available for normal exploration. Planned operations are hidden by default; users may reveal them explicitly, but interactive submission is disabled while the planned view is active.

The Explorer is discoverable from the Stat'sTheGame primary public navigation as API. The bottom-of-page API entry opens the in-app Explorer, while a separate API Documentation link continues to expose the extended MkDocs documentation.

Before the operation list, the Explorer distinguishes anonymous public reads, API-key-authenticated consumer operations and bearer-authenticated application/administrator operations. It explains that consumer keys are administrator-issued, tells prospective external consumers to request access from a Stat'sTheGame administrator or project administrator under the current access model, identifies the X-API-Key request header and consumer limits, and links directly to the consumer-key guidance. A consumer key authorizes only documented consumer operations and never grants administrator, submission or batch access.

The Explorer makes both deferred stages visible: the route-level lazy module and the backend OpenAPI specification request each show the same labelled progress indicator until their associated content is ready. A specification failure replaces that indicator with an explicit retryable error state, so an unfinished or failed Explorer is not presented as a blank page.

Signed-in administrators manage external API consumers through /admin/api-consumers. That frontend uses the existing handwritten list, issue, rotate and individual-key revoke operations and links back to the API Explorer; it complements rather than duplicates the API documentation. A selected consumer's detail view uses the owner-scoped, bearer-authenticated GET /api/v1/admin/api-consumers/{consumerId}/usage operation for safe historical aggregates. The consumer-self GET /api/v1/consumer/usage operation remains API-key authenticated and scoped to the calling consumer.

Current endpoints

GET /api/v1/health

Example response:

{
  "status": "ok",
  "service": "sport-analytics-api",
  "timestamp": "2026-08-04T19:00:00.000Z"
}

This endpoint is scaffold infrastructure only.

Current user profile

GET /api/v1/auth/me
Authorization: Bearer <supabase-access-token>

Successful response:

{
  "user": {
    "id": "42",
    "subject": "<supabase-user-id>",
    "displayName": "Example User",
    "role": "submitter",
    "approvalState": "approved",
    "requestedCompetition": {
      "competitionId": "7",
      "name": "Premier T20"
    },
    "competitionIds": ["7", "12"]
  }
}

Missing, malformed, invalid, expired or revoked tokens receive:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer

The API verifies the Supabase identity, creates or synchronizes the local account, and returns server-owned authorization state. Authentication does not promote a user, approve submission, or grant competition scope. A disabled account receives 403 Forbidden.

Account deletion

An authenticated user can permanently delete their own account through:

DELETE /api/v1/account
Authorization: Bearer <supabase-access-token>
Content-Type: application/json

{"confirmation":"DELETE"}

The endpoint accepts no target account identifier, requires a sign-in no more than 15 minutes old, and returns 422 unless the confirmation is exactly DELETE. A successful request disables the local account, revokes its role, approval and competition grants, hard-deletes the Supabase Auth user, and replaces local identity fields with a tombstone.

The backend requires a separate server-only SUPABASE_SECRET_KEY for that provider operation. If it is not configured, the route returns 501 ACCOUNT_DELETION_UNAVAILABLE before changing local state; other routes and health checks remain available.

Submissions, fixtures, deliveries, derived statistics and their stable app_user_id provenance remain. If Auth deletion or local finalization fails, the API returns 503; the account remains disabled and retry is idempotent. See Privacy and retention.

Application registration is handled by Supabase Auth; there is no backend registration or profile mutation endpoint that accepts application_role. New application accounts are synchronized as viewer, and only a trusted administrative backend process may change the role to submitter or admin.

Submitter access requests

An authenticated viewer who does not already hold a submission-capable role can request submitter access through:

POST /api/v1/submitter-access-requests
Authorization: Bearer <supabase-access-token>
Content-Type: application/json

{"competitionId":"7"}

A successful request validates and persists the selected competition and changes the authenticated application account's server-owned approval state to pending:

{
  "data": {
    "accountId": "42",
    "approvalState": "pending",
    "requestedCompetition": {
      "competitionId": "7",
      "name": "Premier T20"
    }
  }
}

The endpoint returns 401 Unauthorized when no valid authentication is supplied and 422 Unprocessable Entity when the body or competition identifier is invalid.

A 409 Conflict is returned when the account already has a pending request, has the legacy approved request state, or already holds the submitter/admin role. A previously rejected viewer may submit a new request.

The requested competition and request state are stored on the provider-neutral application account and exposed through /api/v1/auth/me and the administrator user list. They are not authorization grants: approval must atomically assign application_role = submitter and grant exactly the stored competition. The backend uses the authoritative role plus granted competition scope for submission decisions.

Administrator submitter-access decisions

Administrators can list active application users through:

GET /api/v1/admin/users
Authorization: Bearer <supabase-access-token>

The endpoint is restricted to the admin role and provides the account state needed for submitter-access review and administration. Each user includes the safe email address required by the administration interface. The backend obtains this value with its server-only Supabase Admin client and returns no provider metadata, credentials, or tokens. If that server-only configuration is unavailable or the provider lookup fails, the endpoint returns a controlled 503 response.

Only an authoritative admin may manage another active, non-administrator account. Approval and scope replacement use PATCH /api/v1/admin/users/{userId}/submitter-access; approval requires a pending viewer and exactly the valid competition stored on that request, while scope replacement for an approved submitter requires at least one valid competition. A legacy pending request without a stored competition cannot be approved and must be rejected before the viewer submits a corrected request. Sending approved: false revokes an approved submitter, removes every scope, and retains the historical approved request decision.

Rejecting a pending request is a separate action:

POST /api/v1/admin/users/{userId}/submitter-access/rejection
Authorization: Bearer <supabase-access-token>

An administrator may promote an active non-administrator through PATCH /api/v1/admin/users/{userId}/role with {"role":"admin"}. The route validates the role value server-side and prohibits self-management, disabled targets, and administrator demotion. Direct viewer and submitter changes are rejected: those states must use the submitter-access lifecycle so that approval and competition scopes remain consistent.

Rejection keeps the account as a viewer, writes rejected, clears all scopes, and allows the user to request again. Invalid lifecycle changes return 409 INVALID_SUBMITTER_ACCESS_TRANSITION and leave the account's role, request state, scopes, and audit fields unchanged.

Public read

The following endpoints are available without authentication:

GET /api/v1/competitions
GET /api/v1/competitions/{competitionId}
GET /api/v1/seasons
GET /api/v1/seasons/{seasonId}
GET /api/v1/fixtures
GET /api/v1/fixtures/{fixtureId}
GET /api/v1/fixtures/{fixtureId}/events
GET /api/v1/fixtures/{fixtureId}/events/{eventId}
GET /api/v1/fixtures/{fixtureId}/events/export.json
GET /api/v1/fixtures/{fixtureId}/events/export.csv
GET /api/v1/fixtures/{fixtureId}/statistics
GET /api/v1/fixtures/{fixtureId}/statistics/{statisticId}
GET /api/v1/fixtures/{fixtureId}/statistics/{statisticId}/events/export.json
GET /api/v1/fixtures/{fixtureId}/statistics/{statisticId}/events/export.csv
GET /api/v1/competitors
GET /api/v1/competitors/{competitorId}
GET /api/v1/participants
GET /api/v1/participants/{participantId}
GET /api/v1/participants/{participantId}/fixtures

See Public Read API for filters, pagination, deterministic ordering and example responses.

Direct event submission

Administrators can use the privileged legacy direct-import endpoint:

POST /api/v1/submissions

See Direct Event Submissions for the versioned request schema, provenance response, validation errors, payload limit, and rate limit.

File event submission

POST /api/v1/submissions/uploads

Administrators may use this legacy synchronous JSON/CSV import path. Ordinary submitter uploads use the staged /api/v1/batches pipeline so validation and review occur before publication. See Direct Event Submissions for the file types, CSV columns, limits, and errors.

Weather integration

The backend exposes the course-required runtime external API integration through:

GET /api/v1/weather

The endpoint accepts documented location and date parameters, calls Open-Meteo server-side, validates the provider response, applies a bounded timeout, and maps upstream failures to safe application errors.

See Weather API for the request parameters, response format, provider behaviour, and current limitations.

Consumer API keys

Administrators can issue, rotate and revoke external-consumer API keys. Applicable canonical cricket reads accept a valid key and apply consumer-wide request-rate, UTC daily quota and usage accounting without changing the resource URL or response schema. See Consumer API keys, rate limits and quotas.

Intermediate API areas

The Intermediate tier is implemented through the same handwritten /api/v1 boundary and is included in the version-controlled OpenAPI contract.

Batch ingestion, review and publication

Whole-season and back-catalogue packages use the asynchronous batch API. The implemented surface covers receipt, status, reports, report downloads, reference mapping, published-delivery conflict resolution, reviewer decisions, correction resubmission and publication.

See Batch ingestion receipt API for the lifecycle and authorisation rules.

Corrections and audit history

Accepted delivery corrections create immutable revisions rather than overwriting published data. Authorised users can submit a correction and retrieve the retained revision history.

See Direct Event Submissions and Protected provenance and audit API.

Participant aggregates

The public API derives season, competition and career aggregates from current accepted delivery revisions:

GET /api/v1/participants/{participantId}/statistics
GET /api/v1/participants/{participantId}/statistics/{statisticId}

See Participant aggregate calculations.

Season and competition leaderboards

GET /api/v1/statistics/leaderboards returns a bounded, server-ranked participant table for one explicit season or competition. Supply scope=season&seasonId=... or scope=competition&competitionId=..., a supported metric, and an optional limit from 1 to 50 (default 10). Invalid scope/identifier combinations, metrics and bounds return 400; a scope that does not exist returns 404.

Total metrics are most_runs, most_wickets, most_fours and most_sixes. Qualified rate metrics are highest_batting_average, highest_strike_rate, best_bowling_average, best_economy_rate and best_bowling_strike_rate. Every response names the scope and metric, returns stable participant identifiers and readable names, and carries the applicable qualification rule. See Participant aggregate calculations.

Analytics query evaluation and natural-language questions

POST /api/v1/query-definitions/evaluate answers a structured query definition from the statistics above. It requires no authentication, computes nothing of its own, and returns the published leaderboard or participant-aggregate resource unchanged, together with the endpoint and statistic identifiers the answer came from. A name that matches nothing or more than one entity is reported as an outcome rather than an error.

POST /api/v1/natural-language-queries answers the same questions written in words. It translates the question into a definition with a server-side language-model adapter, evaluates that definition through the operation above, and returns what was interpreted alongside the answer. It is anonymous too, and is protected instead by a durable per-client rate limit and daily quota, a global daily cap and a 300-character question bound.

See Analytics query for the outcomes, the name-resolution rules, the limits and the recorded limitations.

Dataset releases

Administrators can queue immutable versioned dataset releases. Public consumers can discover release metadata and download the exact checksum-backed JSON artifact.

See Dataset exports.

API consumer protections

Administrators can issue, rotate and revoke consumer API keys. Keyed consumer requests are protected by configurable per-minute rate limits and durable UTC daily quotas. Anonymous canonical reads use lower per-source and global durable minute limits, so omitting a key is not unrestricted fallback.

See Consumer API keys, rate limits and quotas.

Caching and response-time behaviour

Repeated fixture-statistics reads use a versioned 60-second server-side cache-aside path. Contributor traces bypass the cache, and accepted changes advance the fixture version so stale cached statistics are no longer reachable.

The reproducible workload, response-time targets and measurement commands are documented in Representative-scale API performance baseline.

The OpenAPI specification remains the authoritative request/response contract for all implemented endpoints.

Remaining future API areas

The following belong to later Advanced-tier work rather than the implemented Intermediate surface:

  • analyst-defined statistic definitions, validation, sandboxing and versioning;
  • late and out-of-order live-feed replay;
  • bitemporal/as-of statistic queries and release comparisons;
  • larger asynchronous analytical jobs and change-feed functionality where not already implemented for dataset-release generation.
  • Product & API — human-facing entry point for API, submission, statistics and export documentation.
  • Architecture & Data — persistence, ingestion and security boundaries behind the API.
  • Testing & Quality — API contract, browser and performance verification.

AI Declaration

The preceding API overview was reviewed and updated for the Intermediate implementation with the assistance of ChatGPT-Web[GPT-5.6 Sol]. The issue #635 public leaderboard endpoint and qualification summary were documented with the assistance of Codex[GPT-5]. The Issue #660 public API Explorer workflow was reviewed and documented with the assistance of ChatGPT-Web[GPT-5.6 Sol]. The Issue #661 public API Explorer discoverability and production UX guidance was reviewed and documented with the assistance of ChatGPT-Web[GPT-5.6 Sol]. The Issue #726 API Explorer loading-feedback guidance was updated with the assistance of Codex[GPT-5]. The documentation reading-path links were added with the assistance of ChatGPT-Web[GPT-5.6 Sol]. The issue #775 administrator consumer-management frontend boundary was documented with the assistance of Codex[GPT-5.6 Sol]. The issue #776 administrator per-consumer usage workflow was documented with the assistance of Codex[GPT-5.6 Sol]. The issue #783 public API consumer-onboarding guidance was documented with the assistance of Codex[GPT-5]. The issue #820 accepted API consumer access-model link and current/future boundary were documented with the assistance of Codex[GPT-5]. The issue #821 canonical optional-key implementation was documented with the assistance of Codex[GPT-5]. The issue #813 analytics query evaluation endpoint was documented with the assistance of Claude-Code[Claude Opus 5 (1M context)]. The issue #815 natural-language query endpoint was documented with the assistance of Claude-Code[Claude Opus 5 (1M context)].