Consume
Results and standings
Every reported score with its source, and deterministic tables that explain themselves.
A result is an observation like everything else: sources report scores, the conflict policy picks a winner by rank, and the losers stay visible. GET /v1/fixtures/{id}/results returns every report with its source and marks the one that won — when two scorers kept two books, the disagreement is information, not a bug.
Standings are computed, never edited
When a final result lands on a fixture in a pool or league stage, the table recomputes in the same transaction and oyss.standing.updated fires. Given the results and the rules there is exactly one right table — a wrong table is a wrong result, and a wrong result is corrected by an observation from a ranked source.
The rules are the stage’s, not ours: the competition observation carries points ("3-1-0" is common, not universal) and an ordered tiebreakers list. Unknown rule names are rejected at ingest rather than silently skipped. When a host never published rules, a conservative default applies and the response says so (tiebreak_source: "default").
| Rule | Meaning |
|---|---|
points | Points under the stage’s scheme; always applied first |
head_to_head:mini_table | Points recomputed among the tied teams only |
head_to_head:pairwise_only | Head-to-head, but only when exactly two teams are tied |
goal_diff / goal_diff_capped:N | Goal difference, optionally capped at N per game |
goals_for / goals_against / wins | The usual columns |
coin_toss | Not computable: the tie stands, marked, until decided |
Honesty about partial data is part of the contract: complete is false while any game lacks a final result, missing_fixtures counts them, provisional positions are flagged, and every row carries a trace — the ordered rules that placed it — so "why is Riverbend second?" is answerable from the response. derived_from names the exact fixture versions the table came from.