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

# Fetch a single event by slug

> Public event detail, resolved by the canonical event slug (exact match; UUIDs are not accepted). Returns the full `EventSummaryDto` with full `MarketSummaryDto` markets — every visible market in any public status, closed and settled ones included (short-crypto Up/Down windows that are RESOLVED or VOIDED are capped at 3 per event; `totalMarketCount` still counts them all). This is where the fields left out of `GET /api/events` rows live (`eventSlug`, `tags`, `tradingMode`, `notTradableReason`, `resolutionCriteria` outside long-dated crypto, the full `prediction`, `probabilityChange.asOf`, …). 404 `event_not_found` (`details.slug`) when the slug does not exist, has no public market, or belongs to an unpublished match. `saved` is personalised as on the list. Not cached server-side.



## OpenAPI

````yaml /api-reference/openapi.json get /api/events/{slug}
openapi: 3.1.0
info:
  title: PredictStreet API
  description: >-
    Client-facing HTTP API for the PredictStreet prediction-market platform.
    **Partner kinds.** Every authenticated endpoint resolves a request's
    *effective wallet* from the partner row. `single_wallet` partners bind to
    one `associatedWallet` set at creation. `multi_wallet` partners declare the
    actor on every request via an `X-User-Wallet: 0x<40-hex>` header. See the
    [Partner kinds](/auth/api-keys#partner-kinds) doc for the full contract.
  version: '2026-06-16'
  contact:
    name: PredictStreet partners
    email: partners@predictstreet.com
servers:
  - url: https://core.api.dev.predictstreet.sde.adifoundation.ai
    description: Testnet (partner integrator API — final domain TBD)
security: []
tags:
  - name: Deposits
    description: >-
      Gasless USDC deposit relay - submit a signed EIP-2612 permit and the
      platform broadcasts the on-chain deposit for you (no gas).
  - name: Events
    description: >-
      Polymarket-style event grouping with football metadata (group, stage,
      teams, tags).
  - name: Tags
    description: Curated tag taxonomy used to filter events.
  - name: Markets
    description: 'Public market data: list, detail, orderbook, trades, OHLC.'
  - name: Crypto
    description: >-
      Crypto price markets: the underlying-asset price curve and Up/Down series
      navigation. The markets themselves are ordinary binary markets — list them
      through /api/markets and /api/events.
  - name: Orders
    description: >-
      Signed-order place / cancel / read. Requires `X-Api-Key` with
      `orders:read` / `orders:write` scope; every write additionally requires an
      EIP-712 signature over the order.
  - name: Portfolio
    description: >-
      Balances, positions, trades, fees, vault info for the key's
      `associatedWallet`. Requires `X-Api-Key` with `portfolio:read` scope.
  - name: Matches
    description: >-
      A match groups several events into one fixture/card (1X2 + first-scorer +
      over-under under one matchup).
  - name: Vault
    description: >-
      Backend co-signatures for ERC-1155 split / merge, and recovery for
      off-chain locks when the corresponding chain tx never confirmed. Requires
      `X-Api-Key` with `vault:write` scope plus an EIP-712 signature over the
      operation.
  - name: Leaderboard
    description: Public ranked leaderboard across PnL / volume buckets.
  - name: Search
    description: Global search across users, events, and matches.
  - name: Withdrawal Security
    description: >-
      Self-service withdrawal 2FA (TOTP) and withdrawal-address whitelist. Same
      endpoints serve the web app (user sessions) and API-key integrators.
      Mutations need `vault:write`, reads `portfolio:read`. Both are opt-in per
      wallet and only gate withdrawals once the platform enables
      withdrawal-security enforcement.
  - name: Platform
    description: >-
      Public platform state: the contract registry, the platform fee
      configuration, the platform freeze flag and active notices. No
      authentication.
paths:
  /api/events/{slug}:
    get:
      tags:
        - Events
      summary: Fetch a single event by slug
      description: >-
        Public event detail, resolved by the canonical event slug (exact match;
        UUIDs are not accepted). Returns the full `EventSummaryDto` with full
        `MarketSummaryDto` markets — every visible market in any public status,
        closed and settled ones included (short-crypto Up/Down windows that are
        RESOLVED or VOIDED are capped at 3 per event; `totalMarketCount` still
        counts them all). This is where the fields left out of `GET /api/events`
        rows live (`eventSlug`, `tags`, `tradingMode`, `notTradableReason`,
        `resolutionCriteria` outside long-dated crypto, the full `prediction`,
        `probabilityChange.asOf`, …). 404 `event_not_found` (`details.slug`)
        when the slug does not exist, has no public market, or belongs to an
        unpublished match. `saved` is personalised as on the list. Not cached
        server-side.
      operationId: EventsController_bySlug
      parameters:
        - name: slug
          in: path
          required: true
          description: Canonical event slug, e.g. `fifa-world-cup-2026-winner`.
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventSummaryDto'
              examples:
                detail:
                  summary: Binary politics event with its full market row
                  value:
                    id: 5cc08926-c0c6-43c4-885d-f7eaa86c9f85
                    slug: lula-participates-in-debate-before-first-round
                    title: Lula participates in debate before first round?
                    metaTitle: null
                    imageUrl: null
                    homeCountry: null
                    awayCountry: null
                    sport: politics
                    vertical: politics
                    match: null
                    teamA: null
                    teamB: null
                    competition: null
                    tags:
                      - slug: politics
                        name: Politics
                    scheduledAt: '2026-10-03T23:59:00.000Z'
                    endedAt: null
                    scheduleStatus: SCHEDULED
                    scheduleReason: null
                    settlesByAt: null
                    volume24h: '0'
                    totalVolume: '7641.23527'
                    openMarketCount: 1
                    totalMarketCount: 1
                    createdAt: '2026-08-25T12:36:08.393Z'
                    updatedAt: '2026-08-25T12:36:08.393Z'
                    saved: false
                    markets:
                      - id: e5d13707-63c1-43fa-8d07-d8fdc906e405
                        eventId: 5cc08926-c0c6-43c4-885d-f7eaa86c9f85
                        eventSlug: lula-participates-in-debate-before-first-round
                        homeCountry: null
                        awayCountry: null
                        tags:
                          - slug: politics
                            name: Politics
                        symbol: LULA-PARTICIPATES-IN-DEBATE-BEFORE-FIRST-19838666
                        slug: lula-participates-in-debate-before-first-round
                        title: Lula participates in debate before first round?
                        question: Lula participates in debate before first round?
                        groupItemTitle: null
                        groupItemSubtitle: null
                        groupItemImageUrl: null
                        conditionId: >-
                          0x895efaa1bf69dba4b3be31184ad8cc6d077139062d143e75138fa2283de25293
                        questionId: >-
                          0xe8bd100c7f8db1accb62c99b6ceb08e33a4ca7c5ac538b66c8087619c4f3ba15
                        yesTokenId: >-
                          69774830757241944332031024355686314641795603675990763578292357453968296704950
                        noTokenId: >-
                          55033404926999163162452043496432946222771140431114106881962498002067653861509
                        outcomes:
                          - label: 'YES'
                            tokenId: >-
                              69774830757241944332031024355686314641795603675990763578292357453968296704950
                            noTokenId: null
                            conditionId: >-
                              0x895efaa1bf69dba4b3be31184ad8cc6d077139062d143e75138fa2283de25293
                            outcomeIndex: 0
                          - label: 'NO'
                            tokenId: >-
                              55033404926999163162452043496432946222771140431114106881962498002067653861509
                            noTokenId: null
                            conditionId: >-
                              0x895efaa1bf69dba4b3be31184ad8cc6d077139062d143e75138fa2283de25293
                            outcomeIndex: 1
                        sourceSelections: []
                        line: null
                        lineGroup: null
                        outcomeCount: 2
                        outcomeLabels:
                          - 'YES'
                          - 'NO'
                        outcomePrices:
                          - '0.680000'
                          - '0.320000'
                        chances:
                          - '0.680000'
                          - '0.320000'
                        status: OPEN
                        currentReviewRound: 1
                        feeTakerBps: 600
                        executionDelayMs: 0
                        liveTick: null
                        kickoff: null
                        tradingWindow:
                          preMarketStartsAt: '2026-08-27T16:40:03.505Z'
                          opensAt: '2026-08-27T20:40:48.163Z'
                          closesAt: '2026-10-03T23:59:00.000Z'
                        resolutionWindowHours: 2
                        payoutNumerators: null
                        officialDataSource: lsports
                        sourceMatchId: '19838666'
                        additionalSources: []
                        resolutionCriteria: >-
                          This market will resolve to Yes if Luiz Inácio Lula da
                          Silva participates in a televised Brazilian
                          presidential debate by October 3, 2026, 11:59 PM
                          Brasilia time. Otherwise, it will resolve to No.
                        cryptoWindow: null
                        negRiskEligible: false
                        negRiskMarketId: null
                        negRiskQuestionIndex: null
                        isNewMarketType: false
                        marketType: null
                        sport: politics
                        vertical: politics
                        volume24h: '0'
                        totalVolume: '7641.235270000000000000'
                        createdAt: '2026-08-25T12:38:10.240Z'
                        updatedAt: '2026-08-27T20:40:48.163Z'
                        lifecycle:
                          closedAt: null
                          pausedAt: null
                          resolvedAt: null
                          voidedAt: null
                        resolution:
                          proposedAt: null
                          challengeWindowClosesAt: null
                          disputedAt: null
                          proposedOutcome: null
                          proposedOutcomeIndex: null
                          resolvedOutcome: null
                          resolvedOutcomeIndex: null
                          disputeBondUsdcRaw: null
                          disputeReason: null
                          resolutionKind: null
                          proposalKind: null
                          proposedFairPriceSplit: null
                        crypto: null
                        prediction:
                          version: 1
                          provider: lsports
                          questionId: '19838666'
                          question: Lula participates in debate before first round?
                          kind: binary
                          line: null
                          rulesText: >-
                            This market will resolve to Yes if Luiz Inácio Lula
                            da Silva participates in a televised Brazilian
                            presidential debate by October 3, 2026, 11:59 PM
                            Brasilia time. Otherwise, it will resolve to No.
                          threshold: null
                          endsAt: '2026-10-03T23:59:00Z'
                          capturedAt: '2026-08-25T12:38:10.228Z'
                        live: null
                        tradable: true
                        tradingMode: open
                        notTradableReason: null
                        probabilityChange:
                          window: 24h
                          unit: percentage_points
                          asOf: '2026-09-30T11:21:45.199Z'
                          outcomes:
                            - outcomeIndex: 0
                              change: 0
                              baselineAt: '2026-09-28T17:00:00.000Z'
                            - outcomeIndex: 1
                              change: 0
                              baselineAt: '2026-09-28T17:00:00.000Z'
                    category:
                      key: OTHER
                      label: Other
                    live: null
                    inPlay: false
                    cryptoSeries: null
                    cryptoLongSeries: null
        '404':
          description: event_not_found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - {}
components:
  schemas:
    EventSummaryDto:
      type: object
      description: >-
        Full event shape, returned by `GET /api/events/{slug}` and `GET
        /api/events/featured`: the same event-level fields as a `GET
        /api/events` row, with full `MarketSummaryDto` markets.
      properties:
        id:
          type: string
          format: uuid
          description: Event UUID.
        slug:
          type: string
          description: Canonical event slug — the key for `GET /api/events/{slug}`.
          example: lithuania-vs-andorra
        title:
          type: string
          description: Display title.
        metaTitle:
          type: string
          nullable: true
          description: SEO title set by operators; null ⇒ use `title`.
        imageUrl:
          type: string
          nullable: true
          description: >-
            Competition or tournament logo URL. Display-only; null ⇒ use a
            placeholder.
        homeCountry:
          type: string
          nullable: true
          description: >-
            Home participant's country, ISO-3166-1 alpha-2 (tennis: the player's
            flag). Null when unknown — normal for events without participants
            and for uneven feed coverage.
        awayCountry:
          type: string
          nullable: true
          description: Away participant's country, ISO-3166-1 alpha-2 — see `homeCountry`.
        sport:
          type: string
          nullable: true
          description: >-
            Sport in the live-score vocabulary (`soccer`, `tennis`, `baseball`,
            `politics`, …) — the same word `live.sport` carries. For navigation
            use `vertical` (football is `soccer` here and `football` there).
            Null on legacy events.
          example: soccer
        vertical:
          type: string
          nullable: true
          description: >-
            Navigation vertical (`football`, `tennis`, `crypto`, `politics`, …)
            — the value `?vertical=` filters on and `GET /api/verticals` counts.
            Null on legacy events.
          example: football
        match:
          nullable: true
          description: >-
            Parent match (`id`, `slug`, `title`, `group`, `stage`,
            `competition`, teams, `kickoffAt`, `state`). Null for events not
            bound to a match: outrights, politics, and match-less fixtures such
            as most tennis events.
          allOf:
            - $ref: '#/components/schemas/EventMatchSummaryDto'
        stage:
          type: string
          nullable: true
          enum:
            - group
            - r32
            - r16
            - quarter_finals
            - semi_finals
            - third_place
            - final
            - fifa_friendlies
            - ucl
            - uefa_europa_conference_league
          description: >-
            Tournament stage: a match-less football fixture's own, or the parent
            match's (then equal to `match.stage`). Set on match-less fixtures
            too, so read this rather than `match.stage`. A value from the match
            can be a competition tag (`fifa_friendlies`, `ucl`,
            `uefa_europa_conference_league`). The value `?stage=` filters on.
          example: group
        group:
          type: string
          nullable: true
          enum:
            - A
            - B
            - C
            - D
            - E
            - F
            - G
            - H
            - I
            - J
            - K
            - L
          description: >-
            Group letter (A to L), from the same source as `stage`; a match-less
            fixture has one only on the group stage. The value `?group=` filters
            on.
          example: A
        teamA:
          nullable: true
          description: >-
            Home participant — the participant field for head-to-head events,
            whether or not they are bound to a match. On a match-less event
            `code` may be empty and `logo` null — render `label` first. Null on
            outrights, tournament events and legacy rows.
          allOf:
            - $ref: '#/components/schemas/TeamRefDto'
        teamB:
          nullable: true
          description: Away participant; same semantics as `teamA`.
          allOf:
            - $ref: '#/components/schemas/TeamRefDto'
        competition:
          nullable: true
          description: >-
            Effective competition (the match's, else the event's own) — set on
            match-less events too. Its `slug` is what `?competition=` accepts.
            Null when the event has none.
          allOf:
            - $ref: '#/components/schemas/CompetitionRefDto'
        tags:
          type: array
          items:
            $ref: '#/components/schemas/EventTagSummaryDto'
          description: >-
            Active tags (`slug`, `name`). Always an array; empty when the event
            has none.
        category:
          description: >-
            Category-tab bucket folded from the markets' types (`GAME_LINES`,
            `TEAM_TO_ADVANCE`, `EXACT_SCORE`, `OTHER`).
          allOf:
            - $ref: '#/components/schemas/MarketCategoryDto'
        scheduledAt:
          type: string
          format: date-time
          nullable: true
          description: >-
            Scheduled start time of the event. For an event bound to a match
            this usually equals `match.kickoffAt`, but may differ for
            partial-game props. The ISO-8601 `from` / `to` filters compare
            against the event's start time.
        endedAt:
          type: string
          format: date-time
          nullable: true
          description: >-
            When the event's outcome was determined (full time, race end, half
            time for partial-game props). Null until known; unlike `live`, it
            persists after the game.
        scheduleStatus:
          type: string
          enum:
            - SCHEDULED
            - POSTPONED
            - CANCELLED
            - PLAYED
          description: >-
            Schedule state. `POSTPONED` keeps markets open and sets
            `settlesByAt`; `CANCELLED` settles positions at fair value. Read
            this for the badge rather than deriving it from times.
          example: SCHEDULED
        scheduleReason:
          type: string
          nullable: true
          description: Reason when `scheduleStatus` is not `SCHEDULED`.
        settlesByAt:
          type: string
          format: date-time
          nullable: true
          description: >-
            `POSTPONED` only: if the event is not played by this time, positions
            settle at fair value.
        volume24h:
          type: string
          description: >-
            Matched notional across the event's markets over the last 24 h
            (USDC, decimal string).
          example: '578.207202'
        totalVolume:
          type: string
          description: >-
            All-time matched notional across the event's markets (USDC, decimal
            string).
          example: '1084.507287'
        openMarketCount:
          type: integer
          description: >-
            How many of the event's markets are on the open view (visible,
            launched PRE_MARKET / OPEN / PAUSED …). Not the tradeable count — a
            PAUSED market is counted and rejects orders. `markets[]` is
            view-filtered, so render counters from this field, never from
            `markets.length`.
          example: 2
        totalMarketCount:
          type: integer
          description: >-
            How many of the event's markets the public may know exist: visible,
            in an open-view or closed status, and past their launch time.
            `openMarketCount <= totalMarketCount`. On `GET /api/events/{slug}`
            it equals `markets.length`, except on short-crypto Up/Down events,
            whose settled windows are capped at 3 there.
          example: 5
        createdAt:
          type: string
          format: date-time
          description: Creation time.
        updatedAt:
          type: string
          format: date-time
          description: Last update time.
        saved:
          type: boolean
          description: >-
            True when the event is in the signed-in web-app user's saved list.
            Always `false` on anonymous and API-key requests. Always present.
        live:
          nullable: true
          description: >-
            Live clock + score, rolled up from the markets while the fixture is
            in play. After the game a finished event can keep its final-score
            frame (`provider: "final"`, `inPlay: false`). Null when there is no
            frame (pre-match, no live feed) and always null for POSTPONED and
            CANCELLED events.
          allOf:
            - $ref: '#/components/schemas/MarketLiveStatusDto'
        inPlay:
          type: boolean
          description: >-
            True while the event is in play: kickoff passed, not ended, within a
            4-hour window (a live frame's `inPlay` overrides this when one
            exists). Always false for abstract events such as "World Cup
            Winner". Use it instead of recomputing from market status or
            kickoff.
        cryptoSeries:
          nullable: true
          description: >-
            Short-crypto Up/Down series this event's windows belong to; null on
            every other event. One event holds one UTC day of windows (~96 at a
            15-minute cadence) — navigate them with `GET
            /api/crypto-series/{id}/windows` rather than `markets[]`.
          allOf:
            - $ref: '#/components/schemas/EventCryptoSeriesDto'
        cryptoLongSeries:
          nullable: true
          description: >-
            Long-dated crypto series this event is one period of; null on every
            other event. `periods` lists sibling periods for period tabs (at
            most 24); `GET /api/crypto-long-series/{id}/periods` returns them
            all.
          allOf:
            - $ref: '#/components/schemas/EventCryptoLongSeriesDto'
        markets:
          type: array
          items:
            $ref: '#/components/schemas/MarketSummaryDto'
          description: >-
            The event's markets in the full `MarketSummaryDto` shape. `GET
            /api/events/{slug}`: every visible market in any public status,
            closed and settled ones included (RESOLVED / VOIDED short-crypto
            Up/Down windows are capped at 3 per event). `GET
            /api/events/featured`: filtered like the list's open view (closed
            view for the finished-event fallback with `team`).
      required:
        - id
        - slug
        - title
        - metaTitle
        - imageUrl
        - homeCountry
        - awayCountry
        - sport
        - vertical
        - match
        - stage
        - group
        - teamA
        - teamB
        - competition
        - tags
        - category
        - scheduledAt
        - endedAt
        - scheduleStatus
        - scheduleReason
        - settlesByAt
        - volume24h
        - totalVolume
        - openMarketCount
        - totalMarketCount
        - createdAt
        - updatedAt
        - saved
        - live
        - inPlay
        - cryptoSeries
        - cryptoLongSeries
        - markets
    Error:
      type: object
      description: >-
        Error body returned by every API error (same shape as `ErrorEnvelope`).
        Branch on `error.code`, not on `message`.
      required:
        - status
        - error
      properties:
        status:
          type: integer
          description: HTTP status, repeated in the body.
          example: 404
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: >-
                Machine-readable code (e.g. `market_not_found`,
                `event_not_found`, `invalid_limit`).
            message:
              type: string
            trace_id:
              type: string
              description: Request trace id; quote it to support. May be absent.
            retryAfterSec:
              type: integer
              description: >-
                Seconds to wait before retrying, when the server says so (also
                sent as the `Retry-After` header).
            retryable:
              type: boolean
              description: >-
                Whether the same request may be sent again as it is. Absent when
                the server does not say.
            details:
              type: object
              additionalProperties: true
              description: >-
                Extra structured context thrown with the error, e.g. `slug`,
                `allowed`, `auditId`.
    EventMatchSummaryDto:
      type: object
      properties:
        id:
          type: string
          description: Match UUID.
        slug:
          type: string
          description: Match slug — the key for `GET /api/matches/{slug}`.
        title:
          type: string
          description: Fixture title, e.g. `Real Madrid vs Manchester City`.
        group:
          type: string
          nullable: true
          description: Tournament group letter.
        stage:
          type: string
          nullable: true
          description: Knockout stage tag; null on a match with no stage (club fixtures).
        competition:
          nullable: true
          description: >-
            The competition this match belongs to. Null only on a legacy row
            with no catalog link.
          allOf:
            - $ref: '#/components/schemas/CompetitionRefDto'
        teamA:
          description: Home team (FIFA code + display name).
          allOf:
            - $ref: '#/components/schemas/TeamRefDto'
        teamB:
          description: Away team (FIFA code + display name).
          allOf:
            - $ref: '#/components/schemas/TeamRefDto'
        kickoffAt:
          type: string
          format: date-time
          nullable: true
          description: >-
            ISO-8601 — canonical scheduled kickoff for the underlying contest.
            Same value as `kickoffAt` on `GET /api/matches`.
        state:
          type: string
          description: >-
            Match publication state — `LIVE` for every match returned publicly.
            Not an in-play flag.
      required:
        - id
        - slug
        - title
        - group
        - stage
        - competition
        - teamA
        - teamB
        - kickoffAt
        - state
    TeamRefDto:
      type: object
      properties:
        code:
          type: string
          description: FIFA 3-letter code (e.g. "BRA").
        label:
          type: string
          description: >-
            Display name (e.g. "Brazil"). Falls back to the code when the code
            has no name mapping.
        logo:
          type: string
          nullable: true
          description: >-
            Club crest URL, or null. Null is normal for a national team: render
            the crest when present and fall back to a flag drawn from `code`
            only when it is null.
      required:
        - code
        - label
        - logo
    CompetitionRefDto:
      type: object
      properties:
        name:
          type: string
          description: Competition display name.
        slug:
          type: string
          description: Competition slug — accepted by `/api/events?competition=`.
        logo:
          type: string
          nullable: true
          description: Competition crest URL, or null.
      required:
        - name
        - slug
        - logo
    EventTagSummaryDto:
      type: object
      properties:
        slug:
          type: string
          description: >-
            Slug accepted by the `?tag=` filter on `/api/events` and
            `/api/matches`.
        name:
          type: string
          description: Display name.
      required:
        - slug
        - name
    MarketCategoryDto:
      type: object
      properties:
        key:
          type: string
          enum:
            - GAME_LINES
            - TEAM_TO_ADVANCE
            - EXACT_SCORE
            - OTHER
          description: >-
            Category-tab bucket for this event; switch on this. Unmapped, new or
            typeless markets fold to `OTHER`.
        label:
          type: string
          description: Fallback display label; map `key` to your own labels.
      required:
        - key
        - label
    MarketLiveStatusDto:
      type: object
      properties:
        state:
          type: string
          nullable: true
          description: >-
            Raw provider period/status code, kept verbatim for display.
            api-football: "1H" | "HT" | "2H" | "ET" | "BT" | "P" | "LIVE". Stats
            Perform: "FirstHalf" | "HalfTime" | "SecondHalf" | … Null when the
            frame carried no state.
        minute:
          type: number
          nullable: true
          description: >-
            Elapsed match minute; null when the provider sent no clock. Caps at
            45/90 during stoppage — the added minutes are in `addedMinute`.
        addedMinute:
          type: number
          nullable: true
          description: >-
            Stoppage / added minutes (the "+N" in "90+3"); null when the match
            is not in stoppage. Render as `${minute}+${addedMinute}`.
        score:
          nullable: true
          description: Parsed running score; null until the first scored frame arrives.
          allOf:
            - $ref: '#/components/schemas/MarketLiveScoreDto'
        scoreText:
          type: string
          nullable: true
          description: >-
            Raw score string as the provider sent it (e.g. "2-1"); display
            fallback when the numeric parse fails.
        penaltyScore:
          nullable: true
          description: >-
            Penalty-shootout tally, present only while a shootout is in progress
            or decided; the on-pitch score stays in `score` (render e.g. "1-1
            (5-4 pens)"). Usually absent.
          allOf:
            - $ref: '#/components/schemas/MarketLiveScoreDto'
        penaltyScoreText:
          type: string
          nullable: true
          description: >-
            Raw shootout tally as the provider sent it (e.g. `5-4`); display
            fallback. Usually absent.
        inPlay:
          type: boolean
          description: >-
            True while the fixture is live — kickoff to the final whistle,
            half-time and other breaks included (read `state`, e.g. `HT`, for a
            pause). False once the match is over.
        provider:
          type: string
          description: >-
            Feed that produced this frame (`api-football`, `statsperform`,
            `lsports`, …), or `final` for the persisted final-score frame kept
            after the game.
        asOf:
          type: string
          description: >-
            ISO-8601 timestamp the frame was observed at the provider. Treat the
            clock as stale when this falls far behind the current time.
        significantEvent:
          type: string
          nullable: true
          description: >-
            Latest significant match event for a one-line badge, e.g. "goal — A.
            Dedić" / "card — …" / "substitution — …" (from Stats Perform Opta
            typeId + player). Sticky: the last event rides through later frames
            until a newer one arrives. Null when none has been reported for this
            fixture.
        sport:
          type: string
          nullable: true
          description: >-
            Sport of the underlying contest as reported by the oracle frame
            ("soccer" | "tennis" | "baseball" | "boxing" | "cricket" | "cs2" |
            "dota2" | "lol" | "valorant" | …). Tells you how to read the frame:
            tennis reports sets instead of a minute clock, cricket innings,
            esports maps. Absent on legacy frames.
        setScores:
          type: string
          nullable: true
          example: 160-0 0-164
          description: >-
            Per-segment score line; the segment semantics follow `sport`.
            Tennis: per-set game scores in play order, e.g. "6-4 3-2" —
            `score`/`scoreText` carry SETS won ("1-0") and `state` the current
            set label ("Set 2"); `minute` stays null. Cricket: space-separated
            per-innings home-away run pairs in innings order, e.g. "160-0 0-164"
            (the batting side's runs land on its own side); the whole-match
            totals travel in `score`/`scoreText`, never as a trailing segment
            here. Esports: `score`/`scoreText` carry MAPS won ("2-1") for all
            four disciplines and `state` is "Map N"/"Live"/"Played"; this field
            is present only for the round-based ones (cs2, valorant) as
            space-separated per-map round scores in map order, e.g. "13-11 10-13
            13-9" — absent on dota2/lol frames (their map periods are a 1-0 flag
            or kills, not a score); the maps-won total is never appended as a
            trailing segment. Absent on football frames and on the persisted
            final-score fallback.
        homeCountry:
          type: string
          nullable: true
          description: >-
            ISO-3166-1 alpha-2 of the HOME player's nationality (tennis flags).
            Absent when the provider carried no usable nationality (uneven
            coverage, doubles, football frames) — render no flag then.
            Live-only, like setScores.
        awayCountry:
          type: string
          nullable: true
          description: >-
            ISO-3166-1 alpha-2 of the AWAY player's nationality — see
            homeCountry.
        inningHalf:
          type: string
          enum:
            - top
            - bottom
          description: >-
            Baseball only: which half of the inning is being played. "top" = the
            AWAY side is batting, "bottom" = the HOME side. Absent outside
            baseball and outside live play.
        balls:
          type: number
          description: >-
            Baseball only: balls in the at-bat in progress (0-3; a 4th walks the
            batter and the count resets). Live-only and NOT sticky — it
            disappears as soon as a frame stops carrying it, so a stale count is
            never shown as current.
        strikes:
          type: number
          description: >-
            Baseball only: strikes in the at-bat in progress (0-2; a 3rd is an
            out and the count resets). Same live-only rule as balls.
        outs:
          type: number
          description: >-
            Baseball only: outs in the current half-inning (0-3; the 3rd ends
            the half). Same live-only rule as balls.
        bases:
          description: >-
            Baseball only: occupied bases as [1st, 2nd, 3rd] — [true,false,true]
            means runners on 1st and 3rd. Reported by MLB/NPB/KBO feeds; mostly
            ABSENT for CPBL and LMB. Absence means UNKNOWN, not "bases empty" —
            render nothing rather than an empty diamond.
          type: array
          items:
            type: boolean
        periodClock:
          type: string
          example: '07:27'
          description: >-
            American football only: time LEFT in the current quarter as "mm:ss"
            (a countdown; "00:00" once the quarter is over — read `state` for
            "HT"). Moves only when the provider sends a frame (the play clock
            stops between plays), so render it verbatim and never tick it down
            locally. Live-only and NOT sticky — absent as soon as a frame stops
            carrying it, and absent outside american football.
      required:
        - state
        - minute
        - addedMinute
        - score
        - scoreText
        - inPlay
        - provider
        - asOf
        - significantEvent
      description: >-
        Live clock + score frame of a fixture. While the game runs it is
        refreshed from the live feed; after the game a persisted final-score
        frame (`provider: "final"`, `state` such as `Played`, `inPlay: false`)
        may remain.
    EventCryptoSeriesDto:
      type: object
      properties:
        id:
          type: string
          description: Key for `GET /api/crypto-series/{id}/windows`.
        symbolPrefix:
          type: string
          description: Symbol namespace for this series, e.g. BTC15M.
        asset:
          type: string
          description: Underlying asset ticker, e.g. BTC.
        instrumentId:
          type: string
          nullable: true
          description: >-
            Public price-catalogue id (e.g. `BTC-USD`) — the key for `GET
            /api/markets/{symbol}/crypto-price-history` and the
            `crypto_price_tick` WebSocket channel. Null on a window minted
            before the instrument was recorded.
          example: BTC-USD
        cadence:
          type: string
          enum:
            - 5-minute
            - 15-minute
            - 30-minute
            - hourly
            - 6-hour
            - daily
            - weekly
          description: >-
            The series' recurrence slug — the vocabulary `/api/events?cadence=`
            accepts. Render labels from this, not from `cadenceSeconds`.
        cadenceSeconds:
          type: integer
          description: >-
            Seconds between consecutive window starts (windows sit on an
            epoch-anchored grid: `floor(t / cadenceSeconds) * cadenceSeconds`).
        windowSeconds:
          type: integer
          description: >-
            Length of one window in seconds. Equal to `cadenceSeconds` on a
            back-to-back schedule, but independent — do not derive one from the
            other.
        streamDecimals:
          type: integer
          description: >-
            Exponent for every unscaled price string on this series
            (`cryptoWindow.openPrice` / `closePrice`, the `crypto_price_tick`
            frame): price = value / 10^streamDecimals. Use a bigint / decimal
            helper — at 18 decimals the integer exceeds
            `Number.MAX_SAFE_INTEGER`.
        titleTemplate:
          type: string
          description: Operator-authored series title template.
      required:
        - id
        - symbolPrefix
        - asset
        - instrumentId
        - cadence
        - cadenceSeconds
        - windowSeconds
        - streamDecimals
        - titleTemplate
    EventCryptoLongSeriesDto:
      type: object
      properties:
        id:
          type: string
          description: Key for GET /crypto-long-series/{id}/periods.
        symbolPrefix:
          type: string
          description: Symbol namespace for this series.
        asset:
          type: string
          description: Underlying asset ticker, e.g. BTC.
        instrumentId:
          type: string
          description: >-
            Public price-catalog id (e.g. BTC-USD) — the key for both
            /markets/{symbol}/crypto-price-history and the crypto_price_tick
            websocket channel. Non-nullable on long series.
        cadence:
          type: string
          enum:
            - 5-minute
            - 15-minute
            - 30-minute
            - hourly
            - 6-hour
            - daily
            - weekly
            - monthly
            - annual
            - one-time
          description: >-
            The series' recurrence slug (lowercase) — the stored column is
            uppercase (DAILY/WEEKLY/MONTHLY), emitted lowercase to match
            `/api/events?frequency=` vocabulary. This field filters on the
            user-facing frequency axis, not the low-level grid-step mechanism
            (`?cadence=`).
        period:
          description: The current period this event belongs to.
          allOf:
            - $ref: '#/components/schemas/CryptoLongPeriodDto'
        periods:
          description: >-
            All currently-listed periods: every non-past period, plus THIS
            event's own period (even when past) — not "the representative",
            which is a collapsed-list concept with no meaning here (there is no
            filter context to be representative of on a single-event response).
            On a past period fetched directly there is no representative at all.
            Hard-capped at 24; use this to render period tabs.
          type: array
          items:
            $ref: '#/components/schemas/PeriodRefDto'
        hasPast:
          type: boolean
          description: True when at least one past period exists for this series.
      required:
        - id
        - symbolPrefix
        - asset
        - instrumentId
        - cadence
        - period
        - periods
        - hasPast
    MarketSummaryDto:
      type: object
      description: >-
        Full public market row. Returned by `GET /api/markets` (list items,
        which also carry `tradeCount` / `totalShares`) and `GET
        /api/markets/{slug}`, in `markets[]` by `GET /api/events/{slug}` and
        `GET /api/events/featured`, and by `GET /api/markets/by-token/{id}`,
        `GET /api/markets/by-condition/{id}` and `GET /api/markets/disputable`.
        `probabilityChange` is only on the Events endpoints. The `GET
        /api/events` list carries a slimmer row — see `EventListMarketDto`.
      properties:
        id:
          type: string
          format: uuid
          description: Internal market UUID.
        eventId:
          type: string
          format: uuid
          description: UUID of the parent event.
        eventSlug:
          type: string
          nullable: true
          description: >-
            Canonical slug of the parent event (the key for `GET
            /api/events/{slug}`).
          example: fifa-world-cup-2026-winner
        homeCountry:
          type: string
          nullable: true
          description: >-
            Home participant's country of the parent event, ISO-3166-1 alpha-2
            (tennis: the player's flag). Null when unknown — normal for events
            without participants and for uneven feed coverage.
        awayCountry:
          type: string
          nullable: true
          description: Away participant's country, ISO-3166-1 alpha-2 — see `homeCountry`.
        tags:
          type: array
          items:
            $ref: '#/components/schemas/EventTagSummaryDto'
          description: >-
            The parent event's active tags (`slug`, `name`), featured first.
            Always an array; empty when the event has none.
        symbol:
          type: string
          description: >-
            Public market symbol — the key for the market sub-resources
            (`/api/markets/{symbol}/orderbook`, `/trades`, `/ohlc`, `/traders`).
          example: FRIENDLI-LIT-AND-MW-20260930-LIT
        slug:
          type: string
          description: Canonical market slug — the key for `GET /api/markets/{slug}`.
          example: friendli-lithuania-andorra-2026-09-30-lit
        title:
          type: string
          description: Display title.
        question:
          type: string
          nullable: true
          description: >-
            Precise yes/no question for this market row (on a neg-risk leg, the
            per-outcome question, e.g. "Will France win the 2026 World Cup?").
            Null ⇒ fall back to `title`.
        groupItemTitle:
          type: string
          nullable: true
          description: >-
            Per-outcome label inside a multi-market event (e.g. `Lithuania`,
            `<20`). Null on standalone markets.
        groupItemSubtitle:
          type: string
          nullable: true
          description: >-
            Display-only second line under `groupItemTitle` (e.g. the artist of
            a song outcome). Never part of the outcome's identity.
        groupItemImageUrl:
          type: string
          nullable: true
          description: >-
            Team or contestant image URL for this row (per outcome on neg-risk
            legs). Display-only; null ⇒ use your own flag or placeholder.
        conditionId:
          type: string
          nullable: true
          description: >-
            CTF conditionId (0x-prefixed bytes32) of a two-outcome market. Null
            on markets with more than two outcomes — read
            `outcomes[].conditionId` there.
        questionId:
          type: string
          nullable: true
          description: CTF questionId (0x-prefixed bytes32).
        yesTokenId:
          type: string
          nullable: true
          description: >-
            ERC-1155 token id of the YES outcome (uint256 as a decimal string)
            on a two-outcome market. Null on markets with more than two outcomes
            — read `outcomes[].tokenId`.
        noTokenId:
          type: string
          nullable: true
          description: >-
            ERC-1155 token id of the NO outcome (uint256 as a decimal string) on
            a two-outcome market. Null on markets with more than two outcomes —
            read `outcomes[].tokenId`.
        outcomes:
          type: array
          items:
            type: object
            properties:
              outcomeIndex:
                type: integer
                description: >-
                  Zero-based outcome index — the join key for `chances`,
                  `outcomePrices`, `outcomeLabels` and
                  `probabilityChange.outcomes`.
              label:
                type: string
                description: >-
                  Display label of this outcome (e.g. `YES`, `Over`, `IND`): an
                  operator-set label when there is one, else the canonical
                  label. Render-only; key all logic on `outcomeIndex`.
              tokenId:
                type: string
                description: >-
                  ERC-1155 token id of this outcome (uint256 as a decimal
                  string).
              noTokenId:
                type: string
                nullable: true
                description: >-
                  ERC-1155 token id of the NO side for this outcome (uint256 as
                  a decimal string). Null on legacy rows.
              conditionId:
                type: string
                nullable: true
                description: CTF conditionId (0x-prefixed bytes32) for this outcome.
            required:
              - outcomeIndex
              - label
              - tokenId
          description: >-
            Per-outcome chain identifiers in outcome-index order: 2 entries on a
            two-outcome market, N on an N-outcome market. The primary source of
            token ids and condition ids. Empty `[]` on some legacy markets.
        outcomeCount:
          type: integer
          description: Number of outcomes (2 on a binary market).
          example: 2
        outcomeLabels:
          type: array
          items:
            type: string
          description: >-
            Canonical outcome labels in index order — the market's immutable
            on-chain identity. Not overlaid with display labels, so
            `outcomeLabels[i]` can differ from `outcomes[i].label`. Never
            string-match on it; join by index.
          example:
            - 'YES'
            - 'NO'
        sourceSelections:
          type: array
          items:
            type: object
            properties:
              outcomeLabel:
                type: string
                description: >-
                  Canonical label of the bound outcome (e.g. `YES`) — not the
                  display label in `outcomes[].label`.
              outcomeIndex:
                type: integer
                nullable: true
                description: >-
                  Index of the bound outcome — join to `outcomes[]` on
                  `outcomeIndex`. Null on malformed legacy rows.
              providerOutcomeId:
                type: string
                description: Stable id of the selection at the data provider.
                example: MATCH_WINNER:side=home
              providerOutcomeName:
                type: string
                nullable: true
                description: Human-readable provider label; display-only.
              marketType:
                type: string
                description: >-
                  Canonical market type of the binding (e.g. `MATCH_WINNER`,
                  `BASEBALL_TOTAL_RUNS`).
              selector:
                type: object
                additionalProperties: true
                description: >-
                  Provider selector with semantic metadata, e.g. `{"line": 8.5,
                  "side": "over"}`.
                example:
                  side: home
            required:
              - outcomeLabel
              - outcomeIndex
              - providerOutcomeId
              - marketType
              - selector
          description: >-
            Machine-readable bindings between outcomes and the data provider's
            selections ("this side means Over 8.5"). Join to `outcomes[]` by
            `outcomeIndex`, never by label. Empty on manual and legacy markets.
        outcomePrices:
          type: array
          items:
            type: string
            nullable: true
          description: >-
            Cost to buy per outcome, in outcome-index order: the best ask when
            the book has an offer, else the last trade; `null` when neither
            exists. Decimal string in USDC. For the implied probability use
            `chances`.
          example:
            - '0.610000'
            - '0.420000'
        chances:
          type: array
          items:
            type: string
          description: >-
            The mark (implied probability) per outcome, in outcome-index order:
            the book midpoint when the book is two-sided and the spread is at
            most $0.10, else the last trade. `1/outcomeCount` per outcome before
            any trade. Never null.
          example:
            - '0.595000'
            - '0.405000'
        probabilityChange:
          nullable: true
          description: >-
            Signed per-outcome movement of `chances` over `window`, in
            percentage points. Returned by the Events endpoints; may be absent
            on other market surfaces. Null when the lookup degraded (best-effort
            — it never fails the request). A per-outcome `change: null` means no
            usable history, not zero.
          allOf:
            - $ref: '#/components/schemas/ProbabilityChangeDto'
        status:
          type: string
          enum:
            - PRE_MARKET
            - OPEN
            - PAUSED
            - POSTPONED
            - SUSPENDED
            - CLOSED
            - PENDING_RESOLUTION
            - DELAYED
            - DISPUTED
            - RESOLVED
            - VOIDED
          description: >-
            Lifecycle status. The open view of `GET /api/events` returns
            PRE_MARKET, OPEN, PAUSED and POSTPONED; closed statuses (SUSPENDED …
            VOIDED) appear on the closed view (`closed=true`), on in-play or
            postponed events, and on the detail endpoints. Use `tradable` to
            decide whether orders are accepted.
          example: OPEN
        tradable:
          type: boolean
          description: >-
            Whether the market accepts new orders right now (derived from
            `status`; a PAUSED market is not tradable). Use this to enable order
            entry instead of switching on `status`.
        tradingMode:
          type: string
          enum:
            - open
            - pre_market_post_only
            - closed
            - paused
            - under_review
            - awaiting_settlement
            - resolved
            - voided
            - delayed
          description: >-
            Trading-mode code derived from `status`, for banners and order-entry
            affordances.
        notTradableReason:
          type: string
          enum:
            - closed_at_cutoff
            - paused
            - suspended
            - postponed
            - awaiting_settlement
            - under_review
            - awaiting_data
            - resolved
            - voided
            - null
          nullable: true
          description: >-
            Machine code for why trading is unavailable; null when `tradable` is
            true. Distinguishes, e.g., a routine operator pause (`paused`) from
            an escalated suspension (`suspended`).
        currentReviewRound:
          type: integer
          description: Current resolution review round (≥ 1).
          example: 1
        feeTakerBps:
          type: integer
          nullable: true
          description: >-
            Per-fill taker fee rate in basis points (k × 10 000; the peak fee at
            P = 0.5 is `feeTakerBps / 4 / 10 000`). Null ⇒ the platform default
            rate applies.
          example: 600
        executionDelayMs:
          type: integer
          nullable: true
          description: >-
            In-play taker execution delay in milliseconds. While it is in force,
            an aggressive order on a live market returns `status=PENDING` with
            an empty `trades[]` and the fills arrive asynchronously on the user
            WebSocket channel (`user_fills`). `0` or null = no delay.
          example: 0
        liveTick:
          type: string
          nullable: true
          description: >-
            In-play price tick (decimal string). While the fixture is in play,
            order prices must be a multiple of it or the order is rejected with
            `in_play_tick_violation`. Null ⇒ the base 0.01 tick applies.
          example: '0.05'
        line:
          type: number
          nullable: true
          description: >-
            The market's numeric line (totals and handicaps) — do not parse it
            out of `title`. On handicaps this is the YES-side line. Null on
            line-less types (winners, BTTS) and on manual or legacy markets. Not
            the same field as `prediction.line` (a string).
          example: 8.5
        lineGroup:
          type: object
          nullable: true
          description: >-
            The line family this market belongs to: markets of one event that
            differ only by their line (Total Runs 7.5 / 8.5 / 9.5, Run Line
            ±1.5, Total Maps 2.5 / 3.5, …). Group by `lineGroup.id` to render
            one card with a line strip, ordering families by `lineGroup.order`.
            Null for line-less types — and for a team-scoped line market whose
            binding names no single side, which still has a non-null `line`.
          properties:
            id:
              type: string
              description: >-
                Family key within the event. Treat as opaque (the market type,
                or `<TYPE>:home` / `<TYPE>:away` for a one-side line).
              example: CRICKET_TEAM_TOTAL_RUNS:home
            title:
              type: string
              description: Card heading for the family.
              example: Jamaica Kingsmen Total Runs
            kind:
              type: string
              enum:
                - total
                - handicap
              description: >-
                Family kind, stated by the server — do not infer it from the
                type name.
            order:
              type: integer
              description: Display rank among the event's families; lowest first.
              example: 0
          required:
            - id
            - title
            - kind
            - order
        kickoff:
          type: string
          format: date-time
          nullable: true
          description: >-
            Real-world start time of the fixture this market is about. Null on
            non-fixture markets.
        tradingWindow:
          description: >-
            Scheduled trading window: `preMarketStartsAt`, `opensAt`,
            `closesAt`.
          allOf:
            - $ref: '#/components/schemas/MarketTradingWindowDto'
        lifecycle:
          description: >-
            Actual lifecycle transition timestamps (`closedAt`, `pausedAt`,
            `resolvedAt`, `voidedAt`); each is null until that transition
            happens.
          allOf:
            - $ref: '#/components/schemas/MarketLifecycleDto'
        resolutionWindowHours:
          type: integer
          nullable: true
          description: Resolution window in hours after kickoff.
          example: 2
        resolution:
          description: >-
            Oracle proposal, dispute and final-outcome state. All fields are
            null until the oracle acts.
          allOf:
            - $ref: '#/components/schemas/MarketResolutionDto'
        payoutNumerators:
          type: array
          items:
            type: integer
          nullable: true
          description: >-
            Per-outcome payout numerators, set when the market resolves (e.g.
            `[1, 0]` = outcome 0 won). Null until then.
          example:
            - 1
            - 0
        officialDataSource:
          type: string
          nullable: true
          description: Primary data provider the market settles from.
          example: lsports
        sourceMatchId:
          type: string
          nullable: true
          description: The provider's id of the fixture or question.
        additionalSources:
          type: array
          items:
            $ref: '#/components/schemas/MarketAdditionalSourceDto'
          description: >-
            Secondary data sources for multi-source resolution (0–1 entries
            today). Empty on single-source markets.
        resolutionCriteria:
          type: string
          nullable: true
          description: Plain-text settlement rules.
        prediction:
          nullable: true
          description: >-
            The vendor prediction question this market was listed on (politics,
            economics, climate, culture, financials, science): question text,
            rung, verbatim resolution rule and a best-effort threshold — the
            structured counterpart of `resolutionCriteria`, as `crypto` is for
            crypto markets. Descriptive only; settlement follows the vendor
            verdict. Null on every other market.
          allOf:
            - $ref: '#/components/schemas/MarketPredictionRuleDto'
        crypto:
          nullable: true
          description: >-
            Machine-readable price rule of a crypto market (product type,
            direction, strike, instrument, window anchor) — the structured
            counterpart of `resolutionCriteria`. Null on every non-crypto
            market. Branch crypto handling on this block being non-null, not on
            `marketType`.
          allOf:
            - $ref: '#/components/schemas/MarketCryptoRuleDto'
        cryptoWindow:
          nullable: true
          description: >-
            Up/Down window facts: bounds, the frozen open price (the price to
            beat), the settled close and the direction. Non-null only on
            short-crypto Up/Down window markets, where it comes with
            `crypto.productType = "UP_DOWN_WINDOW"`.
          allOf:
            - $ref: '#/components/schemas/MarketCryptoWindowDto'
        negRiskEligible:
          type: boolean
          description: >-
            True when this market is one leg of a neg-risk (mutually exclusive)
            group.
        negRiskMarketId:
          type: string
          nullable: true
          description: >-
            Shared id (bytes32) of the neg-risk group — group sibling legs by
            it. Null on standalone markets.
        negRiskQuestionIndex:
          type: integer
          nullable: true
          description: >-
            This leg's index (0 … N−1) within its neg-risk group. Null on
            standalone markets.
        isNewMarketType:
          type: boolean
          description: Reserved flag for the v2 market schema.
        marketType:
          type: string
          nullable: true
          description: >-
            Canonical market type (`MATCH_WINNER`, `BTTS`, `TOTAL_GOALS`,
            `MATCH_WINNER_AET`, `CRYPTO_PRICE_EVENT`, …). Null is common and
            expected: automatically listed crypto Up/Down windows and manual or
            older markets have no type. New values are added over time — treat
            an unknown value as "other", never as an error. Detect crypto
            markets via `crypto`, not this field.
          example: MATCH_WINNER
        sport:
          type: string
          nullable: true
          description: >-
            Sport in the live-score vocabulary (`soccer`, `tennis`, `baseball`,
            `politics`, …) — the same word `live.sport` carries, but available
            before and after the game. For navigation use `vertical`.
          example: soccer
        vertical:
          type: string
          nullable: true
          description: >-
            This market's vertical (`football`, `tennis`, `crypto`, `politics`,
            …) — the value `/api/events?vertical=` filters on.
          example: football
        volume24h:
          type: string
          description: >-
            Traded volume on this market over the last 24 h (USDC notional,
            decimal string); `"0"` when there were no trades.
          example: '1234.50'
        totalVolume:
          type: string
          description: >-
            Lifetime traded volume on this market (USDC notional, decimal
            string); `"0"` when there were no trades.
          example: '98765.00'
        tradeCount:
          type: integer
          description: >-
            Lifetime trade count. Present only on `GET /api/markets` list items
            — absent on every Events endpoint and on market detail.
        totalShares:
          type: string
          description: >-
            Lifetime sum of trade quantities (decimal string). Present only on
            `GET /api/markets` list items — absent on every Events endpoint and
            on market detail.
        createdAt:
          type: string
          format: date-time
          description: Creation time.
        updatedAt:
          type: string
          format: date-time
          description: Last update time.
        live:
          nullable: true
          description: >-
            Live clock + score frame while the fixture is in play. After the
            game a settled market can keep its final-score frame (`provider:
            "final"`, `inPlay: false`). Null when there is no frame (pre-match,
            non-fixture market, no live feed). The key is always present.
          allOf:
            - $ref: '#/components/schemas/MarketLiveStatusDto'
      required:
        - id
        - eventId
        - eventSlug
        - homeCountry
        - awayCountry
        - tags
        - symbol
        - slug
        - title
        - question
        - groupItemTitle
        - groupItemSubtitle
        - groupItemImageUrl
        - conditionId
        - questionId
        - yesTokenId
        - noTokenId
        - outcomes
        - outcomeCount
        - outcomeLabels
        - sourceSelections
        - outcomePrices
        - chances
        - status
        - tradable
        - tradingMode
        - notTradableReason
        - currentReviewRound
        - feeTakerBps
        - executionDelayMs
        - liveTick
        - line
        - lineGroup
        - kickoff
        - tradingWindow
        - lifecycle
        - resolutionWindowHours
        - resolution
        - payoutNumerators
        - officialDataSource
        - sourceMatchId
        - additionalSources
        - resolutionCriteria
        - prediction
        - crypto
        - cryptoWindow
        - negRiskEligible
        - negRiskMarketId
        - negRiskQuestionIndex
        - isNewMarketType
        - marketType
        - sport
        - vertical
        - volume24h
        - totalVolume
        - createdAt
        - updatedAt
        - live
    MarketLiveScoreDto:
      type: object
      properties:
        home:
          type: number
          description: Goals/points for the home side.
        away:
          type: number
          description: Goals/points for the away side.
      required:
        - home
        - away
    CryptoLongPeriodDto:
      type: object
      properties:
        key:
          type: string
          description: Unique key for this period, derived from start_at and cadence.
        label:
          type: string
          description: Display label for the period.
        startAt:
          type: string
          description: ISO-8601 start time of this period.
        endAt:
          type: string
          description: ISO-8601 end time of this period.
        state:
          type: string
          enum:
            - live
            - upcoming
            - past
          description: 'State of this period: live, upcoming, or past.'
      required:
        - key
        - label
        - startAt
        - endAt
        - state
    PeriodRefDto:
      type: object
      properties:
        slug:
          type: string
          description: >-
            Event slug for this period; the period-event identity on
            /api/events/{slug}.
        key:
          type: string
          description: Unique key for this period, derived from start_at and cadence.
        label:
          type: string
          description: Display label for the period.
        startAt:
          type: string
          description: ISO-8601 start time of this period.
        state:
          type: string
          enum:
            - live
            - upcoming
            - past
          description: 'State of this period: live, upcoming, or past.'
      required:
        - slug
        - key
        - label
        - startAt
        - state
    ProbabilityChangeDto:
      type: object
      description: >-
        Per-outcome movement of `chances` over a fixed window, on the same mark
        as `chances`.
      properties:
        window:
          type: string
          enum:
            - 1h
            - 24h
            - 7d
          description: Comparison window. Always `24h` on the Events endpoints.
          example: 24h
        unit:
          type: string
          enum:
            - percentage_points
          description: 'Unit of `change`: percentage points, never relative percent.'
        asOf:
          type: string
          format: date-time
          description: When the changes were computed.
        outcomes:
          type: array
          items:
            $ref: '#/components/schemas/ProbabilityChangeOutcomeDto'
          description: >-
            One entry per outcome, in outcome-index order (the order of
            `chances`), including outcomes whose `change` is null.
      required:
        - window
        - unit
        - asOf
        - outcomes
    MarketTradingWindowDto:
      type: object
      properties:
        preMarketStartsAt:
          type: string
          nullable: true
          description: >-
            ISO-8601 — when PRE_MARKET (post-only) trading opens. Active when
            `tradingMode === 'pre_market_post_only'`. NULL when the market has
            no pre-market window (jumps straight to OPEN).
        opensAt:
          type: string
          nullable: true
          description: >-
            ISO-8601 — when full OPEN trading starts (post-only flips to full
            matching).
        closesAt:
          type: string
          nullable: true
          description: ISO-8601 — trading cutoff after which orders are rejected.
      required:
        - preMarketStartsAt
        - opensAt
        - closesAt
    MarketLifecycleDto:
      type: object
      properties:
        closedAt:
          type: string
          nullable: true
          description: >-
            ISO-8601 — timestamp of the most-recent CLOSED transition. Preserved
            across DELAYED → CLOSED bounces (a market that moved through DELAYED
            → CLOSED again picks the second transition). Distinct from
            `resolvedAt` (terminal RESOLVED) — this is when trading was cut off.
            NULL for markets that have never been CLOSED (DRAFT through OPEN
            inclusive).
        pausedAt:
          type: string
          nullable: true
          description: >-
            ISO-8601 — last pause timestamp. NOT cleared on resume. Set only
            when admin explicitly paused (status PAUSED). Read this when
            `notTradableReason === 'paused'`; for SUSPENDED markets
            (`notTradableReason === 'suspended'`) this field reflects an earlier
            pause if any, NOT the suspension time — `deriveTradingMode` maps
            BOTH PAUSED and SUSPENDED to `tradingMode === 'paused'` but only
            PAUSED writes `paused_at`.
        resolvedAt:
          type: string
          nullable: true
          description: >-
            ISO-8601 — chain-RESOLVED timestamp (terminal). NULL if not
            resolved.
        voidedAt:
          type: string
          nullable: true
          description: >-
            ISO-8601 — chain-VOIDED timestamp (terminal). NULL if not voided. A
            market reaches exactly one terminal state (resolvedAt XOR voidedAt).
      required:
        - closedAt
        - pausedAt
        - resolvedAt
        - voidedAt
    MarketResolutionDto:
      type: object
      properties:
        proposedAt:
          type: string
          nullable: true
          description: >-
            ISO-8601 — when the oracle propose tx was mined. Start of the
            challenge window.
        challengeWindowClosesAt:
          type: string
          nullable: true
          description: >-
            ISO-8601 — exact moment the binary challenge window closes and
            `finalize` becomes legal. Authoritative redeem-countdown anchor (do
            NOT derive from `resolvedAt + resolutionWindowHours`). NULL for
            neg-risk markets — they finalize in one tx without a window.
        disputedAt:
          type: string
          nullable: true
          description: >-
            ISO-8601 — when an opponent opened a dispute. NULL if no dispute
            filed.
        proposedOutcome:
          type: string
          nullable: true
          description: >-
            Outcome label that the oracle has proposed on-chain (e.g.
            'home'/'draw' or numeric index for neg-risk). Non-null only between
            propose and finalize. Pair with `proposedAt` and
            `challengeWindowClosesAt` to render the redeem-countdown UX during
            the challenge window.
        proposedOutcomeIndex:
          type: number
          nullable: true
          description: Numeric outcome index of `proposedOutcome` (uint8 on-chain).
        resolvedOutcome:
          type: string
          nullable: true
          description: >-
            Final outcome label after `RESOLVED`. For redeem amounts read
            `payoutNumerators` (on-chain truth); this is the human-readable
            label.
        resolvedOutcomeIndex:
          type: number
          nullable: true
          description: >-
            0-based index of the resolved outcome in `outcomeLabels`. NULL until
            RESOLVED. Index counterpart of `resolvedOutcome` — enables neg-risk
            consumers to look up token ids in `outcomes[]` without label string
            matching.
        disputeBondUsdcRaw:
          type: string
          nullable: true
          description: >-
            Raw uint string (6-decimal USDC) of the bond the most recent
            challenger posted on this market. Source-of-truth for the "Stake N
            USDC" CTA on the dispute modal. Don't hardcode the bond: the
            oracle's default can change, and this field carries the bond
            actually posted, taken from the most recent on-chain
            `OutcomeChallenged` event. NULL when the market has not yet been
            challenged — for a first challenge read the oracle's current
            `bondAmount()`.
        disputeReason:
          type: string
          nullable: true
          description: >-
            Disputer's free-text reason. Surfaced verbatim. Persists across
            resolution (banner may render on RESOLVED markets too — the field on
            `market_resolution_state` is not cleared at finalize). Not sanitised
            server-side — escape it before rendering as HTML. NULL until
            disputed.
        resolutionKind:
          type: string
          enum:
            - WINNER
            - FAIR_PRICE
            - null
          nullable: true
          description: >-
            Set once the market is RESOLVED: `WINNER` — a single outcome won
            (`resolvedOutcomeIndex` points to it); `FAIR_PRICE` — no single
            winner, `resolvedOutcomeIndex` is null and `payoutNumerators`
            carries the split. Null before resolution.
        proposalKind:
          type: string
          enum:
            - WINNER
            - FAIR_PRICE
            - null
          nullable: true
          description: >-
            Kind of the open oracle proposal while the market is
            PENDING_RESOLUTION or DISPUTED: `WINNER` (`proposedOutcomeIndex`
            points to it) or `FAIR_PRICE` (`proposedFairPriceSplit` carries the
            split and `proposedOutcomeIndex` is null). Null when no proposal is
            open.
        proposedFairPriceSplit:
          type: object
          nullable: true
          description: >-
            Proposed fair-price YES / NO numerators for this market as raw uint
            strings; implied YES price = `yes / (yes + no)`. Set only when
            `proposalKind` is `FAIR_PRICE`.
          properties:
            'yes':
              type: string
              description: YES numerator (raw uint string).
            'no':
              type: string
              description: NO numerator (raw uint string).
          required:
            - 'yes'
            - 'no'
      required:
        - proposedAt
        - challengeWindowClosesAt
        - disputedAt
        - proposedOutcome
        - proposedOutcomeIndex
        - resolvedOutcome
        - resolvedOutcomeIndex
        - disputeBondUsdcRaw
        - disputeReason
    MarketAdditionalSourceDto:
      type: object
      properties:
        provider:
          type: string
          description: Data-provider identifier.
          enum:
            - stats-perform
            - api-football
          example: api-football
        externalEventId:
          type: string
          description: >-
            Provider-specific fixture id — catalogues don't overlap (Stats
            Perform's Opta fixtureId ≠ api-football's fixtureId for the same
            match).
          example: '12345'
        scope:
          type: string
          enum:
            - FIXTURE
            - TOURNAMENT
          description: >-
            Optional per-source scope override; falls back to the binding's
            primary scope when absent.
      required:
        - provider
        - externalEventId
    MarketPredictionRuleDto:
      type: object
      properties:
        version:
          type: integer
          nullable: true
          description: >-
            Shape version stamped by the writer (1 today); null on a blob that
            predates the stamp.
          example: 1
        provider:
          type: string
          description: Feed the question was captured from ("lsports").
        questionId:
          type: string
          description: The vendor's question id — equals `sourceMatchId`.
        question:
          type: string
          description: The vendor's question text, verbatim.
        kind:
          type: string
          description: >-
            "binary" (whole question is the proposition) | "race" (this market
            is one rung — see `line`) | "unnamed".
        line:
          type: string
          nullable: true
          description: >-
            The rung this market sits on ("Above 25%"); null on a binary
            question.
        rulesText:
          type: string
          nullable: true
          description: >-
            The vendor's verbatim resolution rule: threshold, data source,
            observation moment. The authoritative statement — always render it.
            Null when the feed had not stamped it at listing.
        threshold:
          nullable: true
          description: >-
            Best-effort machine reading of `line` (preferred) or `rulesText` —
            e.g. a "price to beat" label. Null when the vendor's wording is not
            one of the recognised shapes; never a settlement input.
          allOf:
            - $ref: '#/components/schemas/MarketPredictionThresholdDto'
        endsAt:
          type: string
          format: date-time
          nullable: true
          description: The vendor's trading close for the question (UTC instant).
        capturedAt:
          type: string
          format: date-time
          nullable: true
          description: When the block was captured from the vendor catalogue (UTC instant).
      required:
        - provider
        - questionId
        - question
        - kind
    MarketCryptoRuleDto:
      type: object
      properties:
        productType:
          type: string
          description: >-
            Product line: `UP_DOWN_WINDOW` (short windows — `cryptoWindow`
            carries the window facts), `CLOSE_ABOVE_AT_TIME`,
            `THRESHOLD_BY_DEADLINE`, `THRESHOLD_DURING_MONTH`, `RANGE_BAND`,
            `NEW_ALL_TIME_HIGH`, `MONTH_OVER_MONTH_CLOSE`,
            `MONTHLY_CLOSE_ABOVE_STRIKE`, `RELATIVE_PERFORMANCE`,
            `BTC_DOMINANCE_AT_MONTH_END`,
            `TOTAL_CRYPTO_MARKET_CAP_AT_MONTH_END`, `MARKET_CAP_MILESTONE`,
            `RANK_MILESTONE`. Open set: newly enabled products appear with no
            API change, so treat unknown values as "other".
        direction:
          type: string
          nullable: true
          enum:
            - ABOVE
            - BELOW
            - null
          description: >-
            `ABOVE` / `BELOW` the strike; null for direction-less products (e.g.
            month-over-month close).
        targetPrice:
          type: string
          nullable: true
          description: >-
            Strike as a canonical decimal string (e.g. "64850"); null for
            strike-less products.
        instrumentId:
          type: string
          nullable: true
          description: >-
            Catalog id of the underlying instrument (see the crypto product
            catalog).
        benchmarkInstrumentId:
          type: string
          nullable: true
          description: >-
            RELATIVE_PERFORMANCE only — catalog id of the comparison leg. Null
            otherwise.
        deadlineAt:
          type: string
          nullable: true
          description: >-
            Deadline products (THRESHOLD_BY_DEADLINE, MARKET_CAP_MILESTONE,
            RANK_MILESTONE) — the deadline as a canonical UTC-minute ISO-8601
            timestamp. Null otherwise.
        month:
          type: string
          nullable: true
          description: >-
            Monthly products only — the observed month as "YYYY-MM", midnight to
            midnight US Eastern time. Null otherwise.
        coinId:
          type: string
          nullable: true
          description: >-
            MARKET_CAP_MILESTONE only — CoinGecko coin id of the asset whose
            market cap is tested. Absent on other products.
        thresholdUsd:
          type: string
          nullable: true
          description: >-
            MARKET_CAP_MILESTONE only — the USD market-cap threshold, canonical
            decimal string. Absent on other products.
        observationStart:
          type: string
          nullable: true
          description: >-
            MARKET_CAP_MILESTONE only — start of the observation window (daily
            observations), ISO-8601. Absent on other products.
        deadline:
          type: string
          nullable: true
          description: >-
            MARKET_CAP_MILESTONE only — end of the observation window, ISO-8601.
            Absent on other products.
        sourcePolicyVersion:
          type: number
          nullable: true
          description: >-
            MARKET_CAP_MILESTONE only — version of the CoinGecko source-policy
            binding the rule was registered against. Absent on other products.
      required:
        - productType
        - direction
        - targetPrice
        - instrumentId
        - benchmarkInstrumentId
        - deadlineAt
        - month
    MarketCryptoWindowDto:
      type: object
      properties:
        seriesId:
          type: string
          description: >-
            Id of the `crypto_market_series` this window belongs to — the key
            for series navigation.
        windowStartAt:
          type: string
          nullable: true
          description: >-
            Window start, ISO-8601 — the economic period the open/close
            boundaries bracket.
        windowEndAt:
          type: string
          nullable: true
          description: Window end, ISO-8601.
        openPrice:
          type: string
          nullable: true
          description: >-
            The FROZEN open price — the "price to beat", the exact value
            settlement binds. Unscaled integer as a decimal string: scale by
            `streamDecimals` and never parse it into a JS number (at 18 decimals
            it exceeds Number.MAX_SAFE_INTEGER). Null until the oracle freezes
            it (window start + freeze grace).
        streamDecimals:
          type: number
          nullable: true
          description: >-
            Decimal exponent for `openPrice` and `closePrice`, from the series'
            stream decimals: price = value / 10 ** streamDecimals. Present
            whenever the series link is.
        openPriceIsFinal:
          type: boolean
          description: >-
            Whether `openPrice` can no longer change. Structurally `openPrice
            !== null` (the pin is write-once); kept explicit to hold the
            contract stable.
        closePrice:
          type: string
          nullable: true
          description: >-
            The close-boundary price settlement bound — same units and string
            discipline as `openPrice`. Null until the oracle acts on the window;
            present from proposal time, so it can be visible while the outcome
            is still challengeable.
        closePriceIsFinal:
          type: boolean
          description: >-
            True only once the market is RESOLVED with a close price present.
            `closePrice` may be shown earlier, but must not be labelled final
            until this flips.
        outcome:
          type: string
          nullable: true
          enum:
            - UP
            - DOWN
            - null
          description: >-
            Settled direction once the market is RESOLVED (`UP` = outcome slot 0
            = YES, `DOWN` = slot 1 = NO). Null while a proposal is still
            disputable — a proposed direction is not a settled one.
      required:
        - seriesId
        - windowStartAt
        - windowEndAt
        - openPrice
        - streamDecimals
        - openPriceIsFinal
        - closePrice
        - closePriceIsFinal
        - outcome
    ProbabilityChangeOutcomeDto:
      type: object
      properties:
        outcomeIndex:
          type: integer
          description: >-
            Index of the outcome — positionally the same outcome as
            `chances[i]`, `outcomePrices[i]` and `outcomeLabels[i]`.
          example: 0
        change:
          type: number
          nullable: true
          description: >-
            Signed movement in percentage points over `window` (0.27 → 0.32 is
            `5`, not +18.5 % relative), rounded to 2 decimal places. `0` means
            measured and unchanged; `null` means not enough history (e.g. a
            brand-new market) — show "no data", never zero.
          example: 4
        baselineAt:
          type: string
          format: date-time
          nullable: true
          description: >-
            Time of the baseline observation `change` was measured against. Null
            exactly when `change` is null.
      required:
        - outcomeIndex
        - change
        - baselineAt
    MarketPredictionThresholdDto:
      type: object
      properties:
        comparator:
          type: string
          description: ABOVE | BELOW | AT_OR_ABOVE | AT_OR_BELOW | BETWEEN | EQUAL.
        value:
          type: string
          description: Decimal string, never a float ("0.5", "25", "26390").
        upperValue:
          type: string
          nullable: true
          description: Upper bound for BETWEEN; null otherwise.
        unit:
          type: string
          nullable: true
          description: '"%", "USD", "°" … or null when the wording names none.'
        source:
          type: string
          description: >-
            Which text the reading came from: "line" (the rung) or "rules"
            (vendor prose).
      required:
        - comparator
        - value
        - source

````

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