> ## Documentation Index
> Fetch the complete documentation index at: https://docs.routeur.app/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Prices are US dollars per contract that pays $1: 0.46 means 46 cents. Spread is the Yes ask plus the No ask minus $1. Liquidity grades are deep, tradeable and thin; lists hide thin markets unless include_thin=true. Relations are proven from contract terms, never inferred from wording; a lead marked informational is never executable. Every figure carries a graph_run; read /agents/reading-order first, then /concepts/relations and /concepts/liquidity.

# Rules

> Every version of a market's terms, the rulebooks above it, and the ledger of what changed and when.

A market is decided by its rules, and venues change them. Routeur keeps the rule text of every market version it has ever recorded, from the first day it was listed, along with the rulebooks that govern it from above: a Kalshi series' contract terms and settlement sources, a Kalshi event's settlement terms, a Polymarket market's resolution metadata. Every change is an entry in a ledger, with a diff, and a `rule_change` event on the live stream.

## Versions and the rules hash

Each market has a `rules_hash`: a hash over the terms that decide it, which the venue's listing carries. When any of those terms changes, the hash changes and Routeur records a new **contract version**. Relations are proven between contract versions, not markets, so a proof names the hashes it holds for (see [Proof trail](/concepts/proof-trail)).

A version records the rule text, title, outcome labels, event, structured strike, open and close times, game start and, on Polymarket, the outcome tokens. Two versions are compared field by field; the fields that differ are named in `changed_fields`:

| `changed_fields` entry                    | What differed                                           |
| ----------------------------------------- | ------------------------------------------------------- |
| `rules`                                   | The rule text. `diff` holds a unified diff.             |
| `title`, `yes_label`, `no_label`          | The market's title or outcome labels.                   |
| `event_id`                                | The market moved to another event.                      |
| `strike`                                  | The structured strike (floor, cap, type, custom terms). |
| `opens_at`, `closes_at`, `game_starts_at` | A time moved.                                           |
| `outcome_tokens`                          | Polymarket's outcome tokens changed.                    |

An empty `changed_fields` on a later version means the venue changed something the hash covers but none of the recorded fields show, such as an expiration or settlement timestamp; the `summary` says so.

## Rulebooks above markets

Some terms are not written on the market. Routeur records them as **rulebooks**, versioned by the hash of their settlement fields alone, so a rulebook version changes only when the terms do and not when a title or artwork does:

| Venue      | `kind`   | `id`                                            | Fields recorded                                                                                           |
| ---------- | -------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| Kalshi     | `series` | Series ticker, such as `KXCPI`                  | `contract_terms_url`, `contract_url`, `settlement_sources`, `additional_prohibitions`, `product_metadata` |
| Kalshi     | `event`  | Event ticker, such as `KXECONSTATCPICORE-26NOV` | `settlement_sources`, `mutually_exclusive`, `strike_date`, `strike_period`, `collateral_return_type`      |
| Polymarket | `market` | Market slug                                     | `resolutionSource`, `umaResolutionStatuses`, `negRisk`, `negRiskMarketID`, `negRiskOther`                 |

Every rulebook version carries the venue's fields verbatim in `fields`, the `settlement_sources` read from them (name and link), and a `source_url`: the venue's own page or document for these terms, kept only when it is an absolute `https` link.

A Kalshi series rulebook names a **contract terms document**, the PDF Kalshi publishes on its own asset host. A separate job fetches each document at most once a day, extracts its text and stores each distinct content once, so `document` on a series version carries the text in force for that version, its `content_hash`, when it was fetched, the last fetch error if any, and a `diff` from the previous version's text. Only PDFs on `assets.kalshi.com` are fetched.

Each contract version is linked to the rulebook versions that were in force while it was seen, so a market's rules can be read as they stood for any version.

## The change ledger

Every change to a market's terms is one ledger entry, with a `scope`:

| `scope`                     | What changed                                                                             | `from_hash` → `to_hash`  |
| --------------------------- | ---------------------------------------------------------------------------------------- | ------------------------ |
| `contract`                  | A new contract version replaced the previous one.                                        | Rules hashes.            |
| `series`, `event`, `market` | A rulebook of that kind changed under an **unchanged** contract; `rulebook_id` names it. | Rulebook content hashes. |
| `document`                  | The venue's contract terms document changed under an unchanged series version.           | Document content hashes. |

Each entry has `changed_at`, `changed_fields` and a one-sentence `summary` in plain words, such as `Close time moved from 2026-09-17T19:00:00Z to 2026-09-17T20:20:00Z; game start moved from 2026-09-17T13:00:00Z to 2026-09-17T14:20:00Z.` The same change seen again is not recorded twice.

When a rulebook changes at the same moment as the contract itself, the ledger has one `contract` entry and the version lists the rulebook under `rulebooks_changed`, with the hash it replaced; there is no separate rulebook entry, because the rulebook did not change under an unchanged contract.

Every ledger entry is also a `rule_change` event on the `rules` topic of [`/v1/stream`](/concepts/live-stream), with the same fields plus `venue`, `market_id`, `title` and `rules_path`, the endpoint to read the versions and diffs from.

## A market's rules

```bash theme={null}
curl "https://api.routeur.app/v1/markets/polymarket/cs2-b8-gl1-2026-09-17/rules" \
  -H "X-API-Key: $ROUTEUR_API_KEY"
```

Works for any market ever recorded, listed or not. `404 market_not_found` means no contract terms were ever recorded for it.

```json theme={null}
{
  "data": {
    "venue": "polymarket",
    "id": "cs2-b8-gl1-2026-09-17",
    "title": "Counter-Strike: B8 vs GamerLegion (BO1) - Logitech G Play Connect Group A",
    "rules_hash": "6384d3d93cfc9ee19ce213cd7b4c97e1fdcf14c0a5cb5318322e9e9062ca6460",
    "rules": "...",
    "rulebooks": [
      {
        "venue": "polymarket",
        "kind": "market",
        "id": "cs2-b8-gl1-2026-09-17",
        "content_hash": "cdbd53f1af946bec57f7875fb9db386f1687f6acd11e18e01027c4252a900fcb",
        "fields": { "negRisk": false, "negRiskOther": false, "resolutionSource": "https://hltv.org", "umaResolutionStatuses": "[\"proposed\", \"proposed\"]" },
        "settlement_sources": [ { "name": "https://hltv.org", "url": "https://hltv.org" } ],
        "source_url": "https://hltv.org",
        "changed_fields": ["umaResolutionStatuses"],
        "diff": "--- market@02501acd502a\n+++ market@cdbd53f1af94\n@@ -2,5 +2,5 @@\n   \"negRisk\": false,\n   \"negRiskOther\": false,\n   \"resolutionSource\": \"https://hltv.org\",\n-  \"umaResolutionStatuses\": \"[]\"\n+  \"umaResolutionStatuses\": \"[\\\"proposed\\\", \\\"proposed\\\"]\"\n }\n"
      }
    ],
    "versions": [
      { "rules_hash": "8a9cf6a8060a…", "first_seen_at": "2026-09-14T17:32:43.135792Z", "last_seen_at": "2026-09-17T09:33:15.854116Z", "changed_fields": [], "rulebooks_changed": [] },
      { "rules_hash": "4c61f7348bab…", "first_seen_at": "2026-09-17T10:03:11.499751Z", "last_seen_at": "2026-09-17T10:33:05.32337Z",
        "changed_fields": ["closes_at", "game_starts_at"],
        "summary": "Close time moved from 2026-09-17T16:00:00Z to 2026-09-17T16:30:00Z; game start moved from 2026-09-17T10:00:00Z to 2026-09-17T10:30:00Z.",
        "rulebooks_changed": [] },
      { "rules_hash": "7f3fd322e34d…", "first_seen_at": "2026-09-17T11:03:43.628506Z", "last_seen_at": "2026-09-17T12:03:36.748379Z",
        "changed_fields": ["game_starts_at"],
        "summary": "Game start moved from 2026-09-17T10:30:00Z to 2026-09-17T10:50:00Z.",
        "rulebooks_changed": [ { "kind": "market", "id": "cs2-b8-gl1-2026-09-17", "content_hash": "02501acd502a…" } ] },
      { "rules_hash": "6384d3d93cfc…", "first_seen_at": "2026-09-17T12:33:34.741235Z", "last_seen_at": "2026-09-17T12:33:34.741235Z",
        "changed_fields": [],
        "summary": "The venue changed a term the recorded fields do not show, such as an expiration or settlement timestamp.",
        "rulebooks_changed": [ { "kind": "market", "id": "cs2-b8-gl1-2026-09-17", "content_hash": "cdbd53f1af94…", "from_hash": "02501acd502a…" } ] }
    ],
    "changes": [
      { "scope": "contract", "from_hash": "4c61f7348bab…", "to_hash": "7f3fd322e34d…", "changed_at": "2026-09-17T11:03:43.628506Z", "changed_fields": ["game_starts_at"], "summary": "Game start moved from 2026-09-17T10:30:00Z to 2026-09-17T10:50:00Z." },
      { "scope": "contract", "from_hash": "7f3fd322e34d…", "to_hash": "6384d3d93cfc…", "changed_at": "2026-09-17T12:33:34.741235Z", "changed_fields": [], "summary": "The venue changed a term the recorded fields do not show, such as an expiration or settlement timestamp." }
    ]
  }
}
```

Four versions in three days: the venue moved the match twice, then changed a term the recorded fields do not show at the same moment its resolution metadata moved from no UMA status to `proposed`. That rulebook change rides on the contract version's `rulebooks_changed` rather than getting its own ledger entry, because the contract changed with it. Hashes are shortened here; the API returns them in full.

| Field                 | Meaning                                                                                                                                                                                                                                                  |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `rules_hash`, `rules` | The current version and its rule text. The current version is the one seen last.                                                                                                                                                                         |
| `rulebooks`           | The rulebook versions in force for the current contract version, one per rulebook, each with its `fields`, `settlement_sources`, `source_url`, `document` (Kalshi series only) and its own `changed_fields` and `diff` from the rulebook version before. |
| `versions`            | Every contract version, oldest first: hash, when it was first and last seen, `changed_fields`, `summary` and `diff` from the version before, and `rulebooks_changed`.                                                                                    |
| `changes`             | The ledger, oldest first.                                                                                                                                                                                                                                |

<Tip>
  To know whether a market's terms changed since you took a position, compare the `rules_hash` you traded on with the current one, then read `changes` after your trade's time. A `rule_change` stream event does the same without polling.
</Tip>

## A rulebook's versions

```bash theme={null}
curl "https://api.routeur.app/v1/rulebooks/kalshi/event/KXECONSTATCPICORE-26NOV" \
  -H "X-API-Key: $ROUTEUR_API_KEY"
```

`kind` is `series` or `event` on Kalshi and `market` on Polymarket. The response lists every recorded version, oldest first, and `markets`, how many markets were ever recorded under the rulebook. `404 rulebook_not_found` means none has been recorded under that venue, kind and id.

A Kalshi event rulebook as recorded (one version, fields trimmed):

```json theme={null}
{
  "data": {
    "venue": "kalshi",
    "kind": "event",
    "id": "KXECONSTATCPICORE-26NOV",
    "markets": 8,
    "versions": [
      {
        "content_hash": "5e4162745630…",
        "first_seen_at": "2026-09-17T11:01:42.55787Z",
        "fields": {
          "mutually_exclusive": true,
          "strike_period": "",
          "settlement_sources": [
            { "name": "Bureau of Labor Statistics- Consumer Price Index", "url": "https://www.bls.gov/news.release/cpi.nr0.htm" },
            { "name": "Bureau of Labor Statistics- Employment Situation", "url": "https://www.bls.gov/news.release/empsit.nr0.htm" }
          ]
        },
        "settlement_sources": [
          { "name": "Bureau of Labor Statistics- Consumer Price Index", "url": "https://www.bls.gov/news.release/cpi.nr0.htm" },
          { "name": "Bureau of Labor Statistics- Employment Situation", "url": "https://www.bls.gov/news.release/empsit.nr0.htm" }
        ],
        "changed_fields": []
      }
    ]
  }
}
```

A Kalshi series version adds `source_url` (the contract terms PDF) and `document` with the PDF's extracted `text`, `content_hash`, `fetched_at` and, from the second version on, a `diff` of the text. When the last fetch failed, `document.error` says why and `text` is the last content fetched successfully, if any.

## What is not there yet

* **Clause extraction.** The rule text is stored and diffed as text. Settlement sources are read from structured fields, not from the prose, and no clause (settlement time, tie rule, cancellation policy) is extracted as a field yet.
* **Pair comparison.** A proof says why two markets are related from their structured terms; there is no side-by-side comparison of two markets' rule texts yet. Both are planned.

## Related

* [Proof trail](/concepts/proof-trail): how a relation names the contract versions it holds for.
* [Live stream](/concepts/live-stream): the `rules` topic and `rule_change` events.
* [Events and markets](/concepts/events-and-markets): where `rules_hash` and the structured strike appear on every market.
