---
title: "Your usage + remaining quota"
method: GET
path: "/v1/usage"
tags: ["platform"]
---

# Your usage + remaining quota

`GET /v1/usage`

## Request

- Base URL: `https://api.bigballsdata.com`
- URL: `https://api.bigballsdata.com/v1/usage`
- Auth: one of:
  - API key in header `x-api-key`
  - HTTP bearer

Your key's own quota and usage: live remaining quota for today and this minute (from the rate-limit counters) plus a 7-day per-day request + 4xx-error history (from usage_events). Authed by your own key. The recent[] history is empty when the gateway is running without its Postgres pool. Answers "am I rate-limited / how much have I used" without a support round-trip.

## 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` object, required
    - `plan` 'free' | 'solo' | 'multi' | 'edge' | 'pro' | 'max' | 'enterprise' | 'starter' | 'growth' | 'business': The EFFECTIVE plan: what this key can actually reach, and what `limits` below describes. Equal to the billed plan except while a referral grant is active, in which case `billed_plan` and `referral_grant` are also present. The ladder actually sold is `free` → `solo` → `multi` → `edge` → `pro` → `enterprise`. Note `multi` is the stored slug for the tier sold as **Trio**; the display name changed, the slug deliberately did not, so no stored row had to move. `max` is an internal comped tier, never self-serve. `starter`, `growth` and `business` are **deprecated**: retired from sale, never returned for a key created today, and excluded from every upgrade path the gateway builds. They stay enumerated because nothing in the schema prevents a legacy row from still holding one, and an enum that rejects a value the API can really emit fails closed on a live customer, a worse outcome than a wide enum. Treat them as read-only history; do not send a user to one.
    - `billed_plan` 'free' | 'solo' | 'multi' | 'edge' | 'pro' | 'max' | 'enterprise' | 'starter' | 'growth' | 'business': What the account is BILLED for. Present only while a referral grant is raising `plan` above it; absent otherwise, when `plan` is already the billed plan. `plan` stays the effective value because it is what the caller can actually use and what the `limits` beside it describe. Same value set as `plan` above, deprecated tiers included; a legacy row is precisely the kind of account that can still be billed for a tier we no longer sell.
    - `referral_grant` object: A time-boxed plan grant earned through the referral program. Present only while one is active. Not a subscription; it has no price and no invoice, and when it ends the account returns to `billed_plan` with nothing removed from that plan.
      - `plan` 'solo' | 'multi' | 'edge' | 'pro': The granted plan, the same value `plan` reports while it is active.
      - `expires_at` string, date-time: When the grant stops applying.
    - `limits` object
      - `per_minute` integer, nullable: The cap actually ENFORCED for this key, matching the `X-RateLimit-Limit-Minute` header on the same response. null for the unlimited (enterprise) tier.
      - `per_day` integer, nullable: The cap actually ENFORCED for this key, matching the `X-RateLimit-Limit-Day` header on the same response; it includes any active volume grandfather, so it can exceed the plan's published figure. null for the unlimited (enterprise) tier.
    - `used_today` integer
    - `remaining_today` integer, nullable: `limits.per_day` minus `used_today`, i.e. computed against the enforced cap. null for the unlimited (enterprise) tier.
    - `window_reset` string, date-time: Next UTC midnight, when the daily bucket resets.
    - `minute` object
      - `used` integer
      - `limit` integer, nullable
      - `remaining` integer, nullable
      - `resets_at` string, date-time
    - `recent` object[]: Up to 7 rows, most recent day first. Empty without a Postgres pool.
      - `date` string
      - `requests` integer
      - `errors_4xx` integer
  - `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

- `401`: missing or invalid API key

---

[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)
