---
title: "Finishing positions for a Formula 1 session"
method: GET
path: "/v1/f1/sessions/{id}/results"
tags: ["formula1"]
---

# Finishing positions for a Formula 1 session

`GET /v1/f1/sessions/{id}/results`

## Request

- Base URL: `https://api.bigballsdata.com`
- URL: `https://api.bigballsdata.com/v1/f1/sessions/{id}/results`
- Auth: one of:
  - API key in header `x-api-key`
  - HTTP bearer

Returns per-driver finishing positions for a single session (practice,
qualifying, sprint, or race). The underlying `f1_session_results` table
is populated by a periodic worker that fetches the upstream
`/sessions` + `/drivers` + `/position` + `/laps` chain (cron:
a scheduled results cron).

Sessions queried before the worker has processed them return a 200
with an empty `data` array, distinguish "scheduled or freshly
finished" from "doesn't exist" by checking `session_type` /
`status` via `GET /v1/sessions` (GraphQL `Query.sessions`).

## Path parameters

- `id` string, required: BigBalls canonical id, format `bb_<entity>_<10-32 lowercase base32 chars>`. NARROW SCOPE: the Formula 1 stored-session surface is the only place this is minted and the only place it is accepted. F1 sessions, drivers and constructors are keyed this way end to end (1,668 of 1,668 stored result rows on 2026-09-18). Everywhere else, ids are a `StoredId` and this format is REJECTED with a 400 - so do not construct one, and do not carry one across surfaces.

## Response `200`

ok

- object: The standard response wrapper. Only `data` is guaranteed. `error` is absent (not null) on 16 of 40 live 200 responses measured 2026-09-18, so test for the KEY before reading it; this block declared it required until then. On a non-2xx, `error` is present and `data` is absent.
  - `data` SessionResult[], required
    - `position` integer, required: 1-indexed finishing position.
    - `driver_id` string, required: BigBalls canonical id, format `bb_<entity>_<10-32 lowercase base32 chars>`. NARROW SCOPE: the Formula 1 stored-session surface is the only place this is minted and the only place it is accepted. F1 sessions, drivers and constructors are keyed this way end to end (1,668 of 1,668 stored result rows on 2026-09-18). Everywhere else, ids are a `StoredId` and this format is REJECTED with a 400 - so do not construct one, and do not carry one across surfaces.
    - `team_id` string: BigBalls canonical id, format `bb_<entity>_<10-32 lowercase base32 chars>`. NARROW SCOPE: the Formula 1 stored-session surface is the only place this is minted and the only place it is accepted. F1 sessions, drivers and constructors are keyed this way end to end (1,668 of 1,668 stored result rows on 2026-09-18). Everywhere else, ids are a `StoredId` and this format is REJECTED with a 400 - so do not construct one, and do not carry one across surfaces.
    - `driver_name` string: Driver full name
    - `team_name` string: Constructor name
    - `best_lap_seconds` number
    - `gap_to_leader_seconds` number
    - `laps_completed` integer
    - `dnf` boolean, required: True when the driver did not finish (mechanical
  - `meta` ResponseMeta: Response metadata. NOTHING here is guaranteed: measured over 38 live envelopes on 2026-09-18, `cached` and `request_id` appeared in 29, `source` in 28, `cache_age_ms` in 9 and `confidence` in 6. This block previously declared all five REQUIRED, which no response has ever satisfied. Treat every field as optional and branch on its absence. Routes add their own keys here (`count`, `limit`, `offset`, `note`, `total`, and per-endpoint ones), so do not assume a closed set.
    - `date_window` object: Present when ?date= was applied. The exact window the filter used, so an omission at a day boundary is visible. start_utc is inclusive, end_utc exclusive. timezone is UTC, or the zone named by ?tz=, in which case the window is that local day. Boxing card dates are published event dates, so timezone and bounds are null there.
      - `date` string
      - `timezone` string, nullable
      - `start_utc` string, date-time, nullable
      - `end_utc` string, date-time, nullable
      - `note` string
    - `source` 'official-league' | 'aggregator-paid' | 'aggregator-free' | 'community-scraper' | 'forecast' | 'mixed' | 'cache' | 'none' | 'unknown-source' | 'stored' | 'catalogue' | 'gateway' | 'coverage-snapshot': Opaque source-tier label. Customers never see the vendor identity. `forecast` marks a weather forecast (GET /v1/matches/{id}/weather).
    - `confidence` number, float
    - `cached` boolean
    - `cache_age_ms` integer
    - `request_id` string
    - `fields_missing` string[]
    - `note` string: Short factual disclosure about something this response deliberately withheld, present only when there is something to disclose. On live scores it appears when `match_id` could not be resolved to a stored match and was therefore omitted: it gives the counts and points at `/v1/stored/matches`, whose ids you can call back into. Absent when every served id resolves. Distinct from `message`, which explains `coverage: false` or a stale response. This one is attached to a response that DID serve data and names the part of it that is deliberately missing.
  - `error` ApiError
    - `code` string, required
    - `message` string, required
    - `details` unknown

## Other responses

- `400`: Invalid session id (must match `bb_session_<…>`).

---

[API](https://skmtc.dev/bigballsdata/apis/big-ball-sports-api.md) · [All operations](https://skmtc.dev/bigballsdata/apis/big-ball-sports-api/llms.txt) · [OpenAPI document](https://skmtc.dev/bigballsdata/apis/big-ball-sports-api/revisions/31fb54ac414e?raw)
