{
  "info": {
    "name": "OddsRelay API 2026-07-08",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "description": "Generated from https://api.oddsrelay.io/v2/openapi.json. Set ODDSRELAY_KEY to your key."
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{ODDSRELAY_KEY}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api.oddsrelay.io"
    },
    {
      "key": "ODDSRELAY_KEY",
      "value": ""
    }
  ],
  "item": [
    {
      "name": "Odds",
      "description": "Matched boards, raw, one event.",
      "item": [
        {
          "name": "A matched board",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept-Encoding",
                "value": "gzip"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v2/odds/:type",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v2",
                "odds",
                ":type"
              ],
              "query": [
                {
                  "key": "region",
                  "value": "uk",
                  "description": "ONE lowercase region code (`/v2/regions` lists yours). Missing means `uk`: on a data route only when your key covers `uk`, else 400 `region_required` naming a code your key has; on discovery and keyless routes always. A comma list, the parameter sent twice or an uppercase code is 400 `bad_request`; an unknown code, or one with no live bookmaker here, is 404 `unknown_region`.",
                  "disabled": false
                },
                {
                  "key": "format",
                  "value": "envelope",
                  "description": "`envelope` (default): `{meta, data}`. `bare`: the `data` array alone, `meta` moved to `X-*` headers.",
                  "disabled": true
                },
                {
                  "key": "oddsFormat",
                  "value": "decimal",
                  "description": "`decimal` (default) or `american` (a signed integer; null for a price at or below 1.0). `standard` and `dutching` serve decimal only: anything else is 400.",
                  "disabled": true
                },
                {
                  "key": "dateFormat",
                  "value": "iso",
                  "description": "`iso` (default, ISO-8601 UTC) or `unix` (integer epoch seconds) for `commence_time`, `processed_at` and `last_update`. `standard` and `dutching` serve iso only: anything else is 400.",
                  "disabled": true
                },
                {
                  "key": "quote",
                  "value": "true",
                  "description": "`true` (also `1`, `yes`, `on`): price this exact request instead of serving it. 200 `{cost, remaining, rate_card}`, free, every check before the price still applies; any other value is an ordinary request.",
                  "disabled": true
                },
                {
                  "key": "sports",
                  "value": "tennis",
                  "description": "Comma-separated, at most 20: a sport key or a prefix of one as `/v2/sports` lists them (`soccer`, `soccer_epl`), lowercased. Unknown is 400 `unknown_sport` with `valid` (the sport key bases). A known value with nothing on the board is an empty 200, free.",
                  "disabled": true
                },
                {
                  "key": "bookmakers",
                  "value": "william_hill",
                  "description": "Comma-separated, at most 40: bookmaker keys as `/v2/bookmakers` lists them (a listed name is accepted too). Unknown is 400 `unknown_bookmaker` with `valid`; an exchange here is that 400 naming `exchanges` (on `dutching` both lists take venues of either kind); a venue outside the region is 403 `bookmaker_not_in_region`; one outside your plan's bookmaker list is 403 `bookmaker_not_in_plan` with `valid`. A plan with a bookmaker list trims a call naming none to that list.",
                  "disabled": true
                },
                {
                  "key": "exchanges",
                  "value": "betfair_exchange",
                  "description": "Comma-separated, at most 4: exchange keys as `/v2/bookmakers` lists them. Unknown is 400 `unknown_exchange` with `valid`; a bookmaker here is that 400 naming `bookmakers`.",
                  "disabled": true
                },
                {
                  "key": "markets",
                  "value": "h2h",
                  "description": "Comma-separated, at most 20: market keys (`h2h`, `totals`, …; `/v2/sports` rows list the keys seen under each competition). Unknown is 400 `unknown_market` with `valid`.",
                  "disabled": true
                },
                {
                  "key": "commenceTimeFrom",
                  "value": "2026-09-17T12:00:00Z",
                  "description": "Events kicking off at or after this ISO-8601 instant (no offset = UTC; a fraction of a second rounds up). Not ISO-8601 is 400; on the matched boards a From after To is 400.",
                  "disabled": true
                },
                {
                  "key": "commenceTimeTo",
                  "value": "2026-09-17T23:59:59Z",
                  "description": "Events kicking off at or before this ISO-8601 instant (no offset = UTC).",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "type",
                  "value": "standard",
                  "description": "A matched board: `standard`, `2up`, `dutching`, `each-way`, `extra-place` or `bog`. The aliases `two-up`, `each_way` and `extra_place` are accepted and served as their canonical slug. Anything else is 404 `unknown_type`."
                }
              ]
            },
            "description": "The six matched boards: each event's bookmaker back prices beside the exchanges' lay prices (`dutching`: back legs that cover every outcome, grouped by `dutch_id`; `each-way` and `extra-place`: each-way terms against win and place lays).\n\n**Checks, in this order** (each refusal is free): the per-address shield, the key, the account's flood cap, a suspended account, a browser key's website, the API version; then `type` (404 `unknown_type`), `region`, the region in the key (403 `region_not_in_scope`), the product in the key (403 `not_in_key_scope`), the product in the region (403 `product_not_in_region`: a region with no exchange serves only dutching and raw); then the parameters: each one this route reads, once; `format`, `oddsFormat` and `dateFormat` values; on `standard` and `dutching` decimal ISO only and gzip accepted (400 `add Accept-Encoding: gzip; with curl use --compressed`); then the filters, then `quote=true`, the price (402), and the board (503 while it is not ready).\n\n**Filters** cut the whole board's events in order: sport and kick-off, then markets, then back offers by bookmaker and lay offers by exchange; an outcome left with no back or no lay goes, then empty markets and events. `dutching` keeps a dutch only when every leg is a named venue. A filtered reply is priced on its filters (`/v2/pricing`); the kick-off window is never priced.\n\n**Freshness**: `meta.processed_at` and `X-Processed-At` are the board time; `meta.last_seen` is each venue and sport's last read. The API drops no row for age; a venue not read within its own window (at most two minutes) is off the board until its next read.\n\n**Conditional requests**: send the `ETag` back as `If-None-Match`; an unchanged body is a 304 with no body, free. A reply with no events is free."
          }
        },
        {
          "name": "The raw board, paged",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept-Encoding",
                "value": "gzip"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v2/odds/raw",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v2",
                "odds",
                "raw"
              ],
              "query": [
                {
                  "key": "region",
                  "value": "uk",
                  "description": "ONE lowercase region code (`/v2/regions` lists yours). Missing means `uk`: on a data route only when your key covers `uk`, else 400 `region_required` naming a code your key has; on discovery and keyless routes always. A comma list, the parameter sent twice or an uppercase code is 400 `bad_request`; an unknown code, or one with no live bookmaker here, is 404 `unknown_region`.",
                  "disabled": false
                },
                {
                  "key": "format",
                  "value": "envelope",
                  "description": "`envelope` (default): `{meta, data}`. `bare`: the `data` array alone, `meta` moved to `X-*` headers.",
                  "disabled": true
                },
                {
                  "key": "oddsFormat",
                  "value": "decimal",
                  "description": "`decimal` (default) or `american` (a signed integer; null for a price at or below 1.0). `standard` and `dutching` serve decimal only: anything else is 400.",
                  "disabled": true
                },
                {
                  "key": "dateFormat",
                  "value": "iso",
                  "description": "`iso` (default, ISO-8601 UTC) or `unix` (integer epoch seconds) for `commence_time`, `processed_at` and `last_update`. `standard` and `dutching` serve iso only: anything else is 400.",
                  "disabled": true
                },
                {
                  "key": "sports",
                  "value": "tennis",
                  "description": "Comma-separated, at most 20: a sport key, a prefix of one, or a sport name raw serves, lowercased. Unknown is 400 `unknown_sport` with `valid`.",
                  "disabled": true
                },
                {
                  "key": "sport",
                  "value": "",
                  "description": "The same as `sports` (what `/v2/events` takes); ignored when `sports` is sent.",
                  "disabled": true
                },
                {
                  "key": "leagues",
                  "value": "",
                  "description": "Comma-separated, at most 40: competition names (an event's league or `sport_title`), lowercased. Not checked against a catalogue.",
                  "disabled": true
                },
                {
                  "key": "bookmakers",
                  "value": "betfair_exchange",
                  "description": "Comma-separated, at most 40: venue keys of either kind, bookmakers and exchanges, as `/v2/bookmakers` lists them. Unknown is 400 `unknown_bookmaker` with `valid`; outside the region 403 `bookmaker_not_in_region`; outside your plan's bookmaker list 403 `bookmaker_not_in_plan`.",
                  "disabled": true
                },
                {
                  "key": "requireBookmakers",
                  "value": "sky_bet,paddy_power,william_hill,ladbrokes,betfred,bet365",
                  "description": "Comma-separated, at most 40 venue keys, checked as `bookmakers` is (the same 400 and 403 codes). Keeps only the events where EVERY named venue quotes the call's `markets` (with several, at least one of them each), under `exchangesOnly` if set; a venue that lists the event but not the market does not count. `bookmakers` does not narrow this test and `updatedSince` is not part of it: with `updatedSince`, an event carrying every named venue is kept when any venue shown changed, and the page shows only the venues that changed. It narrows events, never venues: every venue the other filters keep is still shown, named or not. `meta.total` and `X-Count` count the events kept. Price: like `eventIds`, it narrows the page and not the query, so a page pays its share of the same call without `requireBookmakers`, and an empty page is free.",
                  "disabled": true
                },
                {
                  "key": "markets",
                  "value": "h2h",
                  "description": "Comma-separated, at most 20: market keys raw serves. Unknown is 400 `unknown_market` with `valid`. Keeps venues quoting one of them, and only those markets.",
                  "disabled": true
                },
                {
                  "key": "eventIds",
                  "value": "",
                  "description": "Comma-separated, at most 50 event ids. Narrows the page, not the query: a page pays its share of the same call without `eventIds`.",
                  "disabled": true
                },
                {
                  "key": "commenceTimeFrom",
                  "value": "2026-09-17T12:00:00Z",
                  "description": "Events kicking off at or after this ISO-8601 instant (no offset = UTC; a fraction of a second rounds up). Not ISO-8601 is 400; on the matched boards a From after To is 400.",
                  "disabled": true
                },
                {
                  "key": "commenceTimeTo",
                  "value": "2026-09-17T23:59:59Z",
                  "description": "Events kicking off at or before this ISO-8601 instant (no offset = UTC).",
                  "disabled": true
                },
                {
                  "key": "updatedSince",
                  "value": "2026-09-17T02:20:00Z",
                  "description": "Exactly `YYYY-MM-DDTHH:MM:SSZ` (any other form is 400). Keeps venues whose `last_update` is at or after it, and the events holding one. The bulk way to follow raw: a recent `updatedSince` pays a reduced share (`/v2/pricing` `recent`).",
                  "disabled": true
                },
                {
                  "key": "exchangesOnly",
                  "value": "",
                  "description": "`true`: exchanges only. `true` or `false`, else 400.",
                  "disabled": true
                },
                {
                  "key": "includeLinks",
                  "value": "false",
                  "description": "`true`: each venue's `link` (its primary event page; left out when it has none). Default `false`. `true` or `false`, else 400.",
                  "disabled": true
                },
                {
                  "key": "includeLiquidity",
                  "value": "true",
                  "description": "`false`: leave out `available` beside an exchange's `lay_price`. Default `true`. `true` or `false`, else 400.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "The previous page's `meta.next_cursor` (or `X-Next-Cursor`). A cursor is bound to no account and expires 300 s after it was issued: 400 `cursor expired: start again from the first page`; any other shape 400 `cursor not recognised: start again from the first page`.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "",
                  "description": "Events per page, 1-250 (default and maximum 250). Anything else is 400.",
                  "disabled": true
                },
                {
                  "key": "quote",
                  "value": "true",
                  "description": "`true` (also `1`, `yes`, `on`): price this exact request instead of serving it. 200 `{cost, remaining, rate_card}`, free, every check before the price still applies; any other value is an ordinary request.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "description": "Every venue's prices per event, one page at a time: bookmakers as `{name, price}`, exchanges quoting a lay side as `{name, back_price, lay_price, available}`. Served gzip only: a request refusing gzip is 400 `add Accept-Encoding: gzip; with curl use --compressed`.\n\n**Checks, in this order**: the per-address shield, the key, the flood cap, a suspended account, a browser key's website, the API version; `region`, the region and `raw` in the key; the parameters (each one this route reads, once) and their values; the filters (400 unknown values, 403 `bookmaker_not_in_region`, 403 `bookmaker_not_in_plan`); `includeLinks` and `includeLiquidity`; `limit`; `cursor`; gzip; the raw board (503 `raw_not_enabled`); the page (503 while it cannot be cut); `quote=true`; the price (402).\n\n**Paging**: pages are ordered by (kick-off, event id) and a cursor resumes strictly after the last event it saw, so an event that leaves the board between pages never restarts the walk. The accepted limit: an event whose kick-off moves across the cursor during a walk can appear twice or be missed. Dedupe by event `id`, and take a missed event on the next walk. A cursor expires 300 s after it was issued.\n\n**Following changes**: walk with `updatedSince` set to the start of your previous walk; `last_update` is when a venue's market last moved (see the schema for what it is not).\n\n**Price**: a page pays its share of the query's price (its prices over all the query's events' prices, at least 1; `eventIds` and `requireBookmakers` narrow the page, never the query), so a whole walk pays the query's price (narrowed by `eventIds` or `requireBookmakers`, only its kept events' share of it); a recent `updatedSince` pays a reduced share. `quote=true` prices this page."
          }
        },
        {
          "name": "One event from the raw board",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept-Encoding",
                "value": "gzip"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v2/odds/event/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v2",
                "odds",
                "event",
                ":id"
              ],
              "query": [
                {
                  "key": "region",
                  "value": "uk",
                  "description": "ONE lowercase region code (`/v2/regions` lists yours). Missing means `uk`: on a data route only when your key covers `uk`, else 400 `region_required` naming a code your key has; on discovery and keyless routes always. A comma list, the parameter sent twice or an uppercase code is 400 `bad_request`; an unknown code, or one with no live bookmaker here, is 404 `unknown_region`.",
                  "disabled": false
                },
                {
                  "key": "oddsFormat",
                  "value": "decimal",
                  "description": "`decimal` (default) or `american` (a signed integer; null for a price at or below 1.0). `standard` and `dutching` serve decimal only: anything else is 400.",
                  "disabled": true
                },
                {
                  "key": "dateFormat",
                  "value": "iso",
                  "description": "`iso` (default, ISO-8601 UTC) or `unix` (integer epoch seconds) for `commence_time`, `processed_at` and `last_update`. `standard` and `dutching` serve iso only: anything else is 400.",
                  "disabled": true
                },
                {
                  "key": "includeLinks",
                  "value": "false",
                  "description": "`true`: each venue's `link` (its primary event page; left out when it has none). Default `false`. `true` or `false`, else 400.",
                  "disabled": true
                },
                {
                  "key": "includeLiquidity",
                  "value": "true",
                  "description": "`false`: leave out `available` beside an exchange's `lay_price`. Default `true`. `true` or `false`, else 400.",
                  "disabled": true
                },
                {
                  "key": "quote",
                  "value": "true",
                  "description": "`true` (also `1`, `yes`, `on`): price this exact request instead of serving it. 200 `{cost, remaining, rate_card}`, free, every check before the price still applies; any other value is an ordinary request.",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "or_evt_da71d5873e85",
                  "description": "An event id (`or_evt_…`) from raw, a matched board or `/v2/events`. Not on the raw board now is 404 `unknown_event`."
                }
              ]
            },
            "description": "One raw event by id, every venue (a plan with a bookmaker list sees those venues and the region's exchanges). Checks: the key and scope as raw, the parameters and their values, the raw board (503 `raw_not_enabled`), the id (404 `unknown_event`), `quote=true`, the price (402). Priced by the event's share of the region's raw prices. Gzip unless refused (over 1 kB)."
          }
        }
      ]
    },
    {
      "name": "Discovery",
      "description": "Sports, events, venues, regions. Free.",
      "item": [
        {
          "name": "Sports and competitions",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept-Encoding",
                "value": "gzip"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v2/sports",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v2",
                "sports"
              ],
              "query": [
                {
                  "key": "region",
                  "value": "uk",
                  "description": "ONE lowercase region code (`/v2/regions` lists yours). Missing means `uk`: on a data route only when your key covers `uk`, else 400 `region_required` naming a code your key has; on discovery and keyless routes always. A comma list, the parameter sent twice or an uppercase code is 400 `bad_request`; an unknown code, or one with no live bookmaker here, is 404 `unknown_region`.",
                  "disabled": false
                },
                {
                  "key": "format",
                  "value": "envelope",
                  "description": "`envelope` (default): `{meta, data}`. `bare`: the `data` array alone, `meta` moved to `X-*` headers.",
                  "disabled": true
                },
                {
                  "key": "dateFormat",
                  "value": "iso",
                  "description": "`iso` (default, ISO-8601 UTC) or `unix` (integer epoch seconds) for `commence_time`, `processed_at` and `last_update`. `standard` and `dutching` serve iso only: anything else is 400.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "The previous page's `meta.next_cursor` (or `X-Next-Cursor`). A cursor is bound to no account and expires 300 s after it was issued: 400 `cursor expired: start again from the first page`; any other shape 400 `cursor not recognised: start again from the first page`.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "description": "Every competition on the matched boards, grouped, with the market keys seen under each. Free. Paged 250 rows at a time in (group, key) order; a cursor expires 300 s after it was issued. `region` missing means `uk`; discovery is not scoped to your key's regions."
          }
        },
        {
          "name": "Events of a sport",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept-Encoding",
                "value": "gzip"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v2/events",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v2",
                "events"
              ],
              "query": [
                {
                  "key": "region",
                  "value": "uk",
                  "description": "ONE lowercase region code (`/v2/regions` lists yours). Missing means `uk`: on a data route only when your key covers `uk`, else 400 `region_required` naming a code your key has; on discovery and keyless routes always. A comma list, the parameter sent twice or an uppercase code is 400 `bad_request`; an unknown code, or one with no live bookmaker here, is 404 `unknown_region`.",
                  "disabled": false
                },
                {
                  "key": "format",
                  "value": "envelope",
                  "description": "`envelope` (default): `{meta, data}`. `bare`: the `data` array alone, `meta` moved to `X-*` headers.",
                  "disabled": true
                },
                {
                  "key": "dateFormat",
                  "value": "iso",
                  "description": "`iso` (default, ISO-8601 UTC) or `unix` (integer epoch seconds) for `commence_time`, `processed_at` and `last_update`. `standard` and `dutching` serve iso only: anything else is 400.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "The previous page's `meta.next_cursor` (or `X-Next-Cursor`). A cursor is bound to no account and expires 300 s after it was issued: 400 `cursor expired: start again from the first page`; any other shape 400 `cursor not recognised: start again from the first page`.",
                  "disabled": true
                },
                {
                  "key": "sport",
                  "value": "tennis",
                  "description": "Required: a sport key or a prefix of one as `/v2/sports` lists them. Missing is 400 `missing_param`; unknown 400 `unknown_sport` with `valid`.",
                  "disabled": false
                },
                {
                  "key": "eventIds",
                  "value": "",
                  "description": "Comma-separated, at most 50 event ids.",
                  "disabled": true
                },
                {
                  "key": "commenceTimeFrom",
                  "value": "2026-09-17T12:00:00Z",
                  "description": "Events kicking off at or after this ISO-8601 instant (no offset = UTC; a fraction of a second rounds up). Not ISO-8601 is 400; on the matched boards a From after To is 400.",
                  "disabled": true
                },
                {
                  "key": "commenceTimeTo",
                  "value": "2026-09-17T23:59:59Z",
                  "description": "Events kicking off at or before this ISO-8601 instant (no offset = UTC).",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "description": "The events on the matched boards under one sport key or prefix, with the boards carrying each. Free. Paged 250 at a time in (kick-off, id) order; a cursor resumes strictly after the last event it saw, so an event whose kick-off moves across the cursor during a walk can appear twice or be missed: dedupe by `id` and take a missed event on the next walk. A cursor expires 300 s after it was issued. `region` missing means `uk`."
          }
        },
        {
          "name": "Venues",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept-Encoding",
                "value": "gzip"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v2/bookmakers",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v2",
                "bookmakers"
              ],
              "query": [
                {
                  "key": "format",
                  "value": "envelope",
                  "description": "`envelope` (default): `{meta, data}`. `bare`: the `data` array alone, `meta` moved to `X-*` headers.",
                  "disabled": true
                }
              ],
              "variable": []
            },
            "description": "Every bookmaker and exchange key the API serves, with its display name, regions and kind. Free. Takes no `region`: a `region` parameter is 400."
          }
        },
        {
          "name": "Your regions",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept-Encoding",
                "value": "gzip"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v2/regions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v2",
                "regions"
              ],
              "query": [],
              "variable": []
            },
            "description": "The regions your key covers that have live bookmakers here, with each region's exchanges and coverage model. Free."
          }
        }
      ]
    },
    {
      "name": "Service",
      "description": "Coverage, status, health, liveness and this document.",
      "item": [
        {
          "name": "Coverage per venue and sport",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept-Encoding",
                "value": "gzip"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v2/coverage",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v2",
                "coverage"
              ],
              "query": [
                {
                  "key": "region",
                  "value": "uk",
                  "description": "ONE lowercase region code (`/v2/regions` lists yours). Missing means `uk`: on a data route only when your key covers `uk`, else 400 `region_required` naming a code your key has; on discovery and keyless routes always. A comma list, the parameter sent twice or an uppercase code is 400 `bad_request`; an unknown code, or one with no live bookmaker here, is 404 `unknown_region`.",
                  "disabled": false
                }
              ],
              "variable": []
            },
            "description": "One document per region, in two views. **Keyless** (no `Authorization` and no `x-api-key` header): per product, each (venue, sport) `live` or `interrupted_24h`, no counts and no times; the per-address shield only; `Cache-Control: public, max-age=60` and `Vary: Authorization, X-Api-Key, Accept-Encoding` on a 200; `Access-Control-Allow-Origin: *` on every reply, refusals and errors included. **Keyed** (either header present, even empty: an invalid key is 401): your key's products the region serves, venues with rows now, their `events` and `last_seen`; free; the flood cap applies. Both: `region` missing means `uk`, gzip over 1 kB unless refused, 503 until the first document is built."
          }
        },
        {
          "name": "Product status, keyless",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept-Encoding",
                "value": "gzip"
              }
            ],
            "auth": {
              "type": "noauth"
            },
            "url": {
              "raw": "{{baseUrl}}/v2/status",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v2",
                "status"
              ],
              "query": [
                {
                  "key": "region",
                  "value": "uk",
                  "description": "ONE lowercase region code (`/v2/regions` lists yours). Missing means `uk`: on a data route only when your key covers `uk`, else 400 `region_required` naming a code your key has; on discovery and keyless routes always. A comma list, the parameter sent twice or an uppercase code is 400 `bad_request`; an unknown code, or one with no live bookmaker here, is 404 `unknown_region`.",
                  "disabled": false
                }
              ],
              "variable": []
            },
            "description": "Per product the region serves: `ok`, `slow` or `stale`, judged on each board's odds age (not servable or not held is `stale`). While boards warm every product reads `stale` in a 200. KEYLESS: the per-address shield only, a key header is ignored, no token is spent. `Cache-Control: public, max-age=10` on a 200; `Access-Control-Allow-Origin: *` on every reply, refusals and errors included. Plain JSON (never gzip)."
          }
        },
        {
          "name": "Board freshness",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept-Encoding",
                "value": "gzip"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v2/health",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v2",
                "health"
              ],
              "query": [],
              "variable": []
            },
            "description": "Each board's `processed_at`, odds age (`age_s`) and event `count`, and a verdict: `degraded` when a board is past the age bound or cannot be served. Always HTTP 200 whatever the verdict. Free. Plain JSON."
          }
        },
        {
          "name": "This document, keyless",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept-Encoding",
                "value": "gzip"
              }
            ],
            "auth": {
              "type": "noauth"
            },
            "url": {
              "raw": "{{baseUrl}}/v2/openapi.json",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v2",
                "openapi.json"
              ],
              "query": [],
              "variable": []
            },
            "description": "This OpenAPI document. KEYLESS: the per-address shield only, a key header is ignored, no token is spent. `ETag` is its SHA-256 (`-gz` on the gzip copy); 304 on a match; gzip unless refused; `Cache-Control: public, max-age=300`; `Access-Control-Allow-Origin: *` on every reply, refusals and errors included. Takes no parameters."
          }
        },
        {
          "name": "Liveness, keyless",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept-Encoding",
                "value": "gzip"
              }
            ],
            "auth": {
              "type": "noauth"
            },
            "url": {
              "raw": "{{baseUrl}}/healthz",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "healthz"
              ],
              "query": [],
              "variable": []
            },
            "description": "Is the service up. KEYLESS and before every other check. `text/plain`, `Cache-Control: no-store`: the first line is `ok` (200) or `warming` (503), then how many boards can be served and any that cannot. Liveness only: board freshness is `/v2/health` and `/v2/status`."
          }
        }
      ]
    },
    {
      "name": "Account",
      "description": "Usage and prices. Free.",
      "item": [
        {
          "name": "Your plan, balance, key and flood cap",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept-Encoding",
                "value": "gzip"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v2/usage",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v2",
                "usage"
              ],
              "query": [],
              "variable": []
            },
            "description": "Free, flood-capped, and answered for a SUSPENDED account too (it shows the reason). Plain JSON."
          }
        },
        {
          "name": "The price table",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept-Encoding",
                "value": "gzip"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v2/pricing",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v2",
                "pricing"
              ],
              "query": [],
              "variable": []
            },
            "description": "The price table every call is priced from, byte for byte. Free. `ETag` is its SHA-256 (`-gz` on the gzip copy); 304 on a match. Gzip unless refused."
          }
        }
      ]
    }
  ]
}