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

# Paginated catalog of verified cross-venue matched markets

> Returns embedding-verified cross-venue market matches (verified matches only), joined against market metadata for display (title, ticker, images, expiry, status). `min_similarity` is clamped server-side to never go below a minimum threshold regardless of what the caller passes. Pairs are dropped if either correlation side has expired, if either side references a provider that is unknown or not currently indexing-enabled, or if either side's resolved market status is settled/closed/resolved; a side with no metadata available (unmirrored rather than de-indexed) is kept with null display fields. `has_more` reflects whether the underlying page (before the live-status post-filter) was full, so it is not a strict function of the returned `count`/`pairs` length. `total` is only computed (filters applied before the live-status post-filter) when `include_total=true`. This is treated as a primary, non-additive endpoint: any backend failure returns 503 rather than a degraded/empty result.



## OpenAPI

````yaml /openapi/data-api.yaml get /matched-markets
openapi: 3.1.0
info:
  title: Kairos Data API
  version: 1.0.0
  summary: >-
    The full Kairos data plane — markets, candles, trades, search, discover,
    sports, trader analytics, and PnL.
  description: |
    The Kairos Data API at `data.kairos.trade` is the platform's primary data
    plane: market metadata and prices, OHLCV candles, live venue trade proxies,
    normalized trade history, full-text search, discovery feeds, the sports
    catalog, public trader analytics, and account PnL.

    ## Authentication

    Most endpoints accept a Kairos **API key** (`X-Client-Id` + `X-Api-Key` +
    `X-Api-Secret`, all three) or a first-party session JWT. Endpoints tagged
    `public` (trader analytics, provider configs, several sports feeds) need
    no credentials at all. Some endpoints additionally require an API-key
    **scope** (`trade:read`, `position:read`) — stated per operation.

    For high-volume market-data consumption (candles/trades/metadata at
    scale), prefer the dedicated **Market Data API** at `md.kairos.trade` —
    it has higher budgets, ETag caching, and a binary candle format.

    ## Rate limits

    Rate limits use a sliding window keyed on the authenticated user (JWT
    `sub`) or, for anonymous callers, the trusted client IP. Routes belong to
    a named **bucket** (`x-kairos-bucket`) whose per-minute budget is shared
    by every route in it; routes with no bucket run under the service default
    of 100/minute. `x-kairos-rate-limit` states the bucket's compile-time
    default — operators can raise or lower a bucket at runtime, so treat the
    documented number as the baseline, not a contract. 429 responses carry
    `Retry-After` and `X-RateLimit-*`.

    ## Conventions

    - Prices are on the **0–100 cents scale** unless a field says otherwise
      (trader-analytics position/trade prices use the 0–1 scale; each field's
      description states its scale).
    - Errors: `{"detail": "<message>"}` for handler errors; FastAPI's
      standard validation envelope for 422s. Errors surfaced from a venue
      adapter instead use `{"error", "provider", "operation", "message"}` —
      see `DataProviderError`. Unhandled failures always return the generic
      500 body; internal details are logged, never returned.
    - Every request body is capped at 8 MiB service-wide (413).
  contact:
    name: Kairos
    url: https://app.kairos.trade/docs/api-reference
  termsOfService: https://kairos.trade/terms
servers:
  - url: https://data.kairos.trade
    description: Production
  - url: https://staging-data.kairos.trade
    description: Staging
security:
  - apiKeyClientId: []
    apiKeyKey: []
    apiKeySecret: []
paths:
  /matched-markets:
    get:
      tags:
        - Sports
      summary: Paginated catalog of verified cross-venue matched markets
      description: >-
        Returns embedding-verified cross-venue market matches (verified matches
        only), joined against market metadata for display (title, ticker,
        images, expiry, status). `min_similarity` is clamped server-side to
        never go below a minimum threshold regardless of what the caller passes.
        Pairs are dropped if either correlation side has expired, if either side
        references a provider that is unknown or not currently indexing-enabled,
        or if either side's resolved market status is settled/closed/resolved; a
        side with no metadata available (unmirrored rather than de-indexed) is
        kept with null display fields. `has_more` reflects whether the
        underlying page (before the live-status post-filter) was full, so it is
        not a strict function of the returned `count`/`pairs` length. `total` is
        only computed (filters applied before the live-status post-filter) when
        `include_total=true`. This is treated as a primary, non-additive
        endpoint: any backend failure returns 503 rather than a degraded/empty
        result.
      operationId: getMatchedMarkets
      parameters:
        - name: limit
          in: query
          required: false
          description: Maximum number of pairs to return.
          schema:
            type: integer
            minimum: 1
            maximum: 1000
            default: 50
          example: 50
        - name: offset
          in: query
          required: false
          description: Legacy pagination offset. Do not combine with cursor.
          schema:
            type: integer
            minimum: 0
            default: 0
          example: 0
        - name: cursor
          in: query
          required: false
          description: >-
            Opaque keyset cursor. Send an empty value on the first page, then
            pass each response next_cursor. Cursor mode orders by immutable
            canonical pair identity so catalogue mutations cannot shift page
            boundaries, and binds every page to one full-set fingerprint.
          schema:
            type: string
            maxLength: 16384
          example: ''
        - name: provider
          in: query
          required: false
          description: >-
            Filter to pairs where either side belongs to this provider. Must
            resolve to a known provider name (case-insensitive) or the request
            fails with 400.
          schema:
            type: string
          example: polymarket
        - name: min_similarity
          in: query
          required: false
          description: >-
            Minimum embedding similarity score. Always clamped up server-side to
            a minimum threshold even if a lower value is supplied.
          schema:
            type: number
            format: double
            minimum: 0
            maximum: 1
            default: 0.82
          example: 0.85
        - name: sort_by
          in: query
          required: false
          description: >-
            Sort column. Must be "similarity" or "updated_at"; any other value
            fails with 400.
          schema:
            type: string
            enum:
              - similarity
              - updated_at
            default: similarity
          example: similarity
        - name: include_total
          in: query
          required: false
          description: >-
            When true, runs an additional COUNT query and includes the total
            matching-pair count in the response.
          schema:
            type: boolean
            default: false
          example: false
      responses:
        '200':
          description: A page of verified cross-venue matched market pairs.
          headers:
            Cache-Control:
              schema:
                type: string
                example: public, max-age=10
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SportsMatchedMarketsResponse'
        '400':
          description: >-
            Unknown provider name, or sort_by is not one of the supported
            columns.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                    example: Unknown provider 'foo'
        '409':
          description: >-
            The correlation catalogue changed during a cursor walk. Discard
            accumulated pages and restart with an empty cursor.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
        '422':
          $ref: '#/components/responses/DataValidationError'
        '429':
          $ref: '#/components/responses/DataRateLimited'
        '503':
          description: The correlation store could not be queried.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                    example: Correlation store unavailable
      security: []
components:
  schemas:
    SportsMatchedMarketsResponse:
      type: object
      required:
        - pairs
        - count
        - limit
        - offset
        - has_more
      properties:
        pairs:
          type: array
          items:
            $ref: '#/components/schemas/SportsMatchedMarketPair'
        count:
          type: integer
          description: >-
            Number of pairs on this page after live-status post-filtering (may
            be less than limit).
          example: 42
        limit:
          type: integer
          example: 50
        offset:
          type: integer
          example: 0
        has_more:
          type: boolean
          description: >-
            Whether the underlying page (before live-status post-filtering) was
            full — not a strict function of count.
        next_cursor:
          type:
            - string
            - 'null'
          description: >-
            Opaque cursor for the next keyset page. Present when cursor mode is
            requested.
        catalog_version:
          type: string
          description: Full-set fingerprint shared by every page in one cursor walk.
        total:
          type: integer
          description: >-
            Only present when include_total=true. Total matching-pair count
            under the pre-live-filter query filters.
          example: 1284
    SportsMatchedMarketPair:
      type: object
      required:
        - a
        - b
        - similarity
        - updated_at
      properties:
        a:
          $ref: '#/components/schemas/SportsMatchedMarketSide'
        b:
          $ref: '#/components/schemas/SportsMatchedMarketSide'
        similarity:
          type: number
          format: double
          minimum: 0.82
          maximum: 1
          example: 0.94
        updated_at:
          type: string
          format: date-time
    SportsMatchedMarketSide:
      type: object
      required:
        - provider_id
        - provider
        - market_id
        - title
        - ticker
        - image
        - icon
        - expires_at
        - category
      properties:
        provider_id:
          type: integer
          example: 2
        provider:
          type: string
          example: polymarket
        market_id:
          type: string
          example: '587234'
        title:
          type:
            - string
            - 'null'
          description: Null if metadata for this side's market isn't available.
          example: Will the Celtics win?
        ticker:
          type:
            - string
            - 'null'
        image:
          type:
            - string
            - 'null'
        icon:
          type:
            - string
            - 'null'
        expires_at:
          type:
            - string
            - 'null'
          format: date-time
        category:
          type:
            - string
            - 'null'
          description: >-
            Canonical title-cased category, or null when the market is
            uncategorised.
  responses:
    DataValidationError:
      description: Request failed FastAPI parameter validation.
      content:
        application/json:
          schema:
            type: object
            required:
              - detail
            properties:
              detail:
                type: array
                description: >-
                  One entry per failed field, with location, message, and error
                  type.
                items:
                  type: object
                  additionalProperties: true
    DataRateLimited:
      description: >
        Rate limit exceeded for this route's sliding window, keyed on the
        session `sub` when

        authenticated and on the trusted client IP otherwise. Honor
        `Retry-After`. A per-API-key

        data ceiling (set per credential) rejects with `{"detail": "API key data
        rate limit

        exceeded"}` instead of the `error` envelope below.
      headers:
        Retry-After:
          schema:
            type: integer
        X-RateLimit-Limit:
          schema:
            type: integer
        X-RateLimit-Remaining:
          schema:
            type: integer
        X-RateLimit-Reset:
          schema:
            type: integer
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
                example: 'Rate limit exceeded: 100 per 1 minute'
  securitySchemes:
    apiKeyClientId:
      type: apiKey
      in: header
      name: X-Client-Id
      description: >-
        Credential client id (`kairos_ck_...`). Must be sent together with
        X-Api-Key and X-Api-Secret.
    apiKeyKey:
      type: apiKey
      in: header
      name: X-Api-Key
      description: 64-char hex API key.
    apiKeySecret:
      type: apiKey
      in: header
      name: X-Api-Secret
      description: 64-char hex API secret.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.