> ## 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.

# Read a proof trail

> Find a cross-venue pair, fetch the proof behind its relation, read the steps, and decide whether the lead on it is executable.

## What you'll get

A cross-venue pair from the latest graph run, the ordered proof steps that relate its two contracts, and a decision: whether the lead priced on that pair could be filled at a profit when the books were read. On 2026-09-17 the only liquid cross-venue lead was a Brewers–Pirates total (Kalshi ↔ Polymarket, equivalent), proven in four steps and not executable at the prices on offer.

## Prerequisites

* An API key in `ROUTEUR_API_KEY`
* Python 3 with `requests`

<Steps>
  <Step title="Find a cross-venue pair">
    Either start from the leads, which come with the depth check already done:

    ```bash theme={null}
    curl "https://api.routeur.app/v1/opportunities?cross_venue=true&limit=1" -H "X-API-Key: $ROUTEUR_API_KEY"
    ```

    ```json theme={null}
    {
      "relation": "equivalent", "cross_venue": true,
      "left":  { "venue": "kalshi", "id": "KXMLBTOTAL-26SEP171235MILPIT-9", "title": "Over 8.5 runs scored",
                 "quote": { "yes_ask_usd": "0.55", "no_ask_usd": "0.46" }, "volume_24h_usd": "16742.70", "liquidity": "tradeable" },
      "right": { "venue": "polymarket", "id": "mlb-mil-pit-2026-09-17-total-8pt5", "title": "Milwaukee Brewers vs. Pittsburgh Pirates: O/U 8.5",
                 "quote": { "yes_ask_usd": "0.56", "no_ask_usd": "0.45" }, "volume_24h_usd": "1874.10", "liquidity": "tradeable" },
      "legs": [ { "side": "yes", "venue": "kalshi", "ask_usd": "0.54", "market_id": "KXMLBTOTAL-26SEP171235MILPIT-9" },
                { "side": "no", "venue": "polymarket", "ask_usd": "0.45", "market_id": "mlb-mil-pit-2026-09-17-total-8pt5" } ],
      "cost_usd": "0.99", "gross_edge_usd": "0.01", "estimated_fee_usd": "0.032375", "net_edge_usd": "-0.022375",
      "issues": [ "unverified: top-of-book depth is unknown; asks are discovery observations",
                  "unverified: the covering payout assumes the event settles normally; postponement, cancellation and disputes settle differently across venues",
                  "unverified: legs settle in USD and USDC; conversion and transfer costs are not priced" ],
      "depth": { "executable": false, "pairs": "0", "cost_usd": "0", "fees_usd": "0", "net_usd": "0",
                 "limited_by": "price", "observed_at": "2026-09-17T12:10:12.831Z",
                 "issues": [ "stale: leg books were read 23s apart" ] }
    }
    ```

    Or start from a market you already care about and ask for its relations to the other venue. Cross-venue relations come first:

    ```bash theme={null}
    curl "https://api.routeur.app/v1/markets/kalshi/KXMLBTOTAL-26SEP171235MILPIT-9/relations?cross_venue=true" \
      -H "X-API-Key: $ROUTEUR_API_KEY"
    ```

    ```json theme={null}
    { "relation": "equivalent", "cross_venue": true,
      "evidence": ["cross-venue: same mlb game scheduled 2026-09-17 ET, matched by team codes and team names; both settle on the game's final score; neither venue restricts periods; postponement and cancellation settle differently"],
      "market": { "venue": "polymarket", "id": "mlb-mil-pit-2026-09-17-total-8pt5", "liquidity": "tradeable", "quote": { "yes_ask_usd": "0.56", "no_ask_usd": "0.45" } } }
    { "relation": "implied_by", "cross_venue": true, "market": { "venue": "polymarket", "id": "mlb-mil-pit-2026-09-17-total-10pt5", "liquidity": "thin" } }
    { "relation": "implied_by", "cross_venue": true, "market": { "venue": "polymarket", "id": "mlb-mil-pit-2026-09-17-total-9pt5", "liquidity": "thin" } }
    ```
  </Step>

  <Step title="Fetch the proof">
    Either market may be given first; the trail is stated from the left one's side.

    ```bash theme={null}
    curl "https://api.routeur.app/v1/relations/kalshi/KXMLBTOTAL-26SEP171235MILPIT-9/polymarket/mlb-mil-pit-2026-09-17-total-8pt5" \
      -H "X-API-Key: $ROUTEUR_API_KEY"
    ```

    The steps and provenance, observed 2026-09-17 12:40 UTC (both contracts' full terms are in `left` and `right`, left out here):

    ```json theme={null}
    {
      "graph_run": 74,
      "data": {
        "relation": "equivalent", "graph_relation": "equivalent", "direction": "both_ways", "cross_venue": true,
        "left":  { "venue": "kalshi", "id": "KXMLBTOTAL-26SEP171235MILPIT-9", "rules_hash": "73562783085732ec…",
                   "strike": { "type": "greater", "floor": "17/2" },
                   "variable": "MLB total, Milwaukee vs Pittsburgh, 2026-09-17 ET", "interval": "(8.5, ∞)",
                   "settlement": { "payout_currency": "USD", "scope": "the game's final score; neither venue restricts periods", "closes_at": "2026-09-20T16:35:00Z" } },
        "right": { "venue": "polymarket", "id": "mlb-mil-pit-2026-09-17-total-8pt5", "rules_hash": "0a6ca28b9b1edeea…",
                   "strike": { "type": "greater", "floor": "17/2" },
                   "variable": "MLB total, Milwaukee Brewers vs Pittsburgh Pirates, 2026-09-17 ET", "interval": "(8.5, ∞)",
                   "settlement": { "payout_currency": "USDC", "scope": "the game's final score; neither venue restricts periods", "game_starts_at": "2026-09-17T16:35:00Z" } },
        "steps": [
          { "step": "game_quantity", "left": "MLB total, Milwaukee vs Pittsburgh, 2026-09-17 ET", "right": "MLB total, Milwaukee Brewers vs Pittsburgh Pirates, 2026-09-17 ET", "result": "same_kind" },
          { "step": "same_game", "detail": "cross-venue: same mlb game scheduled 2026-09-17 ET, matched by team codes and team names; both settle on the game's final score; neither venue restricts periods; postponement and cancellation settle differently", "result": "same" },
          { "step": "intervals", "left": "(8.5, ∞)", "right": "(8.5, ∞)", "result": "equivalent" },
          { "step": "conclusion", "relation": "equivalent" }
        ],
        "reproduced": true,
        "found_by":     { "id": 65, "graph_version": "contract-graph/v1", "finished_at": "2026-09-17T03:10:57.298293Z" },
        "confirmed_by": { "id": 74, "graph_version": "contract-graph/v1", "finished_at": "2026-09-17T12:10:36.937979Z" },
        "first_seen_at": "2026-09-17T03:10:57.298293Z", "last_confirmed_at": "2026-09-17T12:10:36.937979Z"
      }
    }
    ```
  </Step>

  <Step title="Read the steps and decide">
    This script does all three: picks the first liquid cross-venue lead (or, when there is none, the first cross-venue relation of `VENUE`/`MARKET_ID`), prints the proof, and decides from `depth`.

    ```python Python theme={null}
    import os
    import sys
    import requests

    API = "https://api.routeur.app"
    session = requests.Session()
    session.headers["X-API-Key"] = os.environ["ROUTEUR_API_KEY"]


    def get(path, **params):
        res = session.get(f"{API}{path}", params=params, timeout=30)
        if res.status_code == 404:
            return None
        res.raise_for_status()
        return res.json()


    # 1. Find a cross-venue pair. Prefer a lead, because it comes with the depth check.
    lead = None
    leads = get("/v1/opportunities", cross_venue="true", limit=10)["data"]      # booleans go as lowercase text
    if leads:
        lead = leads[0]
        left, right = lead["left"], lead["right"]
    else:
        # No liquid cross-venue lead right now: take the first cross-venue relation of a market you name.
        venue, market_id = os.environ["VENUE"], os.environ["MARKET_ID"]
        relations = get(f"/v1/markets/{venue}/{market_id}/relations", cross_venue="true", limit=1)["data"]
        if not relations:
            sys.exit("That market has no proven relation to the other venue.")
        left = {"venue": venue, "id": market_id}
        right = relations[0]["market"]

    # 2. Fetch the proof.
    proof = get(f"/v1/relations/{left['venue']}/{left['id']}/{right['venue']}/{right['id']}")
    if proof is None:
        sys.exit("relation_not_found: the latest graph does not relate these contract versions any more.")
    p, run = proof["data"], proof["graph_run"]

    # 3. Read the steps.
    print(f"{p['left']['title']!r} on {p['left']['venue']}  is {p['relation']}  {p['right']['title']!r} on {p['right']['venue']}")
    print(f"direction {p['direction']} · found by run {p['found_by']['id']} · confirmed by run {p['confirmed_by']['id']} · reproduced: {p['reproduced']}")
    print(f"  left  reads {p['left'].get('variable')} in {p['left'].get('interval')}, pays in {p['left']['settlement'].get('payout_currency')}")
    print(f"  right reads {p['right'].get('variable')} in {p['right'].get('interval')}, pays in {p['right']['settlement'].get('payout_currency')}")
    for i, step in enumerate(p["steps"], 1):
        parts = [f"{i}. {step['step']}"]
        if step.get("left"):
            parts.append(f"left={step['left']}")
        if step.get("right"):
            parts.append(f"right={step['right']}")
        if step.get("result"):
            parts.append(f"→ {step['result']}")
        if step.get("relation"):
            parts.append(f"→ {step['relation']}")
        print("  " + "  ".join(parts))
        if step.get("detail"):
            print(f"       {step['detail']}")

    # 4. Decide whether it is executable.
    if lead is None:
        print("\nNo lead is priced on this pair right now, so there is nothing to size.")
    else:
        depth = lead.get("depth")
        print(f"\nLead: buy {lead['legs'][0]['side']} on {lead['legs'][0]['venue']} at {float(lead['legs'][0]['ask_usd']) * 100:.1f}¢ "
              f"+ {lead['legs'][1]['side']} on {lead['legs'][1]['venue']} at {float(lead['legs'][1]['ask_usd']) * 100:.1f}¢ "
              f"= {float(lead['cost_usd']) * 100:.1f}¢ for $1, net {float(lead['net_edge_usd']) * 100:+.1f}¢ after estimated fees (top of book)")
        if depth is None:
            print("Not sized against the books this run: treat as not executable.")
        elif depth["limited_by"] == "informational":
            print("Informational only: the venues could settle this differently, so it is never offered as executable.")
        elif depth["executable"]:
            print(f"Executable when the books were read at {depth['observed_at']}: {depth['pairs']} pairs for ${depth['cost_usd']}, "
                  f"${depth['net_usd']} net after ${depth['fees_usd']} fees; growth stopped by {depth['limited_by']}.")
        else:
            print(f"Not executable at {depth['observed_at']}: {depth['pairs']} pairs would fill, net ${depth['net_usd']}; stopped by {depth['limited_by']}.")
        if not p["reproduced"]:
            print("Warning: the proof no longer reproduces from the stored contracts. Do not trade on it.")
        for issue in lead.get("issues") or []:
            print(f"  caveat: {issue}")
    ```

    Output observed 2026-09-17 12:52 UTC:

    ```text theme={null}
    'Over 8.5 runs scored' on kalshi  is equivalent  'Milwaukee Brewers vs. Pittsburgh Pirates: O/U 8.5' on polymarket
    direction both_ways · found by run 65 · confirmed by run 74 · reproduced: True
      left  reads MLB total, Milwaukee vs Pittsburgh, 2026-09-17 ET in (8.5, ∞), pays in USD
      right reads MLB total, Milwaukee Brewers vs Pittsburgh Pirates, 2026-09-17 ET in (8.5, ∞), pays in USDC
      1. game_quantity  left=MLB total, Milwaukee vs Pittsburgh, 2026-09-17 ET  right=MLB total, Milwaukee Brewers vs Pittsburgh Pirates, 2026-09-17 ET  → same_kind
      2. same_game  → same
           cross-venue: same mlb game scheduled 2026-09-17 ET, matched by team codes and team names; both settle on the game's final score; neither venue restricts periods; postponement and cancellation settle differently
      3. intervals  left=(8.5, ∞)  right=(8.5, ∞)  → equivalent
      4. conclusion  → equivalent

    Lead: buy yes on kalshi at 54.0¢ + no on polymarket at 45.0¢ = 99.0¢ for $1, net -2.2¢ after estimated fees (top of book)
    Not executable at 2026-09-17T12:10:12.831Z: 0 pairs would fill, net $0; stopped by price.
      caveat: unverified: top-of-book depth is unknown; asks are discovery observations
      caveat: estimated: Kalshi standard 0.07 taker fee for one contract; series fee multipliers and rounding across quantities are not applied
      caveat: estimated: Polymarket taker fee rate * p * (1 - p) for one share, before rounding
      caveat: unverified: the covering payout assumes the event settles normally; postponement, cancellation and disputes settle differently across venues
      caveat: unverified: legs settle in USD and USDC; conversion and transfer costs are not priced
    ```

    The proof holds; the prices do not pay. Yes at 54¢ plus No at 45¢ is 99¢ for a guaranteed \$1, and 3.2¢ of estimated fees turn a 1¢ gross edge into a 2.2¢ loss.
  </Step>
</Steps>

## Read the result

| Field                            | Meaning                                                                                                                                                                                                                                                                                                                                                                               |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `relation`                       | From the left market's side: `equivalent`, `implies`, `implied_by`, `contradicts` or `overlaps`. `graph_relation` is the same fact in the graph's own terms (`subset`, `superset`).                                                                                                                                                                                                   |
| `direction`                      | Which way the implication runs: `both_ways` for equivalent, `left_implies_right`, `right_implies_left`, `mutually_exclusive`, or `neither`.                                                                                                                                                                                                                                           |
| `left.variable`, `left.interval` | What the proof read the contract as: the quantity it pays on, and the Yes range on it in interval notation over exact decimals. `(8.5, ∞)` is "more than 8.5".                                                                                                                                                                                                                        |
| `left.settlement`                | What settlement reads and what it pays in. `USD` on Kalshi, `USDC` on Polymarket.                                                                                                                                                                                                                                                                                                     |
| `left.rules_hash`                | The contract version the proof holds for. A rules change is a new version, and the proof must be found again.                                                                                                                                                                                                                                                                         |
| `steps[]`                        | The proof, in order. `game_quantity` and `econ_quantity` establish both contracts pay on the same kind of thing; `same_game`, `same_event` and `same_variable` that it is the same instance; `orient_margin` flips a margin stated from the other team's side; `intervals` compares the ranges; `mutually_exclusive` uses an event's one-winner rule; `conclusion` states the result. |
| `reproduced`                     | Rebuilding the graph from the stored contract versions still yields this relation. When `false`, the steps end with `not_reproduced` and the recorded conclusion.                                                                                                                                                                                                                     |
| `found_by`, `confirmed_by`       | The run that first proved it and the latest run that still lists both contract versions. Runs finish hourly.                                                                                                                                                                                                                                                                          |
| `depth` (on the lead)            | The lead sized against live books at `observed_at`: `executable` means at least one whole pair could be bought for less than it pays after fees and minimum sizes; `limited_by` names what stopped the fill growing: `price`, `depth`, `minimum`, `fees`, `unavailable` or `informational`.                                                                                           |
| `issues`                         | Caveats on the estimate. `unverified` ones are things the API cannot check; `estimated` ones are fee models; `stale` ones are timing.                                                                                                                                                                                                                                                 |

## Pitfalls

* **`limited_by: informational` is never executable**, however good the numbers look. It means the relation rests on a settlement the venues could resolve differently: economic releases that get delayed or cancelled. Treat it as a note about prices, not a trade.
* **A proof is per contract version.** When either venue edits its rules, the pair's `rules_hash` changes and the next run must prove it again. Until then `GET /v1/relations/…` returns `404 relation_not_found`: "the latest graph does not relate their current contract versions". A relation that was there an hour ago and is gone now is worth reading as a warning, not a bug. See [Rule-change watch](/cookbook/rule-change-watch).
* **`depth.observed_at` is the graph run's time, not now.** On 2026-09-17 it was 12:10 UTC for a request at 12:52. Books move; size again before you act, with [Slippage at size](/cookbook/slippage-at-size).
* **Postponement settles differently.** Every cross-venue evidence line says so. An equivalent pair is equivalent when the game is played; a rain-out can pay one leg and void the other.
* **`cross_venue=True` is a 400.** Send `cross_venue=true`; `requests` encodes Python booleans with a capital letter.

## Related

* [Relations](/concepts/relations): the three steps behind every proof, and what each relation bounds.
* [Leads](/concepts/leads): how a two-leg purchase pays \$1 in every outcome, and how fees are estimated.
* [Liquid opportunities](/cookbook/liquid-opportunities): every lead, gap and strategy match, ranked by edge × volume.
* [Rule-change watch](/cookbook/rule-change-watch): know when a contract version changes under a proof.
