StatsHub Docs
Plans

API v2 full capability parity plan

The execution plan for making API v2 cover every legacy API capability with coherent resources, explicit security, bounded collections, and complete OpenAPI evidence.

Goal: Make /api/v2 provide every capability available through the legacy API, including authenticated writes and operational integrations, while giving v2 coherent resources, predictable pagination, explicit authentication, Problem Details errors, and complete OpenAPI coverage.

The existing v2 surface is not complete. It is a curated set of canonical reads plus account favorites. Missing watchlists, tracker and report mutations, live alerts, editorial data, shotmaps, heatmaps, administration, billing, and other legacy behavior are unfinished v2 work. They are not acceptable exclusions.

This plan treats capability parity as the target. V2 does not preserve every legacy URL, parameter name, or response quirk. An unchanged old application must continue to call legacy /api/*; migrating it to /api/v2/* requires a client update or an explicit compatibility adapter.

Baseline on 2026-09-02

SurfaceOperationsGETOther methods
Legacy v1 in the combined OpenAPI document299192107
Focused v2 OpenAPI document53476

The legacy Next.js source contains 221 route files. Three capabilities are not ported into Go v1 and therefore require direct v2 coverage as part of this project:

  • tracker bankrolls;
  • fixture unavailability; and
  • the value-bets v4 workflow.

The 299 documented v1 operations cover these capability groups:

Capability groupOperationsReadsMutations and protocol methods
Core football and reference data12310122
Betting, models, and analytics351916
User workflows and alerts391425
Administration and ingestion502228
Billing, automation, and integrations19415
Basketball14140
Editorial and delivery17161
Platform220

These counts measure the work inventory, not the required number of v2 URLs. One v2 operation can replace several legacy operations when it preserves all their behavior. A legacy operation can also map to several v2 operations when the old route mixed unrelated responsibilities.

Non-negotiable constraints

  • Keep legacy /api/* behavior unchanged while clients migrate.
  • Map every documented v1 operation and every legacy-only capability to v2.
  • Do not use a hidden v1 fallback in any v2 handler or first-party v2 client.
  • Do not mark an operation complete from OpenAPI alone. Verify its route, security, database behavior, response schema, and failure behavior.
  • Use the configured real dataset for read verification and public previews. Do not add sample-data, empty-data, redaction, or preview-hiding switches.
  • Run write verification with dedicated principals, transactions where possible, and deterministic cleanup. Never test destructive writes against uncontrolled production records.
  • Preserve deliberate security improvements. Capability parity does not mean reproducing anonymous administrative access, unverified webhooks, or other legacy vulnerabilities.

Deliverables

The project is complete only when it has all of these artifacts:

  1. A machine-readable capability manifest covering v1 and legacy-only routes.
  2. Design records for the v2 domain vocabulary and cross-cutting contracts.
  3. Mounted Go handlers for every approved v2 operation.
  4. A focused OpenAPI document generated from the mounted v2 surface.
  5. Contract, authorization, database, mutation, and performance evidence.
  6. Web and Expo clients that use v2 without implicit v1 fallbacks.
  7. Separate v1 and v2 explorer and reference documentation.
  8. Runtime dashboards that show operation use, failures, latency, and v1 callers during migration.

Phase 1: Build the parity manifest

Generate the source inventory from the legacy OpenAPI document, the Go router, and the three remaining Next.js routes. Store it in a checked-in, machine-readable file rather than a prose checklist.

Each manifest entry must contain:

  • legacy method, path, operation ID, and source handler;
  • stable capability ID and capability group;
  • public, user, superadmin, service, or webhook security persona;
  • request parameters, body, media type, and validation behavior;
  • success payload, errors, side effects, and external integrations;
  • proposed v2 operation ID or operation IDs;
  • migration strategy: direct, merged, split, or protocol-specific;
  • implementation owner module and first-party consumers;
  • lifecycle state: discovered, designed, implemented, contract-verified, data-verified, client-migrated, or rollout-ready; and
  • links to tests and design records.

Add continuous integration checks that fail when:

  • a legacy operation or source route has no manifest entry;
  • a manifest entry has no v2 mapping;
  • a mapped operation is absent from the router or focused OpenAPI document;
  • duplicate operation IDs exist; or
  • a removed legacy operation has no approved replacement or retirement record.

Exit gate: zero unmapped v1 operations and zero unmapped legacy-only capabilities. Every entry has an assigned security persona and implementation wave.

Phase 2: Freeze the v2 platform contract

Write design records before expanding the route count. Reuse the rules already implemented by the current v2 surface and close the remaining gaps.

Resource and representation rules

  • Use canonical domain terms: competition, competition season, competition phase, fixture, fixture incident, lineup, market, price, value bet, betting model, team, player, referee, and manager.
  • Use plural resource nouns and ownership-based nesting. Do not encode actions as route names when a resource or job represents the behavior.
  • Treat IDs as opaque strings at the contract boundary, even when the current database stores integers.
  • Encode timestamps as RFC 3339 UTC strings and define the timezone for date-only values.
  • Return one resource under data. Return collections under data with documented navigation metadata.
  • Use closed response schemas. Add an explicit extension point only where the data is intentionally open-ended.
  • Reject unknown query and body fields so misspellings do not silently change results.

Collection rules

  • Use signed cursor pagination for mutable feeds and large entity collections.
  • Use page-number pagination for ranked boards that require arbitrary page access across explicit sort columns.
  • Leave small, finite reference sets unpaged only when a measured upper bound is part of the contract.
  • Add a deterministic ID tie-breaker to every sort.
  • Bind cursors to resource, filters, sort, direction, and contract version.
  • Apply filters and pagination in the database before enrichment unless a design record proves why that is impossible.
  • Return aggregates from aggregate operations. Do not force clients to download detail rows to calculate summary cards.

Authentication and authorization rules

Define and test an authorization matrix for:

  • anonymous public reads;
  • Supabase bearer tokens;
  • Supabase session cookies;
  • resource-owning users;
  • superadmins;
  • internal service identities; and
  • signed provider webhooks.

Document security requirements per operation in OpenAPI. Derive ownership from the authenticated identity, return 401 for missing or invalid credentials, and return 403 for valid identities without permission. Public preview must use the same authorization rules and real data as production; environment must not become an undocumented authorization dimension.

Mutation and integration rules

  • Use POST to create resources or start jobs, PATCH for partial updates, and DELETE for deletion or cancellation.
  • Define atomicity and conflict behavior for every write.
  • Require idempotency keys for retryable creates, ingestion triggers, alerts, billing actions, and other operations where duplicate execution is harmful.
  • Deduplicate webhook delivery by provider event ID and verify signatures before parsing the event as trusted input.
  • Model long-running imports, analyses, and reports as job resources with a status operation instead of holding requests open.
  • Specify concurrency control for updates that can overwrite newer state.

Errors, caching, and limits

  • Return RFC 9457 Problem Details as application/problem+json for every JSON error.
  • Give each error a stable type and code; never require clients to parse prose.
  • Mark authenticated and user-specific responses private, no-store.
  • Give public responses explicit cache and freshness policies.
  • Define route-class rate limits and return structured 429 responses with retry information.
  • Define upload, request-body, date-range, page-size, and response-size limits.

Exit gate: design records are accepted, shared middleware and schema types are tested, and one representative public read, private read, mutation, webhook, and job operation passes the complete contract.

Phase 3: Implement complete domain coverage

Implement in vertical waves. Every wave includes handlers, database queries, OpenAPI, manifest updates, tests, documentation, and first-party client migration. Do not accumulate undocumented handlers for a later specification pass.

Wave A: Core football and reference data

Complete competitions, seasons, phases, standings, fixtures, incidents, statistics, lineups, fixture unavailability, odds, odds movements, teams, players, player season statistics, positions, percentiles, heatmaps, shotmaps, referees, managers, venues, regions, countries, search, comparisons, rosters, and schedule/history views.

Resolve the remaining aggregate and projection routes into explicit resources rather than recreating legacy handler names.

Wave B: Betting, models, and analytics

Complete markets, prices, value bets, value-bets v4 behavior, matchup edges, betting models, model outputs, player and team prop boards, expected-stat models, ranked views, lineup projections, fair-price calculations, data coverage, and analytical visualizations.

Record the formula version, model version, input freshness, and pagination order wherever they affect reproducibility.

Wave C: User workflows, tracker, reports, and alerts

Complete the authenticated account surface: favorites, watchlists, tracker bankrolls and entries, tipster workflows, report and hide actions, suggestions, live foul/card alerts, and value-bet lineup alerts.

Use /me/* only for resources owned by the current user. Make ownership, subscription requirements, idempotency, and notification delivery state explicit.

Wave D: Administration and ingestion

Cover every dashboard and admin capability, including entity maintenance, data ingestion, recalculation, replay, job status, and operational inspection. Require superadmin or internal-service authorization per operation.

Replace synchronous command-style routes with auditable job resources where the work can outlive one request. Preserve the capability and result, not an accidental request lifetime.

Wave E: Billing, automation, and external integrations

Cover Stripe account and webhook flows, Model Context Protocol (MCP) tools, bots, chat and analysis workflows, tweets, and other provider callbacks.

Keep provider protocols at explicit integration boundaries. A webhook or MCP transport does not need to look like a normal collection, but it must still be versioned, authenticated, documented, observable, and represented in the capability manifest.

Wave F: Basketball, editorial, and delivery formats

Cover basketball reads, World Cup editorial data, previews, images, and XML sitemaps. Decide in a design record whether multi-sport resources share a canonical top-level model or use a sport namespace.

Document non-JSON response schemas and content types. Verify XML and binary delivery directly; do not force these routes into a JSON envelope.

Wave exit gate: all mapped capabilities in the wave reach contract-verified and data-verified, and their migrated first-party callers make no v1 requests for those capabilities.

Phase 4: Prove behavior continuously

Apply these checks to each operation as it lands:

Contract tests

  • The router and focused OpenAPI document expose the same method and path.
  • Every operation ID is unique and stable.
  • Success and error media types, statuses, headers, and bodies match the contract.
  • All JSON success schemas are closed and all JSON errors are Problem Details.
  • Unknown parameters, invalid cursors, oversized bodies, and unsupported methods fail consistently.

Authorization tests

  • Exercise anonymous, unauthenticated, owning-user, other-user, superadmin, service, and webhook personas where applicable.
  • Verify row ownership and subscription gates at the database boundary.
  • Verify private responses can never receive public cache headers.

Database and mutation tests

  • Run representative reads against the configured real dataset and assert meaningful non-empty results for known records.
  • Compare v1 and v2 semantics for the same capability, allowing only approved differences in shape, naming, pagination, security, or bug fixes.
  • Test create, read-after-write, update, conflict, retry, delete, and cleanup for every mutable resource.
  • Verify idempotency and webhook replay behavior.
  • Count database queries and prove filters and pagination occur before expensive enrichment.

Performance and resilience tests

  • Set latency, query-count, response-size, and memory budgets by route class.
  • Test maximum page sizes, date ranges, and filter combinations.
  • Verify cancellation, deadlines, pool exhaustion, rate limiting, and provider failures return bounded, structured responses.

Phase 5: Migrate first-party clients

Build generated or typed client modules from the focused v2 OpenAPI document. Migrate the web app and Expo app capability by capability after the matching wave passes its gates.

For each migration:

  1. replace the legacy call and response adapter;
  2. add client tests for pagination, authentication, errors, and empty states;
  3. run the screen against the real preview dataset;
  4. add a static boundary test that rejects the old route in migrated code; and
  5. mark the manifest entry client-migrated only after both first-party clients are accounted for.

Do not install a global “try v2, then call v1” mechanism. If a staged rollout needs comparison traffic, perform read-only shadow comparison on the server and never use the shadow response as an implicit fallback.

Phase 6: Complete documentation and rollout

  • Keep separate v1 and v2 folders, explorers, references, and OpenAPI files.
  • Add authentication, pagination, errors, idempotency, webhooks, jobs, and migration guides under v2.
  • Show deprecation metadata only after a replacement is implemented and its consumers are known.
  • Publish operation-level dashboards for request count, p50/p95/p99 latency, error type, caller, and version.
  • Use v1 traffic telemetry to identify external callers. Do not retire v1 on a calendar guess.
  • Roll out by capability group, with a rollback that switches first-party callers back through an explicit release change rather than a runtime hidden fallback.

V1 retirement is a separate project. Full v2 parity makes retirement possible; it does not authorize breaking unknown external clients.

Definition of done

API v2 is a complete successor only when all statements below are true:

  • The capability manifest contains every one of the 299 v1 operations and all three legacy-only capabilities, with zero unmapped entries.
  • Every mapped v2 operation is mounted, present in the focused OpenAPI document, documented, and executable.
  • Every operation has closed success schemas, explicit security, and complete Problem Details errors where the response is JSON.
  • Every collection is bounded, deterministically ordered, and paginated or explicitly justified as finite.
  • Every mutation passes success, authorization, conflict, retry, idempotency, and cleanup tests as applicable.
  • Public preview reads the configured real dataset without a hiding or sample data mechanism.
  • Web and Expo contain no legacy calls for migrated capabilities and no silent v1 fallback mechanism.
  • Performance and resilience budgets pass for every route class.
  • Runtime telemetry shows which external callers still use v1.
  • The legacy v1 surface remains unchanged until a separately approved deprecation and retirement process completes.

On this page