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

# Order book

> The market's order book: both outcomes' bids and asks to the depth
asked, best first, with the top of book, the USD resting within 1, 2
and 5 cents of each side's best bid, the imbalance between the sides,
and the market's liquidity grade.

Books are recorded from the venues' own feeds. Markets graded
tradeable or deep, markets in a current lead, and markets of followed
events are recorded at full depth as every level changes (`tier` is
`full`); every other listed market is polled over REST, five levels
per side, once a cycle (`tier` is `rest`; `/v1/books/health` gives the
cycle time). A Yes ask is a No bid at the complementary price: the
two outcomes' ladders are one book seen from each side.

Without `at`, the book is the latest recorded, rebuilt from the last
snapshot and every level change since (`source` is `live`; `as_of` is
when the last change was received, and `feed` says whether the venue
feed is connected). With `at`, the book as it stood at that moment
(`source` is `rebuilt`), from up to 90 days back while events are
still hot; older history is in the daily Parquet export.

Prices are per contract that pays $1; quantities are contracts on
Kalshi and outcome shares on Polymarket.




## OpenAPI

````yaml /openapi.yaml get /v1/markets/{venue}/{id}/book
openapi: 3.1.0
info:
  title: Routeur Graph API
  version: '2026-09-15'
  summary: >-
    Proven relations between Kalshi and Polymarket contracts, with the history
    and signals built on them.
  description: >
    Routeur reads every open market on Kalshi and global Polymarket, and proves

    which ones imply, exclude or equal each other from each venue's structured

    contract terms and exact arithmetic. No relation is inferred from prose, and

    ambiguous or conflicting evidence is withheld.


    ## Authentication

    Send your key in the `X-API-Key` header, or as `Authorization: Bearer
    <key>`.

    Keys look like `rk_live_<12-character id>_<43-character secret>` and are

    shown once when issued. Keep them server-side.


    ## Rate limits

    Every key has a per-minute limit and a per-day quota set by its tier:


    | Tier | Requests per minute | Requests per day |

    |---|---|---|

    | free | 30 | 2,000 |

    | trader | 120 | 50,000 |

    | pro | 600 | 500,000 |

    | institutional | 3,000 | 10,000,000 |


    Responses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining` and

    `X-RateLimit-Reset` (Unix seconds) for the minute window, and

    `X-Daily-Quota-Limit` and `X-Daily-Quota-Remaining` for the day (UTC).

    A request over either limit returns `429` with `Retry-After` in seconds.


    ## Conventions

    - Money and prices are decimal strings in USD (for example `"0.4100"`),
    never
      floats. Prices are per contract that pays $1.
    - Times are RFC 3339 in UTC.

    - Successful responses wrap results in `data`. Graph-derived responses also
      name the `graph_run` they were read from; runs finish hourly.
    - Paginated lists return `next_cursor` when more results exist. Pass it back
      as `cursor` unchanged; cursors are opaque.
    - Unknown or repeated query parameters are rejected with `400`, so typos
    never
      silently widen a query.

    ## Liquidity

    Every object that names a market carries its 24-hour volume, its spread and

    a `liquidity` grade, because a price nobody can trade at is not a price:


    | Grade | 24-hour volume or open interest | Round-trip spread |

    |---|---|---|

    | `deep` | $25,000 traded, or $250,000 open interest | 2¢ or less |

    | `tradeable` | $1,000 traded, or $25,000 open interest | 5¢ or less |

    | `thin` | anything less, or no quoted round trip | |


    Lists that suggest something to act on — price gaps, leads, movers, flows,

    large fills, closing soon, strategy matches — leave thin markets out by

    default, and rank what is left by the money behind it. Three parameters

    change that wherever it applies: `min_volume_usd`, `max_spread_usd` and

    `include_thin=true`, which drops both floors. Search and event listings show

    thin markets but rank them below what can be traded.


    ## Errors

    Errors return a JSON body `{"error": {"code": "...", "message": "..."}}`.

    Branch on `code`; messages may change.


    | Status | Code | Meaning |

    |---|---|---|

    | 400 | `invalid_parameter` | A query parameter is unknown, repeated or out
    of range. |

    | 400 | `invalid_market` | The venue is not `kalshi` or `polymarket`, or the
    market id is malformed. |

    | 400 | `invalid_rulebook` | The venue, rulebook kind or id is malformed. |

    | 401 | `api_key_required` | No key was sent. |

    | 401 | `invalid_api_key` | The key is malformed or unknown. |

    | 401 | `api_key_revoked` | The key was revoked. |

    | 404 | `market_not_found` | The market is not in the latest graph. |

    | 404 | `relation_not_found` | Both markets are listed, but no current proof
    relates them. |

    | 404 | `rulebook_not_found` | No such rulebook has been recorded. |

    | 404 | `book_not_found` | No order book is recorded for the market at that
    time. |

    | 404 | `not_found` | No such endpoint. |

    | 429 | `rate_limited` | The per-minute limit was exceeded. |

    | 429 | `daily_quota_exceeded` | The daily quota is used up. |

    | 429 | `too_many_streams` | The key already holds its concurrent live
    streams. |

    | 503 | `graph_unavailable` | No graph run has finished yet. |

    | 503 | `stream_unavailable` | No live stream capacity is free; retry
    shortly. |

    | 504 | `timeout` | The request took longer than 15 seconds. |

    | 500 | `internal` | Something failed on our side. |


    ## Webhooks

    Mispricing alerts are delivered as signed `POST` requests; see the

    `webhooks` section. Each request carries

    `Routeur-Signature: t=<unix seconds>,v1=<hex>`, where `v1` is

    HMAC-SHA256 of `<t>.<raw body>` keyed by your subscription's signing

    secret. Reject requests whose signature does not match or whose `t` is more

    than five minutes old, and respond `2xx` within 10 seconds.


    `Routeur-Delivery` identifies the delivery and stays the same across
    retries,

    so use it to ignore duplicates. Any response other than `2xx` or `410`, or
    no

    response, is retried with exponential backoff from 30 seconds for up to 8

    attempts; responding `410 Gone` disables the subscription. Endpoints must be

    HTTPS on a public address, and redirects are not followed.
  contact:
    name: Routeur
    url: https://routeur.app
servers:
  - url: https://api.routeur.app
security:
  - apiKey: []
  - bearer: []
tags:
  - name: Events
    description: Real-world events across both venues, the way people browse them.
  - name: Graph
    description: Markets and the relations proven between them.
  - name: History
    description: Recorded quotes and trades.
  - name: Rules
    description: |
      Contract terms and their history. Every version of every market's rule
      text is kept from the day it was first seen, along with the rulebooks
      above it (Kalshi series and event terms, Polymarket resolution metadata)
      and the venue's contract terms documents, with diffs between versions.
  - name: Books
    description: >-
      Order books recorded live from each venue's feed, their history, and the
      health of the feeds.
  - name: Signals
    description: Mispricing leads and unusual trading derived from the graph and history.
  - name: Live
    description: Quotes, trades, relations and leads pushed as they happen.
  - name: Service
    description: Service status and this document.
paths:
  /v1/markets/{venue}/{id}/book:
    parameters:
      - $ref: '#/components/parameters/Venue'
      - $ref: '#/components/parameters/MarketID'
    get:
      tags:
        - Books
      summary: Order book
      description: |
        The market's order book: both outcomes' bids and asks to the depth
        asked, best first, with the top of book, the USD resting within 1, 2
        and 5 cents of each side's best bid, the imbalance between the sides,
        and the market's liquidity grade.

        Books are recorded from the venues' own feeds. Markets graded
        tradeable or deep, markets in a current lead, and markets of followed
        events are recorded at full depth as every level changes (`tier` is
        `full`); every other listed market is polled over REST, five levels
        per side, once a cycle (`tier` is `rest`; `/v1/books/health` gives the
        cycle time). A Yes ask is a No bid at the complementary price: the
        two outcomes' ladders are one book seen from each side.

        Without `at`, the book is the latest recorded, rebuilt from the last
        snapshot and every level change since (`source` is `live`; `as_of` is
        when the last change was received, and `feed` says whether the venue
        feed is connected). With `at`, the book as it stood at that moment
        (`source` is `rebuilt`), from up to 90 days back while events are
        still hot; older history is in the daily Parquet export.

        Prices are per contract that pays $1; quantities are contracts on
        Kalshi and outcome shares on Polymarket.
      operationId: getMarketBook
      parameters:
        - name: depth
          in: query
          description: Levels per side to return.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 10
        - name: at
          in: query
          description: >-
            The moment to rebuild the book at, RFC 3339. Omit for the latest
            book.
          schema:
            type: string
            format: date-time
          example: '2026-09-16T14:30:00Z'
      responses:
        '200':
          description: The book.
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-Daily-Quota-Limit:
              $ref: '#/components/headers/X-Daily-Quota-Limit'
            X-Daily-Quota-Remaining:
              $ref: '#/components/headers/X-Daily-Quota-Remaining'
          content:
            application/json:
              schema:
                type: object
                additionalProperties: false
                required:
                  - data
                properties:
                  data:
                    $ref: '#/components/schemas/Book'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: >-
            No order book is recorded for the market at that time
            (`book_not_found`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        default:
          $ref: '#/components/responses/Error'
components:
  parameters:
    Venue:
      name: venue
      in: path
      required: true
      description: The venue the market is listed on.
      schema:
        $ref: '#/components/schemas/Venue'
      example: kalshi
    MarketID:
      name: id
      in: path
      required: true
      description: >-
        The venue's market id, such as a Kalshi ticker or a Polymarket market
        slug.
      schema:
        $ref: '#/components/schemas/MarketID'
      example: KXNFLTEAMTOTAL-26SEP20MIASF-SF11
  headers:
    X-RateLimit-Limit:
      description: Requests allowed per minute for this key.
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests left in the current minute.
      schema:
        type: integer
    X-RateLimit-Reset:
      description: Unix time when the minute window resets.
      schema:
        type: integer
    X-Daily-Quota-Limit:
      description: Requests allowed per UTC day.
      schema:
        type: integer
    X-Daily-Quota-Remaining:
      description: Requests left today.
      schema:
        type: integer
  schemas:
    Book:
      type: object
      additionalProperties: false
      required:
        - venue
        - market_id
        - source
        - tier
        - as_of
        - snapshot_at
        - events_applied
        - depth
        - 'yes'
        - 'no'
        - top
        - feed
        - issues
        - volume_24h_usd
        - trades_24h
        - liquidity
      properties:
        volume_24h_usd:
          $ref: '#/components/schemas/Decimal'
          description: >
            Traded in the last 24 hours, in USD. The venue's own figure where it

            publishes one (Kalshi counts contracts at their $1 face value, as
            its own

            site does; Polymarket reports USDC notional), otherwise the notional
            of

            the fills this platform recorded. `volume_source` says which.
        volume_source:
          type: string
          enum:
            - venue
            - trades
          description: Where `volume_24h_usd` comes from.
        total_volume_usd:
          $ref: '#/components/schemas/Decimal'
          description: Traded over the market's life, where the venue reports it.
        open_interest_usd:
          $ref: '#/components/schemas/Decimal'
          description: Contracts currently held, at face value. Kalshi only.
        spread_usd:
          $ref: '#/components/schemas/Decimal'
          description: >-
            The round trip: the Yes ask plus the No ask less the $1 a winning
            contract pays. Absent when a side has no ask.
        yes_spread_usd:
          $ref: '#/components/schemas/Decimal'
          description: The Yes ask less the Yes bid, where the venue publishes a bid.
        no_spread_usd:
          $ref: '#/components/schemas/Decimal'
          description: The No ask less the No bid.
        trades_24h:
          type: integer
          description: Fills recorded in the last 24 hours.
        liquidity:
          $ref: '#/components/schemas/LiquidityGrade'
        book_spread_usd:
          $ref: '#/components/schemas/Decimal'
          description: >-
            From the recorded order book: the best Yes ask less the best Yes
            bid. Present for markets whose book is recorded.
        book_yes_depth_5c_usd:
          $ref: '#/components/schemas/Decimal'
          description: >-
            USD resting to buy Yes within 5 cents of the best Yes bid, from the
            recorded book.
        book_no_depth_5c_usd:
          $ref: '#/components/schemas/Decimal'
          description: >-
            USD resting to buy No within 5 cents of the best No bid (that is, to
            sell Yes), from the recorded book.
        book_imbalance:
          $ref: '#/components/schemas/Decimal'
          description: >-
            (Yes depth − No depth) / (Yes depth + No depth) over the 5-cent
            windows, from −1 to 1.
        book_at:
          $ref: '#/components/schemas/Timestamp'
          description: When the recorded book last changed.
        venue:
          $ref: '#/components/schemas/Venue'
        market_id:
          $ref: '#/components/schemas/MarketID'
        source:
          type: string
          enum:
            - live
            - rebuilt
          description: >-
            `live` is the latest recorded book; `rebuilt` is the book at the
            `at` asked for.
        tier:
          type: string
          enum:
            - full
            - rest
          description: >-
            `full`: every level change is recorded from the venue feed. `rest`:
            polled, five levels per side.
        as_of:
          $ref: '#/components/schemas/Timestamp'
          description: When the last change in this book was received.
        venue_ts:
          $ref: '#/components/schemas/Timestamp'
          description: The venue's own time on the last change, where it stamps one.
        seq:
          type: integer
          description: The venue's sequence number of the last change, where it has one.
        snapshot_at:
          $ref: '#/components/schemas/Timestamp'
          description: The snapshot the book was rebuilt from.
        events_applied:
          type: integer
          description: Level changes applied since the snapshot.
        depth:
          type: integer
          description: Levels per side asked for.
        'yes':
          $ref: '#/components/schemas/BookSide'
        'no':
          $ref: '#/components/schemas/BookSide'
        top:
          $ref: '#/components/schemas/BookTop'
        feed:
          type: object
          additionalProperties: false
          required:
            - connected
            - stale_seconds
          properties:
            connected:
              type: boolean
              description: Whether the venue feed is connected right now.
            last_message_at:
              $ref: '#/components/schemas/Timestamp'
            stale_seconds:
              type: integer
              description: Seconds since the book last changed; 0 for a rebuilt book.
        issues:
          type: array
          items:
            type: string
          description: 'Caveats: `polled`, `stale`, `truncated`.'
    Error:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: object
          additionalProperties: false
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: A stable machine-readable code.
            message:
              type: string
              description: A human-readable explanation.
    Venue:
      type: string
      enum:
        - kalshi
        - polymarket
    MarketID:
      type: string
      pattern: ^[A-Za-z0-9][A-Za-z0-9_.-]{0,199}$
    Decimal:
      type: string
      description: An exact decimal number.
      pattern: ^-?[0-9]+(\.[0-9]+)?$
      example: '0.4100'
    LiquidityGrade:
      type: string
      description: |
        How tradeable a market is. `deep`: at least $25,000 traded in 24 hours
        or $250,000 of open interest, with a round trip of 2¢ or less.
        `tradeable`: at least $1,000 traded or $25,000 of open interest, with a
        round trip of 5¢ or less. `thin`: anything less, or no quoted round
        trip. Lists of suggestions leave thin markets out unless asked.
      enum:
        - deep
        - tradeable
        - thin
    Timestamp:
      type: string
      format: date-time
    BookSide:
      type: object
      description: >-
        One outcome's ladder, best first. Its asks are the other outcome's bids
        at the complementary price.
      additionalProperties: false
      required:
        - bids
        - asks
      properties:
        bids:
          type: array
          items:
            $ref: '#/components/schemas/BookLevel'
        asks:
          type: array
          items:
            $ref: '#/components/schemas/BookLevel'
    BookTop:
      type: object
      description: >-
        The top of the book in Yes terms. Depth is the USD resting within 1, 2
        and 5 cents of each side's best bid (a level exactly that far counts);
        imbalance is (Yes − No) / (Yes + No) of the 5-cent depths.
      additionalProperties: false
      required:
        - yes_depth_1c_usd
        - yes_depth_2c_usd
        - yes_depth_5c_usd
        - no_depth_1c_usd
        - no_depth_2c_usd
        - no_depth_5c_usd
      properties:
        yes_bid_usd:
          $ref: '#/components/schemas/Decimal'
        yes_bid_quantity:
          $ref: '#/components/schemas/Decimal'
        yes_ask_usd:
          $ref: '#/components/schemas/Decimal'
          description: One less the best No bid.
        yes_ask_quantity:
          $ref: '#/components/schemas/Decimal'
        no_bid_usd:
          $ref: '#/components/schemas/Decimal'
        no_ask_usd:
          $ref: '#/components/schemas/Decimal'
        mid_usd:
          $ref: '#/components/schemas/Decimal'
        microprice_usd:
          $ref: '#/components/schemas/Decimal'
          description: >-
            The bid and ask weighed by the size resting at the other; leans
            toward the thinner side.
        spread_usd:
          $ref: '#/components/schemas/Decimal'
          description: Yes ask less Yes bid.
        yes_depth_1c_usd:
          $ref: '#/components/schemas/Decimal'
        yes_depth_2c_usd:
          $ref: '#/components/schemas/Decimal'
        yes_depth_5c_usd:
          $ref: '#/components/schemas/Decimal'
        no_depth_1c_usd:
          $ref: '#/components/schemas/Decimal'
        no_depth_2c_usd:
          $ref: '#/components/schemas/Decimal'
        no_depth_5c_usd:
          $ref: '#/components/schemas/Decimal'
        imbalance:
          $ref: '#/components/schemas/Decimal'
    BookLevel:
      type: object
      additionalProperties: false
      required:
        - price_usd
        - quantity
        - notional_usd
      properties:
        price_usd:
          $ref: '#/components/schemas/Decimal'
          description: Per contract that pays $1.
        quantity:
          $ref: '#/components/schemas/Decimal'
          description: >-
            Contracts (Kalshi) or outcome shares (Polymarket) resting at the
            price.
        notional_usd:
          $ref: '#/components/schemas/Decimal'
          description: Price times quantity.
  responses:
    BadRequest:
      description: Invalid parameter or market.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: invalid_parameter
              message: 'Invalid or unsupported query parameter: limit.'
    Unauthorized:
      description: Missing, invalid or revoked API key.
      headers:
        WWW-Authenticate:
          schema:
            type: string
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: api_key_required
              message: Send an API key in the X-API-Key header or as a Bearer token.
    TooManyRequests:
      description: Rate limit or daily quota exceeded.
      headers:
        Retry-After:
          description: Seconds until the limit resets.
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Error:
      description: Any other error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key
    bearer:
      type: http
      scheme: bearer
      description: The same API key sent as a Bearer token.

````