openapi: 3.0.3
info:
  title: Gemini Prediction Markets API
  description: |
    API for trading prediction market contracts on Gemini.

    **Note:** Only fields documented in this specification are considered stable. Undocumented fields in API responses may change or be removed without notice.
  version: 1.0.0
  contact:
    name: Gemini API Support

servers:
  - url: https://api.gemini.com
    description: Production
  - url: https://api.sandbox.gemini.com
    description: Sandbox

tags:
  - name: Markets
    description: |
      Public endpoints for browsing prediction markets.

      **Market Data:** Use these REST endpoints to discover active events and each contract's `instrumentSymbol` (e.g., `GEMI-FEDJAN26-DN25`). For active trading and market making, prefer [Prediction Markets WebSocket streams](/prediction-markets/websocket/streams) with that `instrumentSymbol`.
      - [List Events](/rest-api/prediction-markets/events/list-events) - Discover active events and instrument symbols
      - [Prediction Markets WebSocket Streams](/prediction-markets/websocket/streams) - Stream prices, depth, order events, and positions
  - name: Terms
    description: Read, check, and accept the latest Prediction Markets terms for API key and OAuth trading flows.
  - name: Trading
    description: Authenticated REST endpoints for placing and managing orders. Treat REST order placement as payload reference or a one-off server workflow; for active trading and market making, prefer WebSocket order.place.
  - name: Positions
    description: Authenticated endpoints for viewing positions and order history. Use REST positions for recovery or audit snapshots after reconnects, missed WebSocket messages, and settlement windows.
  - name: Combos
    description: Public endpoints for discovering and inspecting combo contracts. Combos are pre-packaged multi-leg contracts; order entry uses the same place/cancel endpoints as single contracts.
  - name: Rewards
    description: |
      Endpoints for the Maker Rebate and Liquidity Rewards programs.

      - **Maker Rebate** — per-fill rebates earned by resting limit orders that get filled. Rates and rebate multipliers are configured per category. Public rate schedule plus authenticated payout and summary endpoints.
      - **Liquidity Rewards** — daily USD reward pools distributed across qualifying makers based on quote uptime, spread, and size. Public config + event listing, authenticated daily and lifetime summary endpoints.

      When a program is not active, its endpoints return `503 Service Unavailable`.

      **Note on field naming.** Response fields under the Rewards endpoints use `snake_case` (e.g. `event_ticker`, `daily_pool_usd`). This differs from the `camelCase` convention used by the rest of the Prediction Markets REST endpoints.

paths:
  /v1/prediction-markets/events:
    get:
      tags:
        - Markets
      summary: List prediction market events
      description: Returns a paginated list of prediction market events with optional filtering by status, category, and search text.
      operationId: listEvents
      parameters:
        - name: status
          in: query
          description: Filter by event status (can specify multiple)
          schema:
            type: array
            items:
              $ref: '#/components/schemas/MarketStatus'
          style: form
          explode: true
        - name: category
          in: query
          description: Filter by category (can specify multiple). If omitted, returns events from all categories.
          schema:
            type: array
            items:
              type: string
          style: form
          explode: true
        - name: search
          in: query
          description: Search text to filter events by title
          schema:
            type: string
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventsResponse'
              examples:
                activeEvents:
                  summary: List of active events
                  value:
                    data:
                      - id: "evt_123"
                        title: "Will Bitcoin reach $100k by end of 2028?"
                        slug: "bitcoin-100k-2028"
                        description: "Bitcoin must reach $100,000 USD on any major exchange by December 31, 2028"
                        imageUrl: "https://example.com/btc.png"
                        type: "binary"
                        category: "crypto"
                        series: null
                        ticker: "BTC100K2028"
                        status: "active"
                        resolvedAt: null
                        createdAt: "2026-01-01T00:00:00.000Z"
                        effectiveDate: "2026-01-01T00:00:00.000Z"
                        expiryDate: "2028-12-31T23:59:59.000Z"
                        liquidity: "500000.00"
                        tags: ["bitcoin", "cryptocurrency", "price-prediction"]
                        contracts:
                          - id: "contract_123"
                            label: "Yes"
                            description: null
                            prices:
                              buy:
                                "yes": "0.65"
                                "no": "0.35"
                              sell:
                                "yes": "0.65"
                                "no": "0.35"
                              bestBid: "0.64"
                              bestAsk: "0.66"
                              lastTradePrice: "0.65"
                            totalShares: "1000000"
                            color: "#00ff00"
                            status: "active"
                            imageUrl: null
                            priceHistory: null
                            createdAt: "2026-01-01T00:00:00.000Z"
                            expiryDate: "2028-12-31T23:59:59.000Z"
                            resolutionSide: null
                            resolvedAt: null
                            termsAndConditionsUrl: "https://example.com/terms"
                            ticker: "BTC100K-YES"
                            instrumentSymbol: "GEMI-BTC100K-YES"
                            effectiveDate: "2026-01-01T00:00:00.000Z"
                          - id: "contract_124"
                            label: "No"
                            description: null
                            prices:
                              buy:
                                "yes": "0.35"
                                "no": "0.65"
                              sell:
                                "yes": "0.35"
                                "no": "0.65"
                              bestBid: "0.34"
                              bestAsk: "0.36"
                              lastTradePrice: "0.35"
                            totalShares: "1000000"
                            color: "#ff0000"
                            status: "active"
                            imageUrl: null
                            priceHistory: null
                            createdAt: "2026-01-01T00:00:00.000Z"
                            expiryDate: "2028-12-31T23:59:59.000Z"
                            resolutionSide: null
                            resolvedAt: null
                            termsAndConditionsUrl: "https://example.com/terms"
                            ticker: "BTC100K-NO"
                            instrumentSymbol: "GEMI-BTC100K-NO"
                            effectiveDate: "2026-01-01T00:00:00.000Z"
                      - id: "evt_124"
                        title: "Will ETH reach $5k by end of 2028?"
                        slug: "ethereum-5k-2028"
                        description: "Ethereum must reach $5,000 USD on any major exchange by December 31, 2028"
                        imageUrl: "https://example.com/eth.png"
                        type: "binary"
                        category: "crypto"
                        series: null
                        ticker: "ETH5K2028"
                        status: "active"
                        resolvedAt: null
                        createdAt: "2026-01-01T00:00:00.000Z"
                        effectiveDate: "2026-01-01T00:00:00.000Z"
                        expiryDate: "2028-12-31T23:59:59.000Z"
                        liquidity: "300000.00"
                        tags: ["ethereum", "cryptocurrency", "price-prediction"]
                        contracts:
                          - id: "contract_125"
                            label: "Yes"
                            description: null
                            prices:
                              buy:
                                "yes": "0.48"
                                "no": "0.52"
                              sell:
                                "yes": "0.48"
                                "no": "0.52"
                              bestBid: "0.47"
                              bestAsk: "0.49"
                              lastTradePrice: "0.48"
                            totalShares: "800000"
                            color: "#00ff00"
                            status: "active"
                            imageUrl: null
                            priceHistory: null
                            createdAt: "2026-01-01T00:00:00.000Z"
                            expiryDate: "2028-12-31T23:59:59.000Z"
                            resolutionSide: null
                            resolvedAt: null
                            termsAndConditionsUrl: "https://example.com/terms"
                            ticker: "ETH5K-YES"
                            instrumentSymbol: "GEMI-ETH5K-YES"
                            effectiveDate: "2026-01-01T00:00:00.000Z"
                          - id: "contract_126"
                            label: "No"
                            description: null
                            prices:
                              buy:
                                "yes": "0.52"
                                "no": "0.48"
                              sell:
                                "yes": "0.52"
                                "no": "0.48"
                              bestBid: "0.51"
                              bestAsk: "0.53"
                              lastTradePrice: "0.52"
                            totalShares: "800000"
                            color: "#ff0000"
                            status: "active"
                            imageUrl: null
                            priceHistory: null
                            createdAt: "2026-01-01T00:00:00.000Z"
                            expiryDate: "2028-12-31T23:59:59.000Z"
                            resolutionSide: null
                            resolvedAt: null
                            termsAndConditionsUrl: "https://example.com/terms"
                            ticker: "ETH5K-NO"
                            instrumentSymbol: "GEMI-ETH5K-NO"
                            effectiveDate: "2026-01-01T00:00:00.000Z"
                    pagination:
                      limit: 50
                      offset: 0
                      total: 2
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/events/{eventTicker}:
    get:
      tags:
        - Markets
      summary: Get event by ticker
      description: Returns detailed information about a specific prediction market event.
      operationId: getEvent
      parameters:
        - name: eventTicker
          in: path
          required: true
          description: The event ticker symbol (e.g., "BTC100K")
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Event'
        '404':
          description: Event not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/events/{eventTicker}/strike:
    get:
      tags:
        - Markets
      summary: Get strike price for event
      description: |
        Returns strike price information for a specific prediction market event.

        Useful for crypto Up/Down contracts where the strike price becomes available at the start of the observation window (typically ~5 minutes before expiry for 5M contracts).

        For Up/Down contracts, the `value` field will be `null` until the strike is captured at `availableAt` time.
      operationId: getEventStrike
      parameters:
        - name: eventTicker
          in: path
          required: true
          description: The event ticker symbol (e.g., "BTC05M2603271950")
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Strike'
              examples:
                strikeAvailable:
                  summary: Strike price captured
                  value:
                    value: "98000.50"
                    type: "reference"
                    availableAt: "2026-03-27T19:45:00.000Z"
                strikePending:
                  summary: Strike pending (pre-T-0)
                  value:
                    value: null
                    type: "reference"
                    availableAt: "2026-03-27T19:45:00.000Z"
        '404':
          description: Strike not found (event doesn't exist or doesn't have strike data)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "Strike not found"
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/events/newly-listed:
    get:
      tags:
        - Markets
      summary: List newly listed events
      description: Returns a list of prediction market events created in the last 24 hours, sorted by creation date (newest first).
      operationId: listNewlyListedEvents
      parameters:
        - name: category
          in: query
          description: Filter by category (can specify multiple). If omitted, returns events from all categories.
          schema:
            type: array
            items:
              type: string
          style: form
          explode: true
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventsResponse'
              examples:
                newlyListedEvents:
                  summary: Newly listed events
                  value:
                    data:
                      - id: "4126"
                        title: "SOL price today at 12am EST"
                        slug: "sol-price-today-at-12am-est"
                        description: "Interval SOL price prediction event"
                        imageUrl: "https://images.ctfassets.net/example.png"
                        type: "categorical"
                        category: "Crypto"
                        series: "SOL1H"
                        ticker: "SOL2603050500"
                        status: "active"
                        resolvedAt: null
                        createdAt: "2026-03-05T02:57:31.548Z"
                        effectiveDate: null
                        expiryDate: "2026-03-05T05:00:00.000Z"
                        liquidity: null
                        tags: ["Solana"]
                        contracts:
                          - id: "4126-33859"
                            label: "SOL > $90"
                            abbreviatedName: ">$90"
                            description: null
                            prices:
                              buy:
                                "yes": "0.42"
                                "no": "0.58"
                              sell:
                                "yes": "0.42"
                                "no": "0.58"
                              bestBid: "0.49"
                              bestAsk: "0.54"
                              lastTradePrice: "0.75"
                            totalShares: null
                            color: "#4CAF50"
                            status: "active"
                            imageUrl: null
                            priceHistory: null
                            createdAt: "2026-03-05T02:57:31.548Z"
                            expiryDate: "2026-03-05T05:00:00.000Z"
                            resolutionSide: null
                            resolvedAt: null
                            termsAndConditionsUrl: "https://example.com/terms"
                            ticker: "HI90"
                            instrumentSymbol: "GEMI-SOL2603050500-HI90"
                            effectiveDate: null
                            marketState: "open"
                            sortOrder: 1
                    pagination:
                      limit: 50
                      offset: 0
                      total: 1
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/events/recently-settled:
    get:
      tags:
        - Markets
      summary: List recently settled events
      description: Returns a list of prediction market events settled in the last 24 hours, sorted by resolution date (most recently settled first).
      operationId: listRecentlySettledEvents
      parameters:
        - name: category
          in: query
          description: Filter by category (can specify multiple). If omitted, returns events from all categories.
          schema:
            type: array
            items:
              type: string
          style: form
          explode: true
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventsResponse'
              examples:
                recentlySettledEvents:
                  summary: Recently settled events
                  value:
                    data:
                      - id: "4100"
                        title: "SOL price today at 4am EST"
                        slug: "sol-price-today-at-4am-est"
                        description: "Interval SOL price prediction event"
                        imageUrl: "https://images.ctfassets.net/example.png"
                        type: "categorical"
                        category: "Crypto"
                        series: "SOL1H"
                        ticker: "SOL2603050400"
                        status: "settled"
                        resolvedAt: "2026-03-05T04:00:21.400Z"
                        createdAt: "2026-03-05T01:57:31.548Z"
                        effectiveDate: null
                        expiryDate: "2026-03-05T04:00:00.000Z"
                        liquidity: null
                        tags: ["Solana"]
                        contracts:
                          - id: "4100-33800"
                            label: "SOL > $90"
                            abbreviatedName: ">$90"
                            description: null
                            prices:
                              buy: {}
                              sell: {}
                              bestBid: null
                              bestAsk: null
                              lastTradePrice: "0.80"
                            totalShares: null
                            color: "#4CAF50"
                            status: "settled"
                            imageUrl: null
                            priceHistory: null
                            createdAt: "2026-03-05T01:57:31.548Z"
                            expiryDate: "2026-03-05T04:00:00.000Z"
                            resolutionSide: "yes"
                            resolvedAt: "2026-03-05T04:00:21.400Z"
                            termsAndConditionsUrl: "https://example.com/terms"
                            ticker: "HI90"
                            instrumentSymbol: "GEMI-SOL2603050400-HI90"
                            effectiveDate: null
                            marketState: "closed"
                            sortOrder: 1
                    pagination:
                      limit: 50
                      offset: 0
                      total: 1
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/events/upcoming:
    get:
      tags:
        - Markets
      summary: List upcoming events
      description: Returns a list of approved prediction market events that are not yet active (pre-launch), sorted by start time (soonest first).
      operationId: listUpcomingEvents
      parameters:
        - name: category
          in: query
          description: Filter by category (can specify multiple). If omitted, returns events from all categories.
          schema:
            type: array
            items:
              type: string
          style: form
          explode: true
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventsResponse'
              examples:
                upcomingEvents:
                  summary: Upcoming events
                  value:
                    data:
                      - id: "4200"
                        title: "Lakers vs Celtics"
                        slug: "lakers-vs-celtics-march-10"
                        description: "NBA game prediction market"
                        imageUrl: "https://images.ctfassets.net/example.png"
                        type: "binary"
                        category: "Sports"
                        series: null
                        ticker: "NBA260310LAL-BOS"
                        status: "approved"
                        resolvedAt: null
                        createdAt: "2026-03-04T12:00:00.000Z"
                        effectiveDate: "2026-03-10T19:30:00.000Z"
                        expiryDate: "2026-03-11T02:00:00.000Z"
                        liquidity: null
                        tags: ["NBA", "Basketball"]
                        subcategory:
                          id: 10
                          slug: "sports_nba"
                          name: "NBA"
                          path: ["Sports", "NBA"]
                        contracts:
                          - id: "4200-1"
                            label: "Lakers Win"
                            abbreviatedName: "LAL"
                            description: null
                            prices:
                              buy: {}
                              sell: {}
                              bestBid: null
                              bestAsk: null
                              lastTradePrice: null
                            totalShares: null
                            color: "#552583"
                            status: "approved"
                            imageUrl: null
                            priceHistory: null
                            createdAt: "2026-03-04T12:00:00.000Z"
                            expiryDate: "2026-03-11T02:00:00.000Z"
                            resolutionSide: null
                            resolvedAt: null
                            termsAndConditionsUrl: "https://example.com/terms"
                            ticker: "LAL"
                            instrumentSymbol: "GEMI-NBA260310LAL-BOS-LAL"
                            effectiveDate: "2026-03-10T19:30:00.000Z"
                            marketState: "closed"
                            sortOrder: 1
                    pagination:
                      limit: 50
                      offset: 0
                      total: 1
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/categories:
    get:
      tags:
        - Markets
      summary: List event categories
      description: Returns available prediction market event categories, optionally filtered by event status.
      operationId: getCategories
      parameters:
        - name: status
          in: query
          description: Filter categories by event status
          schema:
            type: array
            items:
              $ref: '#/components/schemas/MarketStatus'
          style: form
          explode: true
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  categories:
                    type: array
                    items:
                      type: string
                    example: ["sports", "politics", "crypto", "entertainment"]
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/terms:
    get:
      tags:
        - Terms
      summary: Get prediction market terms
      description: Returns the latest Prediction Markets terms content. This endpoint is public so clients can display the terms before asking an authenticated account to accept them.
      operationId: getPredictionMarketsTerms
      responses:
        '200':
          description: Latest Prediction Markets terms
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PredictionMarketsTerms'
              examples:
                terms:
                  summary: Latest terms
                  value:
                    termsType: "PredictionsMarket"
                    version: 3
                    content: "These are the prediction market terms."
                    updatedAt: "2026-05-18T17:00:00Z"
        '404':
          description: No Prediction Markets terms are configured
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "TermsNotFound"
                message: "No terms configured for prediction markets"
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/prediction-markets/terms/status:
    get:
      tags:
        - Terms
      summary: Get prediction market terms status
      description: Returns whether the authenticated account group has accepted the latest Prediction Markets terms. Requires authentication and OrderStatus permission.
      operationId: getPredictionMarketsTermsStatus
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      responses:
        '200':
          description: Terms acceptance status
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PredictionMarketsTermsStatus'
              examples:
                accepted:
                  summary: Latest terms accepted
                  value:
                    hasAcceptedLatest: true
                    acceptedVersion: 3
                    latestVersion: 3
                needsAcceptance:
                  summary: Latest terms not accepted
                  value:
                    hasAcceptedLatest: false
                    acceptedVersion: 2
                    latestVersion: 3
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/prediction-markets/terms/accept:
    post:
      tags:
        - Terms
      summary: Accept prediction market terms
      description: Accepts the latest configured Prediction Markets terms for the authenticated account group. Requires authentication and NewOrder permission. The actor is recorded from the OAuth client when OAuth is used, otherwise from the API key session.
      operationId: acceptPredictionMarketsTerms
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      responses:
        '200':
          description: Terms accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AcceptPredictionMarketsTermsResponse'
              example:
                success: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: No Prediction Markets terms are configured
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "TermsNotFound"
                message: "No terms configured for prediction markets"
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/prediction-markets/order:
    post:
      tags:
        - Trading
      summary: Place order
      description: |
        Place a new prediction market order. Supports limit and stop-limit order types. Requires authentication and NewOrder permission.

        Before sending orders, check `GET /v1/prediction-markets/terms/status`. If `hasAcceptedLatest` is `false`, display `GET /v1/prediction-markets/terms` and call `POST /v1/prediction-markets/terms/accept`, then retry the order.

        ### Stop-Limit Orders
        A stop-limit order is an order type that allows for order placement when a price reaches a specified level. Stop-limit orders take in both a `price` and a `stopPrice` as parameters. The `stopPrice` is the price that triggers the order to be placed on the continuous live order book at the `price`. For buy orders, the `stopPrice` must be greater than or equal to the last trade price and less than or equal to the `price`; for sell orders, the `stopPrice` must be less than or equal to the last trade price and greater than or equal to the `price`. Both `price` and `stopPrice` must be in the 0-1 range.
      operationId: placeOrder
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderRequest'
            examples:
              buyYes:
                summary: Buy YES contract
                description: Place a limit order to buy 100 YES contracts at 0.65
                value:
                  symbol: "GEMI-FEDJAN26-DN25"
                  orderType: "limit"
                  side: "buy"
                  quantity: "100"
                  price: "0.65"
                  outcome: "yes"
                  timeInForce: "good-til-cancel"
              sellNo:
                summary: Sell NO contract
                description: Place a limit order to sell 50 NO contracts at 0.35
                value:
                  symbol: "GEMI-FEDJAN26-DN25"
                  orderType: "limit"
                  side: "sell"
                  quantity: "50"
                  price: "0.35"
                  outcome: "no"
                  timeInForce: "good-til-cancel"
              makerOnly:
                summary: Maker-only order (post-only)
                description: Place a maker-only order that will be cancelled if it would match immediately. Useful for ensuring you provide liquidity and qualify for maker rebates.
                value:
                  symbol: "GEMI-FEDJAN26-DN25"
                  orderType: "limit"
                  side: "buy"
                  quantity: "100"
                  price: "0.55"
                  outcome: "yes"
                  timeInForce: "good-til-cancel"
                  makerOrCancel: true
              buyYesStopLimit:
                summary: Buy YES stop-limit
                description: Place a stop-limit order to buy 100 YES contracts at 0.70 once the market reaches the stop trigger of 0.65.
                value:
                  symbol: "GEMI-FEDJAN26-DN25"
                  orderType: "stop-limit"
                  side: "buy"
                  quantity: "100"
                  price: "0.70"
                  stopPrice: "0.65"
                  outcome: "yes"
                  timeInForce: "good-til-cancel"
              sellNoStopLimit:
                summary: Sell NO stop-limit
                description: Place a stop-limit order to sell 50 NO contracts at 0.40 once the market falls to the stop trigger of 0.45.
                value:
                  symbol: "GEMI-FEDJAN26-DN25"
                  orderType: "stop-limit"
                  side: "sell"
                  quantity: "50"
                  price: "0.40"
                  stopPrice: "0.45"
                  outcome: "no"
                  timeInForce: "good-til-cancel"
      responses:
        '201':
          description: Order created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderResponse'
              examples:
                orderPlaced:
                  summary: Order successfully placed
                  value:
                    orderId: 12345678901
                    status: "open"
                    symbol: "GEMI-FEDJAN26-DN25"
                    side: "buy"
                    outcome: "yes"
                    orderType: "limit"
                    quantity: "100"
                    filledQuantity: "0"
                    remainingQuantity: "100"
                    price: "0.65"
                    avgExecutionPrice: null
                    createdAt: "2025-12-15T10:30:00.000Z"
                    updatedAt: "2025-12-15T10:30:00.000Z"
                    cancelledAt: null
                    contractMetadata:
                      contractId: "contract_123"
                      contractName: "FEDJAN26-DN25"
                      contractTicker: "FEDJAN26-DN25"
                      eventTicker: "FEDJAN26"
                      eventName: "Will Fed Funds Rate drop at least 0.25% at January 2026 meeting?"
                      category: "economics"
                      contractStatus: "active"
                      imageUrl: "https://example.com/fed.png"
                      expiryDate: "2026-01-31T23:59:59.000Z"
                      resolvedAt: null
                      description: "Resolves YES if Federal Reserve lowers the target rate by 0.25% or more at the January 2026 FOMC meeting"
                stopLimitOrderPlaced:
                  summary: Stop-limit order successfully placed
                  value:
                    orderId: 12345678902
                    status: "open"
                    symbol: "GEMI-FEDJAN26-DN25"
                    side: "buy"
                    outcome: "yes"
                    orderType: "stop-limit"
                    quantity: "100"
                    filledQuantity: "0"
                    remainingQuantity: "100"
                    price: "0.70"
                    stopPrice: "0.65"
                    avgExecutionPrice: null
                    createdAt: "2025-12-15T10:30:00.000Z"
                    updatedAt: "2025-12-15T10:30:00.000Z"
                    cancelledAt: null
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          description: Order rejected (e.g., insufficient funds)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/order/batch:
    post:
      tags:
        - Trading
      summary: Place a batch of orders
      description: |
        Place between 1 and 20 prediction market orders in one authenticated request. The complete payload is signed once using the standard private REST authentication headers. Each entry accepts the same fields as `POST /v1/prediction-markets/order`.

        The operation is synchronous and non-atomic. Gemini validates the entire batch before submitting any orders. If the batch or any entry fails up-front validation, the request fails and no orders are submitted. After validation succeeds, orders are submitted sequentially and each result is returned in request order. An exchange rejection for one order does not stop later orders from being submitted; it appears as an `error` and `message` for that entry in the `200` response.
      operationId: placeOrderBatch
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlaceOrderBatchRequest'
            examples:
              twoOrders:
                summary: Place two orders
                value:
                  orders:
                    - symbol: "GEMI-FEDJAN26-DN25"
                      orderType: "limit"
                      side: "buy"
                      quantity: "100"
                      price: "0.65"
                      outcome: "yes"
                      timeInForce: "good-til-cancel"
                    - symbol: "GEMI-FEDJAN26-DN25"
                      orderType: "limit"
                      side: "sell"
                      quantity: "50"
                      price: "0.35"
                      outcome: "no"
                      timeInForce: "good-til-cancel"
      responses:
        '200':
          description: Batch processed. Results are returned in request order and may contain both successful orders and per-entry errors.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlaceOrderBatchResponse'
              examples:
                partialSuccess:
                  summary: One order accepted and one order rejected
                  value:
                    results:
                      - order:
                          orderId: 12345678901
                          status: "open"
                          symbol: "GEMI-FEDJAN26-DN25"
                          side: "buy"
                          outcome: "yes"
                          orderType: "limit"
                          timeInForce: "good-til-cancel"
                          quantity: "100"
                          filledQuantity: "0"
                          remainingQuantity: "100"
                          price: "0.65"
                          createdAt: "2025-12-15T10:30:00.000Z"
                          updatedAt: "2025-12-15T10:30:00.000Z"
                      - error: "InsufficientFunds"
                        message: "Insufficient funds"
        '400':
          description: Invalid payload, empty batch, more than 20 entries, or an invalid order. No orders are submitted.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/AuthErrorResponse'
                  - $ref: '#/components/schemas/PredictionMarketsError'
        '401':
          description: Authentication is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthErrorResponse'
        '403':
          description: The account is not permitted to place orders or has not accepted the current Prediction Markets terms. No orders are submitted.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/AuthErrorResponse'
                  - $ref: '#/components/schemas/AccountGroupBlockedError'
                  - $ref: '#/components/schemas/TermsNotAcceptedError'
                  - $ref: '#/components/schemas/RestrictedSellOnlyError'
        '409':
          description: The request nonce conflicts with a previously submitted request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthErrorResponse'
        '422':
          description: An order failed an up-front risk check. No orders are submitted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PredictionMarketsError'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PredictionMarketsError'
        '503':
          description: Prediction markets or batch orders are temporarily unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PredictionMarketsError'

  /v1/prediction-markets/order/cancel:
    post:
      tags:
        - Trading
      summary: Cancel order
      description: Cancel an existing prediction market order. Requires authentication and CancelOrder permission.
      operationId: cancelOrder
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - orderId
              properties:
                orderId:
                  type: integer
                  format: int64
                  description: The order ID to cancel
                  example: 12345678
      responses:
        '200':
          description: Order cancelled successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  result:
                    type: string
                    example: "ok"
                  message:
                    type: string
                    example: "Order 12345678 cancelled successfully"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Order not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Order cannot be cancelled (e.g., already filled)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/order/batch/cancel:
    post:
      tags:
        - Trading
      summary: Cancel a batch of orders
      description: |
        Cancel between 1 and 20 prediction market orders in one authenticated request. The complete payload is signed once using the standard private REST authentication headers. Each order ID may be a JSON integer or a quoted numeric string.

        The operation is synchronous and non-atomic. Gemini validates all order IDs before attempting any cancellation. If the batch is empty, contains more than 20 entries, or contains an invalid ID, the request fails and no orders are cancelled. After validation succeeds, cancellations are attempted sequentially and each result is returned in request order. A rejection for one cancellation does not stop later cancellations from being attempted; it appears as an `error` and `message` for that entry in the `200` response.
      operationId: cancelOrderBatch
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CancelOrderBatchRequest'
            examples:
              twoOrders:
                summary: Cancel two orders
                value:
                  orderIds:
                    - 12345678
                    - "12345679"
      responses:
        '200':
          description: Batch processed. Results are returned in request order and may contain both successful cancellations and per-entry errors.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CancelOrderBatchResponse'
              examples:
                partialSuccess:
                  summary: One order cancelled and one order not found
                  value:
                    results:
                      - orderId: 12345678
                        result: "ok"
                      - orderId: 12345679
                        error: "OrderNotFound"
                        message: "Order 12345679 not found"
        '400':
          description: Invalid payload, empty batch, more than 20 entries, or an invalid order ID. No orders are cancelled.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/AuthErrorResponse'
                  - $ref: '#/components/schemas/PredictionMarketsError'
        '401':
          description: Authentication is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthErrorResponse'
        '403':
          description: The account is not permitted to cancel orders.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthErrorResponse'
        '409':
          description: The request nonce conflicts with a previously submitted request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PredictionMarketsError'
        '503':
          description: Prediction markets or batch orders are temporarily unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PredictionMarketsError'

  # /v1/prediction-markets/order/quote:
  #   get:
  #     tags:
  #       - Trading
  #     summary: Get price quote
  #     description: |
  #       Get a price quote for buying/selling contracts. Provide either `shares` OR `totalSpend`, not both.
  #       Requires authentication.
  #     operationId: getQuote
  #     security:
  #       - apiKey: []
  #     parameters:
  #       - name: symbol
  #         in: query
  #         required: true
  #         description: The contract instrument symbol
  #         schema:
  #           type: string
  #           example: "GEMI-BTC100K-YES"
  #       - name: shares
  #         in: query
  #         description: Number of shares to quote (mutually exclusive with totalSpend)
  #         schema:
  #           type: string
  #           example: "100"
  #       - name: totalSpend
  #         in: query
  #         description: Total amount to spend in USD (mutually exclusive with shares)
  #         schema:
  #           type: string
  #           example: "50.00"
  #     responses:
  #       '200':
  #         description: Successful quote
  #         content:
  #           application/json:
  #             schema:
  #               oneOf:
  #                 - $ref: '#/components/schemas/QuoteByQuantityResponse'
  #                 - $ref: '#/components/schemas/QuoteBySpendResponse'
  #       '400':
  #         $ref: '#/components/responses/BadRequest'
  #       '401':
  #         $ref: '#/components/responses/Unauthorized'
  #       '404':
  #         description: Contract not found
  #         content:
  #           application/json:
  #             schema:
  #               $ref: '#/components/schemas/Error'
  #       '500':
  #         $ref: '#/components/responses/InternalError'
  #       '503':
  #         $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/orders/active:
    post:
      tags:
        - Positions
      summary: Get active orders
      description: Returns a list of currently open (active) orders. Requires authentication.
      operationId: getActiveOrders
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                symbol:
                  type: string
                  description: Filter by contract instrument symbol
                  example: "GEMI-FEDJAN26-DN25"
                limit:
                  type: integer
                  description: Maximum number of results to return (default 50, max 100)
                  default: 50
                  maximum: 100
                offset:
                  type: integer
                  description: Number of results to skip for pagination
                  default: 0
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrdersResponse'
              examples:
                activeOrders:
                  summary: List of active orders
                  value:
                    orders:
                      - orderId: 12345678901
                        status: "open"
                        symbol: "GEMI-FEDJAN26-DN25"
                        side: "buy"
                        outcome: "yes"
                        orderType: "limit"
                        quantity: "100"
                        filledQuantity: "25"
                        remainingQuantity: "75"
                        price: "0.65"
                        avgExecutionPrice: "0.64"
                        createdAt: "2025-12-15T10:30:00.000Z"
                        updatedAt: "2025-12-15T11:00:00.000Z"
                        cancelledAt: null
                        contractMetadata:
                          contractId: "contract_123"
                          contractName: "FEDJAN26-DN25"
                          contractTicker: "FEDJAN26-DN25"
                          eventTicker: "FEDJAN26"
                          eventName: "Will Fed Funds Rate drop at least 0.25% at January 2026 meeting?"
                          category: "economics"
                          contractStatus: "active"
                          imageUrl: "https://example.com/fed.png"
                          expiryDate: "2026-01-31T23:59:59.000Z"
                          resolvedAt: null
                          description: "Resolves YES if Federal Reserve lowers the target rate by 0.25% or more at the January 2026 FOMC meeting"
                      - orderId: 12345678902
                        status: "open"
                        symbol: "GEMI-FEDJAN26-DN25"
                        side: "sell"
                        outcome: "yes"
                        orderType: "limit"
                        quantity: "50"
                        filledQuantity: "0"
                        remainingQuantity: "50"
                        price: "0.65"
                        avgExecutionPrice: null
                        createdAt: "2025-12-15T12:00:00.000Z"
                        updatedAt: "2025-12-15T12:00:00.000Z"
                        cancelledAt: null
                        contractMetadata:
                          contractId: "contract_123"
                          contractName: "FEDJAN26-DN25"
                          contractTicker: "FEDJAN26-DN25"
                          eventTicker: "FEDJAN26"
                          eventName: "Will Fed Funds Rate drop at least 0.25% at January 2026 meeting?"
                          category: "economics"
                          contractStatus: "active"
                          imageUrl: "https://example.com/fed.png"
                          expiryDate: "2026-01-31T23:59:59.000Z"
                          resolvedAt: null
                          description: "Resolves YES if Federal Reserve lowers the target rate by 0.25% or more at the January 2026 FOMC meeting"
                    pagination:
                      limit: 50
                      offset: 0
                      count: 2
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/orders/history:
    post:
      tags:
        - Positions
      summary: Get order history
      description: >-
        Returns historical orders (filled or cancelled) for the authenticated user. Use `status: filled` with `from` and `to` to retrieve fully filled orders in a bounded time window. The range is `[from, to)`: `from` is inclusive and `to` is exclusive. A time-bounded response contains at most `limit` results and ignores `offset`; split high-volume periods into non-overlapping ranges. Use `/orders/active` for open orders.
      operationId: getOrderHistory
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                status:
                  type: string
                  description: Filter by order status
                  enum: [filled, cancelled]
                symbol:
                  type: string
                  description: Filter by contract instrument symbol
                  example: "GEMI-FEDJAN26-DN25"
                limit:
                  type: integer
                  description: Maximum number of results to return. Defaults to 50 and is capped at 1000.
                  default: 50
                  minimum: 1
                  maximum: 1000
                offset:
                  type: integer
                  description: Number of results to skip for pagination. Offset is ignored when `from` or `to` is supplied.
                  default: 0
                  minimum: 0
                  maximum: 10000
                from:
                  type: integer
                  format: int64
                  description: Inclusive start of the order-closed time range, expressed as Unix epoch milliseconds. Use with `to` for a UTC daily window.
                  example: 1775001600000
                to:
                  type: integer
                  format: int64
                  description: Exclusive end of the order-closed time range, expressed as Unix epoch milliseconds. `from` must not be later than `to`.
                  example: 1775088000000
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrdersResponse'
        '400':
          description: Invalid status parameter or date range
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/positions:
    post:
      tags:
        - Positions
      summary: Get positions
      description: |
        Returns current filled positions for the authenticated user. All query parameters are optional; omitting them preserves the legacy unpaginated, unsorted behavior.
      operationId: getPositions
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      parameters:
        - name: eventTicker
          in: query
          required: false
          description: Filter positions to a single event ticker (e.g. `FEDJAN26`). Positions on sub-events whose `parentEventTicker` matches the value may also be included.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum number of positions to return. Clamped to `[1, 1000]` when supplied. Omit for legacy unpaginated behavior.
          schema:
            type: integer
            minimum: 1
            maximum: 1000
        - name: offset
          in: query
          required: false
          description: Number of positions to skip for pagination. Floor-clamped to `0` when supplied. Ignored when `limit` is omitted (the response is unpaginated).
          schema:
            type: integer
            minimum: 0
        - name: sort
          in: query
          required: false
          description: |
            Sort order. Accepts `positionValue`, `unrealizedPnl`, or `expiryDate` (case-insensitive), optionally prefixed with `+` (ascending) or `-` (descending). A bare field name uses each field's default direction: `positionValue` and `unrealizedPnl` default to descending; `expiryDate` defaults to ascending (soonest-first). `unrealizedPnl` and `expiryDate` sort NULLS LAST so positions without the sort key sink to the bottom regardless of direction. `instrumentId` ascending is the final tiebreaker for stable pagination across quote ticks. A malformed `sort` value silently falls back to `-positionValue` — no `400` is returned.
          schema:
            type: string
            enum:
              - positionValue
              - '+positionValue'
              - '-positionValue'
              - unrealizedPnl
              - '+unrealizedPnl'
              - '-unrealizedPnl'
              - expiryDate
              - '+expiryDate'
              - '-expiryDate'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PositionsResponse'
              examples:
                positions:
                  summary: User positions
                  value:
                    positions:
                      - symbol: "GEMI-FEDJAN26-DN25"
                        instrumentId: 1001
                        totalQuantity: "125"
                        quantityOnHold: "10"
                        avgPrice: "0.63"
                        outcome: "yes"
                        contractMetadata:
                          contractId: "contract_123"
                          contractName: "FEDJAN26-DN25"
                          contractTicker: "FEDJAN26-DN25"
                          eventTicker: "FEDJAN26"
                          eventName: "Will Fed Funds Rate drop at least 0.25% at January 2026 meeting?"
                          category: "economics"
                          contractStatus: "active"
                          imageUrl: "https://example.com/fed.png"
                          eventImageUrl: "https://example.com/fed-event.png"
                          eventType: "binary"
                          expiryDate: "2026-01-31T23:59:59.000Z"
                          resolvedAt: null
                          resolutionSide: null
                          description: "Resolves YES if Federal Reserve lowers the target rate by 0.25% or more at the January 2026 FOMC meeting"
                          sortOrder: null
                          parentEventTicker: null
                          template: "binary"
                          color: null
                          startTime: null
                        prices:
                          buy:
                            yes: "0.63"
                            no: "0.37"
                          sell:
                            yes: "0.61"
                            no: "0.35"
                          bestBid: "0.61"
                          bestAsk: "0.63"
                          lastTradePrice: "0.62"
                        resolutionSide: null
                        isAboveAutoStartThreshold: false
                        isLive: true
                        realizedPl: "0"
                        marketValue: "78.75"
                        unrealizedPnl: "0"
                        unrealizedPct: 0
                      - symbol: "GEMI-FEDJAN26-DN25"
                        instrumentId: 1001
                        totalQuantity: "200"
                        quantityOnHold: "0"
                        avgPrice: "0.36"
                        outcome: "no"
                        contractMetadata:
                          contractId: "contract_123"
                          contractName: "FEDJAN26-DN25"
                          contractTicker: "FEDJAN26-DN25"
                          eventTicker: "FEDJAN26"
                          eventName: "Will Fed Funds Rate drop at least 0.25% at January 2026 meeting?"
                          category: "economics"
                          contractStatus: "active"
                          imageUrl: "https://example.com/fed.png"
                          eventImageUrl: "https://example.com/fed-event.png"
                          eventType: "binary"
                          expiryDate: "2026-01-31T23:59:59.000Z"
                          resolvedAt: null
                          resolutionSide: null
                          description: "Resolves YES if Federal Reserve lowers the target rate by 0.25% or more at the January 2026 FOMC meeting"
                          sortOrder: null
                          parentEventTicker: null
                          template: "binary"
                          color: null
                          startTime: null
                        prices:
                          buy:
                            yes: "0.37"
                            no: "0.63"
                          sell:
                            yes: "0.35"
                            no: "0.61"
                          bestBid: "0.35"
                          bestAsk: "0.37"
                          lastTradePrice: "0.36"
                        resolutionSide: null
                        isAboveAutoStartThreshold: false
                        isLive: true
                        realizedPl: "0"
                        marketValue: "72.00"
                        unrealizedPnl: "0"
                        unrealizedPct: 0
                    total: 2
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/positions/settled:
    post:
      tags:
        - Positions
      summary: Get settled positions
      description: |
        Returns historically settled positions for the authenticated user. Each entry represents a position in a contract that has resolved.
         - `payout` — the amount received from settlement
         - `resolutionSide` — indicates which outcome (`yes` or `no`) won.

        This endpoint differs from [Get positions](#operation/getPositions) in that it returns closed positions from settled contracts rather than current open positions.
      operationId: getSettledPositions
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      parameters:
        - name: eventTicker
          in: query
          description: Optional event ticker to filter settled positions to a single event (e.g. `FEDJAN26`). If omitted, all settled positions for the account are returned.
          required: false
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum number of settled positions to return.
          schema:
            type: integer
            default: 1000
            minimum: 1
            maximum: 1000
        - name: offset
          in: query
          required: false
          description: Number of settled positions to skip for pagination.
          schema:
            type: integer
            default: 0
            minimum: 0
        - name: sort
          in: query
          required: false
          description: |
            Sort order. Accepts `date` or `payout`, optionally prefixed with `+` (ascending) or `-` (descending). A bare field name defaults to descending. `date` ascending is rejected and silently falls back to the default order — settled positions are conceptually ordered most-recent-first. A malformed `sort` value also falls back silently; no `400` is returned.
          schema:
            type: string
            enum:
              - date
              - '-date'
              - payout
              - '+payout'
              - '-payout'
            example: "-payout"
        - name: search
          in: query
          required: false
          description: |
            Case-insensitive substring filter. Matches against the event name, contract name, event ticker, or any ancestor category name in the contract's category subtree (up to four levels). Whitespace is trimmed; inputs under 3 characters are dropped (GIN trigram lookup floor); inputs over 64 characters are truncated.
          schema:
            type: string
        - name: category
          in: query
          required: false
          description: |
            Filter to settled positions whose contract's event belongs to the named category (or any of its descendants in the category tree). Whitespace is trimmed; empty values are ignored.
          schema:
            type: string
            example: "sports"
        - name: withCashOuts
          in: query
          required: false
          description: |
            Opt-in flag. When `true`, the response carries new sibling fields (`cashOuts`, `totalCashOutProceeds`, `totalCashOutCostBasis`, `totalCashOutNetProfit`) populated with the qualifying cash-outs in the same account-scoped time window as the returned page's settled positions. When `false` (default) the response shape is byte-identical to the pre-`withCashOuts` contract: the `positions[]` element schema is unchanged regardless of the flag.
          schema:
            type: boolean
            default: false
            example: true
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SettledPositionsResponse'
              examples:
                settledPositions:
                  summary: Settled positions with one winning and one losing position
                  value:
                    positions:
                      - accountId: 12345
                        instrumentId: 1001
                        instrumentSymbol: "GEMI-FEDJAN26-DN25"
                        position: "125"
                        positionQuantity: "125"
                        outcome: "yes"
                        payout: "125.00"
                        resolutionSide: "yes"
                        settledAt: "2026-01-31T23:59:59.000Z"
                        contractMetadata:
                          contractId: "contract_123"
                          contractName: "FEDJAN26-DN25"
                          contractTicker: "FEDJAN26-DN25"
                          eventTicker: "FEDJAN26"
                          eventName: "Will Fed Funds Rate drop at least 0.25% at January 2026 meeting?"
                          category: "economics"
                          contractStatus: "resolved"
                          imageUrl: "https://example.com/fed.png"
                          eventImageUrl: "https://example.com/fed-event.png"
                          eventType: "binary"
                          expiryDate: "2026-01-31T23:59:59.000Z"
                          resolvedAt: "2026-01-31T23:59:59.000Z"
                          resolutionSide: "yes"
                          description: "Resolves YES if Federal Reserve lowers the target rate by 0.25% or more at the January 2026 FOMC meeting"
                          sortOrder: null
                          parentEventTicker: null
                          template: "binary"
                          color: null
                          startTime: null
                        costBasis: "78.75"
                        realizedPnl: "0"
                        netProfit: "46.25"
                      - accountId: 12345
                        instrumentId: 1002
                        instrumentSymbol: "GEMI-FEDJAN26-NOCUT"
                        position: "-200"
                        positionQuantity: "200"
                        outcome: "no"
                        payout: "0"
                        resolutionSide: "yes"
                        settledAt: "2026-01-31T23:59:59.000Z"
                        contractMetadata:
                          contractId: "contract_124"
                          contractName: "FEDJAN26-NOCUT"
                          contractTicker: "FEDJAN26-NOCUT"
                          eventTicker: "FEDJAN26"
                          eventName: "Will Fed Funds Rate drop at least 0.25% at January 2026 meeting?"
                          category: "economics"
                          contractStatus: "resolved"
                          imageUrl: "https://example.com/fed.png"
                          eventImageUrl: "https://example.com/fed-event.png"
                          eventType: "binary"
                          expiryDate: "2026-01-31T23:59:59.000Z"
                          resolvedAt: "2026-01-31T23:59:59.000Z"
                          resolutionSide: "yes"
                          description: "Resolves YES if Federal Reserve lowers the target rate by 0.25% or more at the January 2026 FOMC meeting"
                          sortOrder: null
                          parentEventTicker: null
                          template: "binary"
                          color: null
                          startTime: null
                        costBasis: "72.00"
                        realizedPnl: "0"
                        netProfit: "-72.00"
                    total: 2
                settledPositionsWithCashOuts:
                  summary: Same response with `withCashOuts=true`
                  value:
                    positions:
                      - accountId: 12345
                        instrumentId: 1001
                        instrumentSymbol: "GEMI-FEDJAN26-DN25"
                        position: "125"
                        positionQuantity: "125"
                        outcome: "yes"
                        payout: "125.00"
                        resolutionSide: "yes"
                        settledAt: "2026-01-31T23:59:59.000Z"
                        contractMetadata:
                          contractId: "contract_123"
                          contractName: "FEDJAN26-DN25"
                          contractTicker: "FEDJAN26-DN25"
                          eventTicker: "FEDJAN26"
                          eventName: "Will Fed Funds Rate drop at least 0.25% at January 2026 meeting?"
                          category: "economics"
                          contractStatus: "resolved"
                          imageUrl: "https://example.com/fed.png"
                          eventImageUrl: "https://example.com/fed-event.png"
                          eventType: "binary"
                          expiryDate: "2026-01-31T23:59:59.000Z"
                          resolvedAt: "2026-01-31T23:59:59.000Z"
                          resolutionSide: "yes"
                          description: "Resolves YES if Federal Reserve lowers the target rate by 0.25% or more at the January 2026 FOMC meeting"
                          sortOrder: null
                          parentEventTicker: null
                          template: "binary"
                          color: null
                          startTime: null
                        costBasis: "78.75"
                        realizedPnl: "0"
                        netProfit: "46.25"
                    total: 1
                    cashOuts:
                      - accountId: 12345
                        instrumentId: 1003
                        instrumentSymbol: "GEMI-FEDJAN26-DN25"
                        timestamp: "2026-01-28T10:15:00.000Z"
                        filledQuantity: "10"
                        side: "sell"
                        proceeds: "6.50"
                        costBasis: "6.30"
                        netProfit: "0.20"
                        contractMetadata:
                          contractId: "contract_123"
                          contractName: "FEDJAN26-DN25"
                          contractTicker: "FEDJAN26-DN25"
                          eventTicker: "FEDJAN26"
                          eventName: "Will Fed Funds Rate drop at least 0.25% at January 2026 meeting?"
                          category: "economics"
                          contractStatus: "resolved"
                          imageUrl: "https://example.com/fed.png"
                          eventImageUrl: "https://example.com/fed-event.png"
                          eventType: "binary"
                          expiryDate: "2026-01-31T23:59:59.000Z"
                          resolvedAt: "2026-01-31T23:59:59.000Z"
                          resolutionSide: "yes"
                          description: "Resolves YES if Federal Reserve lowers the target rate by 0.25% or more at the January 2026 FOMC meeting"
                          sortOrder: null
                          parentEventTicker: null
                          template: "binary"
                          color: null
                          startTime: null
                    totalCashOutProceeds: "6.50"
                    totalCashOutCostBasis: "6.30"
                    totalCashOutNetProfit: "0.20"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/metrics/volume:
    post:
      tags:
        - Positions
      summary: Get volume metrics
      description: |
        Returns per-contract share volume metrics for an event, including the authenticated user's taker and maker volumes.

        All volumes are in shares (number of contracts traded), not dollar amounts.

        - `totalQty` — Total taker volume across all participants for this contract
        - `userAggressorQty` — The authenticated user's taker (aggressor) volume
        - `userRestingQty` — The authenticated user's maker (resting) volume, counted when another order fills against the user's resting limit order

        An optional time range can be specified to filter trades within a specific window.
      operationId: getVolumeMetrics
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - eventTicker
              properties:
                eventTicker:
                  type: string
                  description: The event ticker symbol
                  example: "FED260318"
                startTime:
                  type: integer
                  format: int64
                  description: Start of time range filter (epoch milliseconds). If omitted, defaults to the earliest contract creation time.
                endTime:
                  type: integer
                  format: int64
                  description: End of time range filter (epoch milliseconds). If omitted, includes all trades up to now.
            examples:
              allTime:
                summary: All-time volume for an event
                value:
                  eventTicker: "FED260318"
              timeRanged:
                summary: Volume within a specific time range
                value:
                  eventTicker: "FED260318"
                  startTime: 1772412364000
                  endTime: 1772671564000
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VolumeMetricsResponse'
              examples:
                volumeMetrics:
                  summary: Volume metrics for a multi-contract event
                  value:
                    eventTicker: "FED260318"
                    contracts:
                      - symbol: "GEMI-FED260318-CUT25"
                        totalQty: "94625"
                        userAggressorQty: "1"
                        userRestingQty: "0"
                      - symbol: "GEMI-FED260318-CUTGT25"
                        totalQty: "68666"
                        userAggressorQty: "0"
                        userRestingQty: "0"
                      - symbol: "GEMI-FED260318-HIKE"
                        totalQty: "15397"
                        userAggressorQty: "0"
                        userRestingQty: "0"
                      - symbol: "GEMI-FED260318-MAINTAIN"
                        totalQty: "20400"
                        userAggressorQty: "5"
                        userRestingQty: "0"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /v1/prediction-markets/combos:
    get:
      tags:
        - Combos
      summary: List combo contracts
      description: Returns a paginated list of pre-packaged combo contracts. Each combo includes its full leg breakdown and per-leg resolution status.
      operationId: listCombos
      parameters:
        - name: status
          in: query
          required: false
          description: Filter by combo contract status (e.g. `Active`, `Settled`, `Voided`)
          schema:
            type: string
        - name: contractId
          in: query
          required: false
          description: Filter to combos that contain a specific underlying contract ID as a leg
          schema:
            type: integer
            format: int64
        - name: instrumentRegistered
          in: query
          required: false
          description: Filter by whether the combo has been registered as a tradeable instrument on the orderbook
          schema:
            type: boolean
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Offset'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListCombosResponse'
              examples:
                activeCombos:
                  summary: List of active combo contracts
                  value:
                    combos:
                      - contract:
                          contractId: "456"
                          contractName: "BTC EOY26 > $120k AND ETH EOY26 > $4k"
                          contractTicker: "GEMI-CMB-0526-A7F3B2C1D4E5"
                          eventTicker: "GEMI-CMB-0526-A7F3B2C1D4E5"
                          eventName: "BTC EOY26 > $120k AND ETH EOY26 > $4k"
                          category: "Combo"
                          contractStatus: "Active"
                          eventType: "binary"
                          expiryDate: "2026-12-31T23:59:59Z"
                          resolvedAt: null
                          resolutionSide: null
                          parentEventTicker: null
                          startTime: null
                        legs:
                          - comboId: 456
                            legIndex: 0
                            contractId: 101
                            requiredOutcome: "Yes"
                            legOutcome: null
                            resolvedAt: null
                            contract:
                              contractId: "101"
                              contractName: "BTC above $120,000 at year-end 2026"
                              contractTicker: "GEMI-BTC-EOY26-HI120000"
                              eventTicker: "GEMI-BTC-EOY26"
                              eventName: "Bitcoin Year-End 2026"
                              category: "Crypto"
                              contractStatus: "Active"
                              eventType: "binary"
                              expiryDate: "2026-12-31T23:59:59Z"
                              resolvedAt: null
                              resolutionSide: null
                              parentEventTicker: null
                              startTime: null
                          - comboId: 456
                            legIndex: 1
                            contractId: 202
                            requiredOutcome: "Yes"
                            legOutcome: null
                            resolvedAt: null
                            contract:
                              contractId: "202"
                              contractName: "ETH above $4,000 at year-end 2026"
                              contractTicker: "GEMI-ETH-EOY26-HI4000"
                              eventTicker: "GEMI-ETH-EOY26"
                              eventName: "Ethereum Year-End 2026"
                              category: "Crypto"
                              contractStatus: "Active"
                              eventType: "binary"
                              expiryDate: "2026-12-31T23:59:59Z"
                              resolvedAt: null
                              resolutionSide: null
                              parentEventTicker: null
                              startTime: null
                    pagination:
                      limit: 50
                      offset: 0
                      total: 1
        '404':
          description: Combo contracts feature is not yet available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "NOT_FOUND"
                message: "Not Found"
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/prediction-markets/combos/{instrumentSymbol}:
    get:
      tags:
        - Combos
      summary: Get combo by instrument symbol
      description: Returns the full specification of a single combo contract identified by its instrument symbol, including leg breakdown and per-leg resolution status.
      operationId: getComboByInstrumentSymbol
      parameters:
        - name: instrumentSymbol
          in: path
          required: true
          description: The combo contract's instrument symbol (e.g. `GEMI-CMB-0526-A7F3B2C1D4E5`)
          schema:
            type: string
          example: "GEMI-CMB-0526-A7F3B2C1D4E5"
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ComboResponse'
              examples:
                comboDetail:
                  summary: Combo contract detail
                  value:
                    contract:
                      contractId: "456"
                      contractName: "BTC EOY26 > $120k AND ETH EOY26 > $4k"
                      contractTicker: "GEMI-CMB-0526-A7F3B2C1D4E5"
                      eventTicker: "GEMI-CMB-0526-A7F3B2C1D4E5"
                      eventName: "BTC EOY26 > $120k AND ETH EOY26 > $4k"
                      category: "Combo"
                      contractStatus: "Active"
                      eventType: "binary"
                      expiryDate: "2026-12-31T23:59:59Z"
                      resolvedAt: null
                      resolutionSide: null
                      parentEventTicker: null
                      startTime: null
                    legs:
                      - comboId: 456
                        legIndex: 0
                        contractId: 101
                        requiredOutcome: "Yes"
                        legOutcome: null
                        resolvedAt: null
                        contract:
                          contractId: "101"
                          contractName: "BTC above $120,000 at year-end 2026"
                          contractTicker: "GEMI-BTC-EOY26-HI120000"
                          eventTicker: "GEMI-BTC-EOY26"
                          eventName: "Bitcoin Year-End 2026"
                          category: "Crypto"
                          contractStatus: "Active"
                          eventType: "binary"
                          expiryDate: "2026-12-31T23:59:59Z"
                          resolvedAt: null
                          resolutionSide: null
                          parentEventTicker: null
                          startTime: null
                      - comboId: 456
                        legIndex: 1
                        contractId: 202
                        requiredOutcome: "Yes"
                        legOutcome: null
                        resolvedAt: null
                        contract:
                          contractId: "202"
                          contractName: "ETH above $4,000 at year-end 2026"
                          contractTicker: "GEMI-ETH-EOY26-HI4000"
                          eventTicker: "GEMI-ETH-EOY26"
                          eventName: "Ethereum Year-End 2026"
                          category: "Crypto"
                          contractStatus: "Active"
                          eventType: "binary"
                          expiryDate: "2026-12-31T23:59:59Z"
                          resolvedAt: null
                          resolutionSide: null
                          parentEventTicker: null
                          startTime: null
        '404':
          description: Combo not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "NOT_FOUND"
                message: "Combo not found"
        '500':
          $ref: '#/components/responses/InternalError'

  /v1/prediction-markets/maker-rebate/rates:
    get:
      tags:
        - Rewards
      summary: Get maker-rebate rate schedule
      description: |
        Returns the current Maker Rebate rate rules. Public endpoint; no authentication required.

        Each rule defines a `rebate_multiplier_bps` (basis points of the maker fee that is rebated) and an `effective_from` timestamp. An optional `category` scopes the rule to a single market category (omitted rules apply to all categories). An optional `effective_to` marks a rule as superseded.

        Returns `503` with `error: "Maker rebate program is not currently available"` when the program is disabled.
      operationId: getMakerRebateRates
      parameters:
        - name: category
          in: query
          description: Filter to rules that apply to this category (e.g. `Crypto`, `Sports`). When omitted, returns all rules.
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MakerRebateRatesResponse'
              examples:
                allCategories:
                  summary: Full rate schedule
                  value:
                    rate_rules:
                      - id: 12
                        rebate_multiplier_bps: 5000
                        effective_from: "2026-03-19T00:00:00Z"
                        category: "Crypto"
                      - id: 13
                        rebate_multiplier_bps: 2500
                        effective_from: "2026-03-19T00:00:00Z"
                        category: "Sports"
                        effective_to: "2026-04-19T00:00:00Z"
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "An unexpected error occurred"
        '503':
          description: Maker rebate program is not currently available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "Maker rebate program is not currently available"

  /v1/prediction-markets/maker-rebate/payouts:
    post:
      tags:
        - Rewards
      summary: List maker-rebate payouts
      description: |
        Returns the authenticated account's Maker Rebate payout history. Most recent payout first.

        Pagination is read from the `limit` and `offset` query parameters: `limit` is clamped to `[1, 100]` (default 50), `offset` is clamped to `[0, +∞)` (default 0).

        Requires authentication with `OrderStatus` permission. Returns `503` when the program is disabled.
      operationId: listMakerRebatePayouts
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      parameters:
        - name: limit
          in: query
          description: Maximum number of payouts to return (default 50, clamped to [1, 100]).
          required: false
          schema:
            type: integer
            default: 50
            minimum: 1
            maximum: 100
        - name: offset
          in: query
          description: Number of payouts to skip (default 0).
          required: false
          schema:
            type: integer
            default: 0
            minimum: 0
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MakerRebatePayoutsResponse'
              examples:
                samplePayouts:
                  summary: Two recent payouts
                  value:
                    payouts:
                      - id: 9182
                        total_volume_usd: "12450.00"
                        total_rebate_usd: "6.23"
                        total_fill_count: 187
                        status: "PAID"
                        paid_at: "2026-05-20T21:00:00Z"
                        created_at: "2026-05-20T20:55:12Z"
                      - id: 9173
                        total_volume_usd: "8920.50"
                        total_rebate_usd: "4.46"
                        total_fill_count: 124
                        status: "PAID"
                        paid_at: "2026-05-19T21:00:00Z"
                        created_at: "2026-05-19T20:55:08Z"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "An unexpected error occurred"
        '503':
          description: Maker rebate program is not currently available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "Maker rebate program is not currently available"

  /v1/prediction-markets/maker-rebate/summary/total:
    get:
      tags:
        - Rewards
      summary: Get maker-rebate lifetime summary
      description: |
        Returns lifetime totals for the authenticated account's Maker Rebate payouts. When both `dateFrom` and `dateTo` are provided, the totals are restricted to payouts paid within that inclusive Eastern Time window.

        Either provide both date parameters or omit both. Dates must be in `YYYY-MM-DD` format, `dateTo` must be on or after `dateFrom`, and the range must not exceed 5 years.

        Requires authentication with `OrderStatus` permission. Returns `503` when the program is disabled.
      operationId: getMakerRebateLifetimeSummary
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      parameters:
        - name: dateFrom
          in: query
          description: Inclusive start of the payout date window (`YYYY-MM-DD`, Eastern Time). Must be provided together with `dateTo`.
          required: false
          schema:
            type: string
            format: date
            example: "2026-04-01"
        - name: dateTo
          in: query
          description: Inclusive end of the payout date window (`YYYY-MM-DD`, Eastern Time). Must be on or after `dateFrom` and within 5 years of it.
          required: false
          schema:
            type: string
            format: date
            example: "2026-05-01"
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MakerRebateLifetimeSummary'
              examples:
                lifetime:
                  summary: Lifetime totals (no date filter)
                  value:
                    total_earned_usd: "152.40"
                    total_fill_count: 4218
                    total_volume_usd: "304800.00"
                    payout_count: 27
                    first_payout_date: "2026-03-19"
                    last_payout_date: "2026-05-20"
                emptyHistory:
                  summary: Account has never received a payout
                  value:
                    total_earned_usd: "0"
                    total_fill_count: 0
                    total_volume_usd: "0"
                    payout_count: 0
                    first_payout_date: null
                    last_payout_date: null
        '400':
          description: Invalid date parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "BAD_REQUEST"
                message: "date_to must be on or after date_from"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "INTERNAL_ERROR"
                message: "An unexpected error occurred"
        '503':
          description: Maker rebate program is not currently available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "SERVICE_UNAVAILABLE"
                message: "Maker rebate program is not currently available"

  /v1/prediction-markets/liquidity-rewards/config:
    get:
      tags:
        - Rewards
      summary: Get liquidity-rewards program config
      description: |
        Returns the Liquidity Rewards program configuration. Public endpoint; no authentication required.

        When the program is fully configured the response includes `max_spread_cents`, `min_payout_threshold_usd`, and `enabled: true`. When the program is not yet fully configured, the response collapses to `{ "enabled": false }` only.

        Returns `503` when the program is not currently available.
      operationId: getLiquidityRewardsConfig
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LiquidityRewardsConfig'
              examples:
                enabled:
                  summary: Program enabled and configured
                  value:
                    max_spread_cents: 10
                    min_payout_threshold_usd: "1.00"
                    enabled: true
                disabledShape:
                  summary: Program flag on but config incomplete upstream
                  value:
                    enabled: false
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "INTERNAL_ERROR"
                message: "An unexpected error occurred"
        '503':
          description: Liquidity rewards program is not currently available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "SERVICE_UNAVAILABLE"
                message: "Liquidity rewards program is not currently available"

  /v1/prediction-markets/liquidity-rewards/events:
    get:
      tags:
        - Rewards
      summary: List liquidity-rewards events
      description: |
        Returns the paginated list of events currently participating in the Liquidity Rewards program. Public endpoint; no authentication required.

        `category` accepts a comma-separated list of category names (whitespace trimmed, empty entries dropped). `sort` controls ordering. `limit` is clamped to `[1, 100]` (default 50); `offset` is clamped to `[0, +∞)` (default 0). `last_score_date` is the most recent date for which scoring data has been written, or `null` when no scoring has run yet.

        Returns `503` when the program is not currently available.
      operationId: listLiquidityRewardsEvents
      parameters:
        - name: category
          in: query
          description: Comma-separated list of category names. Whitespace is trimmed and empty entries are dropped.
          required: false
          schema:
            type: string
            example: "Crypto,Sports"
        - name: search
          in: query
          description: Filter events by title substring (case-insensitive).
          required: false
          schema:
            type: string
        - name: sort
          in: query
          description: Sort order for the returned events. Defaults to `daily_pool_desc`.
          required: false
          schema:
            type: string
            default: daily_pool_desc
            enum:
              - daily_pool_desc
              - daily_pool_asc
              - ends_soonest
              - ends_latest
              - title_asc
              - title_desc
              - category_asc
              - category_desc
              - competition_asc
              - competition_desc
        - name: limit
          in: query
          description: Maximum number of events to return (default 50, clamped to [1, 100]).
          required: false
          schema:
            type: integer
            default: 50
            minimum: 1
            maximum: 100
        - name: offset
          in: query
          description: Number of events to skip (default 0).
          required: false
          schema:
            type: integer
            default: 0
            minimum: 0
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LiquidityRewardsEventsResponse'
              examples:
                sampleEvents:
                  summary: Two scored events
                  value:
                    events:
                      - event_ticker: "BTC2605202100"
                        title: "BTC above $95,000?"
                        category: "Crypto"
                        daily_pool_usd: "500.00"
                        pool_source: "event_override"
                        ends_at: "2026-05-20T21:00:00Z"
                        qualifying_maker_count: 14
                        icon_url: "https://example.com/btc.png"
                      - event_ticker: "FRENCHOPEN-FINAL"
                        title: "French Open 2026 — Men's Final winner"
                        category: "Sports"
                        daily_pool_usd: "250.00"
                        pool_source: "category_default"
                        ends_at: "2026-06-07T15:00:00Z"
                        qualifying_maker_count: 7
                    pagination:
                      limit: 50
                      offset: 0
                      total: 2
                    last_score_date: "2026-05-19"
                emptyBeforeScoring:
                  summary: Program just turned on, no scoring yet
                  value:
                    events: []
                    pagination:
                      limit: 50
                      offset: 0
                      total: 0
                    last_score_date: null
        '400':
          description: Invalid sort or pagination parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "BAD_REQUEST"
                message: "sort must be one of: daily_pool_desc, daily_pool_asc, ends_soonest, ends_latest, title_asc, title_desc, category_asc, category_desc, competition_asc, competition_desc (got 'foo')"
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "INTERNAL_ERROR"
                message: "An unexpected error occurred"
        '503':
          description: Liquidity rewards program is not currently available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "SERVICE_UNAVAILABLE"
                message: "Liquidity rewards program is not currently available"

  /v1/prediction-markets/liquidity-rewards/summary/daily:
    get:
      tags:
        - Rewards
      summary: Get liquidity-rewards daily summary
      description: |
        Returns daily Liquidity Rewards payouts for the authenticated account within the requested date window. Both `dateFrom` and `dateTo` are required and must be in `YYYY-MM-DD` format; `dateTo` must be on or after `dateFrom`.

        Each daily entry includes the total USD reward for that day, the payout status (e.g. `PENDING`, `PAID`), the paid-at timestamp (if paid), and per-event score breakdowns showing how the day's reward was distributed across events the account scored on.

        Requires authentication with `OrderStatus` permission. Returns `503` when the program is not currently available.
      operationId: getLiquidityRewardsDailySummary
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      parameters:
        - name: dateFrom
          in: query
          description: Inclusive start of the date window (`YYYY-MM-DD`, Eastern Time).
          required: true
          schema:
            type: string
            format: date
            example: "2026-05-01"
        - name: dateTo
          in: query
          description: Inclusive end of the date window (`YYYY-MM-DD`, Eastern Time). Must be on or after `dateFrom`.
          required: true
          schema:
            type: string
            format: date
            example: "2026-05-07"
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LiquidityRewardsDailySummaryResponse'
              examples:
                sampleWeek:
                  summary: One week of daily summaries
                  value:
                    daily_summaries:
                      - payout_date: "2026-05-07"
                        total_reward_usd: "12.45"
                        payout_status: "PAID"
                        paid_at: "2026-05-08T21:00:00Z"
                        events:
                          - event_id: 1234567890
                            event_name: "BTC above $95,000?"
                            category_name: "Crypto"
                            normalized_score: "0.4521"
                            snapshot_count: 1180
                            total_snapshots: 1440
                            event_reward_usd: "8.20"
                          - event_id: 9876543210
                            event_name: "ETH above $4,000?"
                            category_name: "Crypto"
                            normalized_score: "0.2341"
                            snapshot_count: 920
                            total_snapshots: 1440
                            event_reward_usd: "4.25"
                      - payout_date: "2026-05-06"
                        total_reward_usd: "0"
                        payout_status: "ZERO_AMOUNT"
                        paid_at: null
                        events: []
        '400':
          description: Invalid date parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "date_to must be on or after date_from"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "An unexpected error occurred"
        '503':
          description: Liquidity rewards program is not currently available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "Liquidity incentive program is not currently available"

  /v1/prediction-markets/liquidity-rewards/summary/total:
    get:
      tags:
        - Rewards
      summary: Get liquidity-rewards lifetime summary
      description: |
        Returns lifetime totals for the authenticated account's Liquidity Rewards payouts. When both `dateFrom` and `dateTo` are provided, the totals are restricted to payouts paid within that inclusive Eastern Time window.

        Either provide both date parameters or omit both. Dates must be in `YYYY-MM-DD` format, `dateTo` must be on or after `dateFrom`, and the range must not exceed 5 years.

        Requires authentication with `OrderStatus` permission. Returns `503` when the program is not currently available.
      operationId: getLiquidityRewardsLifetimeSummary
      security:
        - apiKey: []
          payloadAuth: []
          signatureAuth: []
      parameters:
        - name: dateFrom
          in: query
          description: Inclusive start of the payout date window (`YYYY-MM-DD`, Eastern Time). Must be provided together with `dateTo`.
          required: false
          schema:
            type: string
            format: date
            example: "2026-04-01"
        - name: dateTo
          in: query
          description: Inclusive end of the payout date window (`YYYY-MM-DD`, Eastern Time). Must be on or after `dateFrom` and within 5 years of it.
          required: false
          schema:
            type: string
            format: date
            example: "2026-05-01"
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LiquidityRewardsLifetimeSummary'
              examples:
                lifetime:
                  summary: Lifetime totals
                  value:
                    total_earned_usd: "84.20"
                    payout_count: 12
                    first_payout_date: "2026-05-08"
                    last_payout_date: "2026-05-20"
                emptyHistory:
                  summary: Account has never received a payout
                  value:
                    total_earned_usd: "0"
                    payout_count: 0
                    first_payout_date: null
                    last_payout_date: null
        '400':
          description: Invalid date parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "BAD_REQUEST"
                message: "date_to must be on or after date_from"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "INTERNAL_ERROR"
                message: "An unexpected error occurred"
        '503':
          description: Liquidity rewards program is not currently available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "SERVICE_UNAVAILABLE"
                message: "Liquidity rewards program is not currently available"

components:
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: X-GEMINI-APIKEY
      description: Gemini API key with appropriate permissions
    payloadAuth:
      type: apiKey
      in: header
      name: X-GEMINI-PAYLOAD
      description: Base64-encoded private REST payload. See Gemini private REST authentication.
    signatureAuth:
      type: apiKey
      in: header
      name: X-GEMINI-SIGNATURE
      description: Hex HMAC-SHA384 signature of the payload using the API secret.

  parameters:
    Limit:
      name: limit
      in: query
      description: Maximum number of results to return (max 500)
      schema:
        type: integer
        default: 50
        minimum: 1
        maximum: 500
    Offset:
      name: offset
      in: query
      description: Number of results to skip for pagination
      schema:
        type: integer
        default: 0
        minimum: 0

  responses:
    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Authentication required or invalid credentials
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ServiceUnavailable:
      description: Prediction markets feature is temporarily unavailable
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

  schemas:
    Error:
      type: object
      properties:
        error:
          type: string
          description: Error code
          example: "InvalidInput"
        message:
          type: string
          description: Human-readable error message
          example: "orderId is required"

    PredictionMarketsError:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: string
          description: Prediction Markets error class
          example: "InvalidInput"
        field:
          type: string
          description: Request field associated with the error, when available
          example: "orders"
        message:
          type: string
          description: Human-readable error detail, when available
          example: "orders must contain between 1 and 20 entries"

    AuthErrorResponse:
      type: object
      additionalProperties: false
      required:
        - result
        - reason
        - message
      properties:
        result:
          type: string
          enum: [error]
        reason:
          type: string
          description: Authentication or authorization error class
          example: "MissingNonce"
        message:
          type: string
          description: Human-readable authentication or authorization detail
          example: "Must provide unique monotonic increasing 'nonce' field in payload"

    AccountGroupBlockedError:
      type: object
      additionalProperties: false
      required:
        - error
        - code
      properties:
        error:
          type: string
          enum: ["This account is not permitted to trade prediction markets"]
        code:
          type: string
          enum: [ACCOUNT_GROUP_BLOCKED]

    TermsNotAcceptedError:
      type: object
      additionalProperties: false
      required:
        - error
        - message
      properties:
        error:
          type: string
          enum: [TERMS_NOT_ACCEPTED]
        message:
          type: string
          enum: ["Prediction markets terms must be accepted before placing orders"]

    RestrictedSellOnlyError:
      type: object
      additionalProperties: false
      required:
        - error
        - message
      properties:
        error:
          type: string
          enum: [ACCOUNT_RESTRICTED_SELL_ONLY]
        message:
          type: string
          enum: ["Your account is restricted to selling existing positions; buying is not permitted."]

    PredictionMarketsTerms:
      type: object
      required:
        - termsType
        - version
        - content
        - updatedAt
      properties:
        termsType:
          type: string
          description: Terms type identifier
          example: "PredictionsMarket"
        version:
          type: integer
          description: Latest terms version
          example: 3
        content:
          type: string
          description: Terms content to display before acceptance
          example: "These are the prediction market terms."
        updatedAt:
          type: string
          format: date-time
          description: UTC timestamp when the terms content was last updated
          example: "2026-05-18T17:00:00Z"

    PredictionMarketsTermsStatus:
      type: object
      required:
        - hasAcceptedLatest
      properties:
        hasAcceptedLatest:
          type: boolean
          description: Whether the account group has accepted the latest configured Prediction Markets terms
          example: false
        acceptedVersion:
          type: integer
          nullable: true
          description: Latest terms version accepted by the account group, if any
          example: 2
        latestVersion:
          type: integer
          nullable: true
          description: Latest configured Prediction Markets terms version, if available
          example: 3

    AcceptPredictionMarketsTermsResponse:
      type: object
      required:
        - success
      properties:
        success:
          type: boolean
          example: true

    MarketStatus:
      type: string
      enum: [approved, active, closed, under_review, settled, invalid]
      description: Status of a prediction market

    MarketType:
      type: string
      enum: [binary, categorical]
      description: Type of prediction market

    OrderType:
      type: string
      enum: [limit, stop-limit]
      description: Order type. `stop-limit` orders require a `stopPrice` that triggers a limit order at `price` when the market reaches the trigger.

    OrderSide:
      type: string
      enum: [buy, sell]

    Outcome:
      type: string
      enum: ["yes", "no"]
      description: The outcome being traded (Yes or No)

    TimeInForce:
      type: string
      enum: [good-til-cancel, immediate-or-cancel, fill-or-kill]
      default: good-til-cancel
      description: |
        Order execution behavior:
        - `good-til-cancel` - Order remains active until filled or cancelled (default)
        - `immediate-or-cancel` - Fill immediately or cancel remaining
        - `fill-or-kill` - Fill entire order immediately or cancel

    OrderStatus:
      type: string
      enum: [open, filled, cancelled]

    PositionStatus:
      type: string
      enum: [active, resolved, cancelled]

    Pagination:
      type: object
      properties:
        limit:
          type: integer
          example: 50
        offset:
          type: integer
          example: 0
        total:
          type: integer
          example: 100

    PaginationSimple:
      type: object
      properties:
        limit:
          type: integer
        offset:
          type: integer
        count:
          type: integer
          description: Number of items in current response

    OrderBook:
      type: object
      properties:
        bids:
          type: array
          items:
            $ref: '#/components/schemas/OrderBookEntry'
        asks:
          type: array
          items:
            $ref: '#/components/schemas/OrderBookEntry'

    OrderBookEntry:
      type: object
      properties:
        side:
          $ref: '#/components/schemas/OrderSide'
        price:
          type: string
          example: "0.65"
        quantity:
          type: string
          example: "1000"

    OrderBookDepth:
      type: object
      properties:
        bids:
          type: array
          items:
            $ref: '#/components/schemas/OrderBookLevel'
        asks:
          type: array
          items:
            $ref: '#/components/schemas/OrderBookLevel'
        lastUpdateTime:
          type: string
          format: date-time

    OrderBookLevel:
      type: object
      properties:
        price:
          type: string
        quantity:
          type: string
        orderCount:
          type: integer

    Contract:
      type: object
      properties:
        id:
          type: string
        label:
          type: string
          description: Human-readable label (e.g., "Yes", "No")
        abbreviatedName:
          type: string
          nullable: true
          description: Short form label (e.g., ">$90")
        description:
          type: object
          description: Rich text description
        prices:
          $ref: '#/components/schemas/ContractPrices'
        totalShares:
          type: string
          nullable: true
        color:
          type: string
          nullable: true
        status:
          $ref: '#/components/schemas/MarketStatus'
        imageUrl:
          type: string
          nullable: true
        priceHistory:
          type: array
          nullable: true
          items:
            $ref: '#/components/schemas/PricePoint'
        createdAt:
          type: string
          format: date-time
        expiryDate:
          type: string
          format: date-time
          nullable: true
        resolutionSide:
          $ref: '#/components/schemas/Outcome'
        resolvedAt:
          type: string
          format: date-time
          nullable: true
        termsAndConditionsUrl:
          type: string
        ticker:
          type: string
        instrumentSymbol:
          type: string
        effectiveDate:
          type: string
          format: date-time
          nullable: true
        marketState:
          type: string
          nullable: true
          description: Trading state of the contract
          enum: [open, closed]
        sortOrder:
          type: integer
          nullable: true
          description: Display order within the event
        strike:
          $ref: '#/components/schemas/Strike'
        source:
          type: string
          nullable: true
          deprecated: true
          description: 'Deprecated: use the event-level `sourceDetails` (`agency` + `index`) instead. Data source identifier for price observation (e.g., "GRR-KAIKO_BTCUSD_60S"). Present for crypto Up/Down contracts.'
          example: "GRR-KAIKO_BTCUSD_60S"
        settlementValue:
          type: string
          nullable: true
          description: The observed settlement price. Only present after the contract is settled.
          example: "87654.32"

    Strike:
      type: object
      description: Strike price information for Up/Down crypto contracts
      properties:
        value:
          type: string
          nullable: true
          description: The strike price value. Null for "reference" type strikes where the value is determined at availableAt time.
          example: "87500.00"
        type:
          type: string
          description: Strike type - "reference" for Up/Down contracts, "above" for Higher/Lower contracts
          enum: [reference, above]
          example: "reference"
        availableAt:
          type: string
          format: date-time
          nullable: true
          description: When the strike price becomes available
          example: "2026-03-27T19:45:00.000Z"

    SourceDetails:
      type: object
      nullable: true
      description: >-
        Structured data source information for price observation. Replaces the deprecated
        flat `source` string on the event and contract. Present for crypto Up/Down events.
        Both fields are omitted when not available.
      properties:
        agency:
          type: string
          nullable: true
          description: The data provider / vendor name.
          example: "Kaiko"
        index:
          type: string
          nullable: true
          description: The specific data feed identifier (the value previously carried by the flat `source` field).
          example: "GRR-KAIKO_BTCUSD_60S"

    PricePoint:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
        price:
          type: string

    ContractPrices:
      type: object
      nullable: true
      description: Current bid/ask pricing for the contract
      properties:
        buy:
          type: object
          description: Buy prices for each outcome
          properties:
            "yes":
              type: string
              description: Price to buy YES outcome
              example: "0.42"
            "no":
              type: string
              description: Price to buy NO outcome
              example: "0.58"
        sell:
          type: object
          description: Sell prices for each outcome
          properties:
            "yes":
              type: string
              description: Price to sell YES outcome
              example: "0.42"
            "no":
              type: string
              description: Price to sell NO outcome
              example: "0.58"
        bestBid:
          type: string
          nullable: true
          description: Highest buy offer
          example: "0.49"
        bestAsk:
          type: string
          nullable: true
          description: Lowest sell offer
          example: "0.54"
        lastTradePrice:
          type: string
          nullable: true
          description: Most recent transaction price
          example: "0.75"

    Event:
      type: object
      description: A prediction market event containing one or more tradeable contracts
      properties:
        id:
          type: string
        title:
          type: string
          example: "Will Bitcoin reach $100k by end of 2028?"
        slug:
          type: string
          example: "bitcoin-100k-2028"
        description:
          type: string
          nullable: true
        imageUrl:
          type: string
          nullable: true
        type:
          $ref: '#/components/schemas/MarketType'
        category:
          type: string
          example: "crypto"
        series:
          type: string
          nullable: true
        ticker:
          type: string
          description: The event ticker (e.g., "BTC100K2028")
          example: "BTC100K2028"
        status:
          $ref: '#/components/schemas/MarketStatus'
        resolvedAt:
          type: string
          format: date-time
          nullable: true
        createdAt:
          type: string
          format: date-time
        contracts:
          type: array
          description: Tradeable contracts within this event
          items:
            $ref: '#/components/schemas/Contract'
        contractOrderbooks:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/OrderBook'
        volume:
          type: string
          description: Total trading volume in USD
          example: "125000.00"
        liquidity:
          type: string
          description: Total liquidity in USD
          example: "50000.00"
        tags:
          type: array
          nullable: true
          items:
            type: string
        effectiveDate:
          type: string
          format: date-time
        expiryDate:
          type: string
          format: date-time
          nullable: true
        subcategory:
          $ref: '#/components/schemas/Subcategory'
        source:
          type: string
          nullable: true
          deprecated: true
          description: 'Deprecated: use `sourceDetails` (`agency` + `index`) instead. Data source identifier for price observation. Aggregated from contracts for crypto Up/Down events.'
          example: "GRR-KAIKO_BTCUSD_60S"
        sourceDetails:
          $ref: '#/components/schemas/SourceDetails'
        settlement:
          $ref: '#/components/schemas/Settlement'

    Subcategory:
      type: object
      nullable: true
      description: Nested category information for the event
      properties:
        id:
          type: integer
          description: Category identifier
          example: 35
        slug:
          type: string
          description: URL-friendly category identifier
          example: "crypto_solana"
        name:
          type: string
          description: Display name
          example: "Solana"
        path:
          type: array
          description: Category hierarchy path
          items:
            type: string
          example: ["Crypto", "Solana"]

    Settlement:
      type: object
      description: Settlement information for resolved events
      properties:
        value:
          type: string
          nullable: true
          description: The observed settlement value (e.g., the price at expiry for crypto contracts)
          example: "87654.32"

    EventsResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Event'
        pagination:
          $ref: '#/components/schemas/Pagination'

    ContractMetadata:
      type: object
      properties:
        contractId:
          type: string
        contractName:
          type: string
        contractTicker:
          type: string
        eventTicker:
          type: string
        eventName:
          type: string
        category:
          type: string
        contractStatus:
          type: string
        eventType:
          type: string
          description: Event type ("binary" or "categorical")
        expiryDate:
          type: string
          format: date-time
          nullable: true
        resolvedAt:
          type: string
          format: date-time
          nullable: true
        resolutionSide:
          type: string
          nullable: true
          description: Winning outcome if resolved ("yes" or "no")
        parentEventTicker:
          type: string
          nullable: true
          description: Parent event ticker for sub-events
        startTime:
          type: string
          format: date-time
          nullable: true
          description: Start datetime (ISO 8601)

    ComboLeg:
      type: object
      properties:
        comboId:
          type: integer
          format: int64
          description: Internal ID of the parent combo contract
          example: 456
        legIndex:
          type: integer
          description: Zero-based position of this leg in the combo
          example: 0
        contractId:
          type: integer
          format: int64
          description: Internal ID of the underlying single contract
          example: 101
        requiredOutcome:
          type: string
          description: The outcome this leg must settle for the combo to settle YES (`"Yes"` at launch)
          example: "Yes"
        legOutcome:
          type: string
          nullable: true
          description: The outcome this leg has settled to, if resolved (`"Yes"` or `"No"`). Null while the leg is still active.
          example: null
        resolvedAt:
          type: string
          format: date-time
          nullable: true
          description: UTC timestamp when this leg resolved. Null while still active.
          example: null
        contract:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/ContractMetadata'
          description: Full metadata for the underlying single contract

    ComboResponse:
      type: object
      properties:
        contract:
          allOf:
            - $ref: '#/components/schemas/ContractMetadata'
          description: Metadata for the combo contract itself (ticker, status, expiry, etc.)
        legs:
          type: array
          description: Ordered list of legs that make up this combo
          items:
            $ref: '#/components/schemas/ComboLeg'

    ListCombosResponse:
      type: object
      properties:
        combos:
          type: array
          description: List of combo contracts matching the query
          items:
            $ref: '#/components/schemas/ComboResponse'
        pagination:
          allOf:
            - $ref: '#/components/schemas/Pagination'

    OrderRequest:
      type: object
      required:
        - symbol
        - orderType
        - side
        - quantity
        - price
        - outcome
      properties:
        symbol:
          type: string
          description: Contract instrument symbol
          example: "GEMI-FEDJAN26-DN25"
        orderType:
          $ref: '#/components/schemas/OrderType'
        side:
          $ref: '#/components/schemas/OrderSide'
        quantity:
          type: string
          description: Number of contracts
          example: "100"
        price:
          type: string
          description: Limit price (0-1 range)
          example: "0.65"
        stopPrice:
          type: string
          description: The price to trigger a stop-limit order (0-1 range). Only available for stop-limit orders. See [Stop-Limit Orders](#operation/placeOrder) above for `stopPrice`/`price` constraints.
          example: "0.60"
        outcome:
          $ref: '#/components/schemas/Outcome'
        timeInForce:
          $ref: '#/components/schemas/TimeInForce'
        makerOrCancel:
          type: boolean
          description: Set to `true` to require maker-only behavior. If the order would immediately take liquidity, the order is cancelled instead of filling.
          default: false

    PlaceOrderBatchRequest:
      type: object
      required:
        - orders
      properties:
        orders:
          type: array
          minItems: 1
          maxItems: 20
          description: Orders to submit. Every entry is validated before any order is submitted. All orders use the account associated with the authenticated request.
          items:
            $ref: '#/components/schemas/OrderRequest'

    BatchOrderResponse:
      type: object
      description: An accepted order returned for one batch entry.
      required:
        - orderId
        - status
        - symbol
        - side
        - outcome
        - orderType
        - timeInForce
        - quantity
        - filledQuantity
        - remainingQuantity
        - price
        - createdAt
        - updatedAt
      properties:
        orderId:
          type: integer
          format: int64
          example: 12345678
        hashOrderId:
          type: string
          description: Hashed order ID; omitted when unavailable
        clientOrderId:
          type: string
          description: Client-provided order ID; omitted when unavailable
        globalOrderId:
          type: string
          description: Global order ID; omitted when unavailable
        status:
          type: string
          enum: [open, filled, cancelled, closed]
        symbol:
          type: string
        side:
          $ref: '#/components/schemas/OrderSide'
        outcome:
          $ref: '#/components/schemas/Outcome'
        orderType:
          $ref: '#/components/schemas/OrderType'
        timeInForce:
          type: string
          enum: [good-til-cancel, immediate-or-cancel, fill-or-kill, maker-or-cancel]
        quantity:
          type: string
          description: Original order quantity
        filledQuantity:
          type: string
          description: Amount filled so far
        remainingQuantity:
          type: string
          description: Amount remaining to fill
        price:
          type: string
          description: Limit price
        stopPrice:
          type: string
          description: Stop trigger price; omitted unless populated for a `stop-limit` order
        avgExecutionPrice:
          type: string
          description: Average price of fills; omitted when unavailable
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        cancelledAt:
          type: string
          format: date-time
          description: Cancellation time; omitted unless the order was cancelled
        contractMetadata:
          $ref: '#/components/schemas/ContractMetadata'
        promoCashApplied:
          type: string
          description: Promotional cash reserved or applied to the order; omitted when unavailable
        fundsOnHold:
          type: string
          description: Cash reserved for the unfilled portion of a resting buy order; omitted when unavailable

    PlaceOrderBatchSuccessResult:
      type: object
      additionalProperties: false
      required:
        - order
      properties:
        order:
          $ref: '#/components/schemas/BatchOrderResponse'

    PlaceOrderBatchErrorResult:
      type: object
      additionalProperties: false
      required:
        - error
        - message
      properties:
        error:
          type: string
          description: Error class for a rejected entry
          example: "InsufficientFunds"
        message:
          type: string
          description: Human-readable detail for a rejected entry
          example: "Insufficient funds"

    PlaceOrderBatchResult:
      description: Exactly one outcome is present. Accepted entries contain `order`; rejected entries contain `error` and `message`.
      oneOf:
        - $ref: '#/components/schemas/PlaceOrderBatchSuccessResult'
        - $ref: '#/components/schemas/PlaceOrderBatchErrorResult'

    PlaceOrderBatchResponse:
      type: object
      required:
        - results
      properties:
        results:
          type: array
          minItems: 1
          maxItems: 20
          description: One result for each submitted order, in request order.
          items:
            $ref: '#/components/schemas/PlaceOrderBatchResult'

    CancelOrderBatchRequest:
      type: object
      required:
        - orderIds
      properties:
        orderIds:
          type: array
          minItems: 1
          maxItems: 20
          description: Order IDs to cancel. Each ID may be an integer or a quoted numeric string. All IDs are validated before any cancellation is attempted.
          items:
            oneOf:
              - type: integer
                format: int64
                example: 12345678
              - type: string
                pattern: '^\d+$'
                example: "12345678"

    CancelOrderBatchSuccessResult:
      type: object
      additionalProperties: false
      required:
        - orderId
        - result
      properties:
        orderId:
          type: integer
          format: int64
          description: Order ID from the corresponding request entry.
          example: 12345678
        result:
          type: string
          enum: [ok]

    CancelOrderBatchErrorResult:
      type: object
      additionalProperties: false
      required:
        - orderId
        - error
        - message
      properties:
        orderId:
          type: integer
          format: int64
          description: Order ID from the corresponding request entry.
          example: 12345678
        error:
          type: string
          description: Error class for a rejected cancellation
          example: "OrderNotFound"
        message:
          type: string
          description: Human-readable detail for a rejected cancellation
          example: "Order 12345678 not found"

    CancelOrderBatchResult:
      description: Exactly one outcome is present. Successful entries contain `orderId` and `result`; rejected entries contain `orderId`, `error`, and `message`.
      oneOf:
        - $ref: '#/components/schemas/CancelOrderBatchSuccessResult'
        - $ref: '#/components/schemas/CancelOrderBatchErrorResult'

    CancelOrderBatchResponse:
      type: object
      required:
        - results
      properties:
        results:
          type: array
          minItems: 1
          maxItems: 20
          description: One result for each requested cancellation, in request order.
          items:
            $ref: '#/components/schemas/CancelOrderBatchResult'

    OrderResponse:
      type: object
      properties:
        orderId:
          type: integer
          format: int64
          example: 12345678
        hashOrderId:
          type: string
          nullable: true
        clientOrderId:
          type: string
          nullable: true
        globalOrderId:
          type: string
          nullable: true
        status:
          $ref: '#/components/schemas/OrderStatus'
        symbol:
          type: string
        side:
          $ref: '#/components/schemas/OrderSide'
        outcome:
          $ref: '#/components/schemas/Outcome'
        orderType:
          $ref: '#/components/schemas/OrderType'
        quantity:
          type: string
          description: Original order quantity
        filledQuantity:
          type: string
          description: Amount filled so far
        remainingQuantity:
          type: string
          description: Amount remaining to fill
        price:
          type: string
          description: Limit price
        stopPrice:
          type: string
          nullable: true
          description: Stop trigger price (populated for `stop-limit` orders)
        avgExecutionPrice:
          type: string
          nullable: true
          description: Average price of fills
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        cancelledAt:
          type: string
          format: date-time
          nullable: true
        contractMetadata:
          $ref: '#/components/schemas/ContractMetadata'

    OrdersResponse:
      type: object
      properties:
        orders:
          type: array
          items:
            $ref: '#/components/schemas/OrderResponse'
        pagination:
          $ref: '#/components/schemas/PaginationSimple'

    # QuoteByQuantityResponse:
    #   type: object
    #   properties:
    #     symbol:
    #       type: string
    #     quantity:
    #       type: string
    #       description: Requested quantity
    #     bestPrice:
    #       type: string
    #       description: Best available price
    #     executionPrice:
    #       type: string
    #       description: Expected execution price
    #     estimatedSpend:
    #       type: string
    #       description: Estimated total spend before fees
    #     estimatedFees:
    #       type: string
    #       description: Estimated fees
    #     totalCost:
    #       type: string
    #       description: Total cost including fees
    #     liquidity:
    #       type: string
    #       description: Available liquidity
    #     priceImpact:
    #       type: string
    #       nullable: true
    #       description: Expected price impact
    #     marketDepth:
    #       $ref: '#/components/schemas/OrderBookDepth'
    #     warning:
    #       type: string
    #       nullable: true
    #       description: Warning message if applicable
    #     quoteExpiry:
    #       type: string
    #       format: date-time
    #       description: When this quote expires

    # QuoteBySpendResponse:
    #   type: object
    #   properties:
    #     symbol:
    #       type: string
    #     totalSpend:
    #       type: string
    #       description: Requested spend amount
    #     bestPrice:
    #       type: string
    #     executionPrice:
    #       type: string
    #     estimatedQuantity:
    #       type: string
    #       description: Estimated quantity for the spend
    #     estimatedFees:
    #       type: string
    #     totalCost:
    #       type: string
    #     liquidity:
    #       type: string
    #     priceImpact:
    #       type: string
    #       nullable: true
    #     marketDepth:
    #       $ref: '#/components/schemas/OrderBookDepth'
    #     warning:
    #       type: string
    #       nullable: true
    #     quoteExpiry:
    #       type: string
    #       format: date-time

    Position:
      type: object
      properties:
        symbol:
          type: string
        instrumentId:
          type: integer
          format: int64
        totalQuantity:
          type: string
          description: Total position size
        quantityOnHold:
          type: string
          description: Quantity currently on hold from open orders
        avgPrice:
          type: string
          description: Average entry price
        outcome:
          $ref: '#/components/schemas/Outcome'
        contractMetadata:
          $ref: '#/components/schemas/ContractMetadata'
        prices:
          $ref: '#/components/schemas/PositionPrices'
        resolutionSide:
          type: string
          nullable: true
          description: Winning outcome ("yes" or "no") if the contract has resolved
        isAboveAutoStartThreshold:
          type: boolean
          description: Whether the position is above the auto-start threshold
        isLive:
          type: boolean
          description: Whether the market is currently live/active
        realizedPl:
          type: string
          nullable: true
          description: Realized profit/loss from sells
        marketValue:
          type: string
          description: Mark-to-market value of the position in USD at the current sell price (bestBid for YES, bestAsk for NO). **Absent** from the response when the held outcome has no live sell quote (no liquidity to sell into) — surface a no-liquidity state rather than a price the user cannot transact at. `lastTradePrice` is still returned for display. Treat as `Optional<T>`.
          example: "65.00"
        unrealizedPnl:
          type: string
          description: Unrealized P&L in USD (`marketValue - costBasis`). **Absent** whenever `marketValue` is absent. Treat as `Optional<T>`.
          example: "12.50"
        unrealizedPct:
          type: number
          format: double
          description: Unrealized P&L as a percentage of cost basis. Expressed as a percent (e.g. `12.5` represents 12.5%, **not** `0.125`); rounded to 4 decimal places. **Absent** when there is no live sell quote, or when cost basis is zero. Treat as `Optional<T>`.
          example: 23.81

    PositionPrices:
      type: object
      nullable: true
      description: Current bid/ask/last-trade prices for the contract
      required:
        - buy
        - sell
      properties:
        buy:
          type: object
          properties:
            yes:
              type: string
              nullable: true
            no:
              type: string
              nullable: true
        sell:
          type: object
          properties:
            yes:
              type: string
              nullable: true
            no:
              type: string
              nullable: true
        bestBid:
          type: string
          nullable: true
        bestAsk:
          type: string
          nullable: true
        lastTradePrice:
          type: string
          nullable: true

    PositionsResponse:
      type: object
      properties:
        positions:
          type: array
          items:
            $ref: '#/components/schemas/Position'
        total:
          type: integer
          nullable: true
          description: Total number of positions (for pagination)

    SettledPosition:
      type: object
      description: A historically settled position in a resolved prediction market contract.
      properties:
        accountId:
          type: integer
          format: int64
          description: Account that held the position
        instrumentId:
          type: integer
          format: int64
          description: Unique instrument identifier for the contract
        instrumentSymbol:
          type: string
          description: Contract instrument symbol
          example: "GEMI-FEDJAN26-DN25"
        position:
          type: string
          description: Signed position held at settlement. Positive values represent a `yes` position; negative values represent a `no` position.
          example: "125"
        positionQuantity:
          type: string
          description: Absolute quantity held at settlement (unsigned)
          example: "125"
        outcome:
          $ref: '#/components/schemas/Outcome'
        payout:
          type: string
          description: Payout received from settlement. `0` when the position lost.
          example: "125.00"
        resolutionSide:
          allOf:
            - $ref: '#/components/schemas/Outcome'
          description: The winning outcome of the contract
        settledAt:
          type: string
          format: date-time
          description: Settlement timestamp (ISO 8601)
        contractMetadata:
          $ref: '#/components/schemas/ContractMetadata'
        costBasis:
          type: string
          nullable: true
          description: Total amount spent to enter the position, net of any prior realized P&L from partial sells. Omitted when cost-basis data is not available.
          example: "78.75"
        realizedPnl:
          type: string
          nullable: true
          description: Realized profit or loss recorded from sells prior to settlement. Omitted when not available.
          example: "0"
        netProfit:
          type: string
          nullable: true
          description: Net profit for the position, computed as `payout - costBasis + realizedPnl`. Omitted when `costBasis` is not available.
          example: "46.25"

    SettledPositionsResponse:
      type: object
      properties:
        positions:
          type: array
          items:
            $ref: '#/components/schemas/SettledPosition'
        total:
          type: integer
          nullable: true
          description: Total number of settled positions across all pages for the current filter set.
        totalPayout:
          type: string
          description: Sum of `payout` across all settled positions in the filter set. Retained for binary back-compat with the legacy response shape; **field is absent (not `null`) on the unified backend** because computing a roll-up over the full filtered set would require a separate aggregate query (deferred until a partner asks). Play's default `OptionHandlers` omits absent `Option` fields rather than emitting `null`.
        totalCostBasis:
          type: string
          description: Sum of `costBasis` across all settled positions in the filter set. Retained for binary back-compat; **field is absent (not `null`) on the unified backend** (see `totalPayout`).
        totalNetProfit:
          type: string
          description: Sum of `netProfit` across all settled positions in the filter set. Retained for binary back-compat; **field is absent (not `null`) on the unified backend** (see `totalPayout`).
        cashOuts:
          type: array
          description: |
            Cash-outs (early sells before contract resolution) in the same account-scoped time window as the returned page's settled positions. Field is absent (not `null`) when `withCashOuts=true` is not passed on the request. `positions[]` pagination is unaffected — `limit`/`offset` continue to scope `positions[]` only.
          items:
            $ref: '#/components/schemas/CashedOutPosition'
        totalCashOutProceeds:
          type: string
          description: Sum of `cashOuts[].proceeds` over the returned cash-outs. Field is absent (not `null`) when `withCashOuts=true` is not passed on the request.
          example: "120.00"
        totalCashOutCostBasis:
          type: string
          description: Sum of `cashOuts[].costBasis` over the returned cash-outs. Field is absent (not `null`) when `withCashOuts=true` is not passed on the request.
          example: "100.00"
        totalCashOutNetProfit:
          type: string
          description: Sum of `cashOuts[].netProfit` over the returned cash-outs. Field is absent (not `null`) when `withCashOuts=true` is not passed on the request.
          example: "20.00"

    CashedOutPosition:
      type: object
      required:
        - accountId
        - instrumentId
        - instrumentSymbol
        - timestamp
        - filledQuantity
        - side
        - proceeds
        - costBasis
        - netProfit
      description: |
        A qualifying cash-out (early sell before contract resolution) with cost-basis context. Exposed only via the `withCashOuts=true` sibling array on `POST /v1/prediction-markets/positions/settled`. Distinct from `SettledPosition` — cash-outs don't have a `payout` or `resolutionSide` since the contract hadn't resolved when the user sold.
      properties:
        accountId:
          type: integer
          format: int64
          description: Account that held the position.
          example: 456
        instrumentId:
          type: integer
          format: int64
          description: Contract instrument ID.
          example: 16789219
        instrumentSymbol:
          type: string
          description: Contract instrument symbol.
          example: "GEMI-BTC100K-YES"
        timestamp:
          type: string
          format: date-time
          description: Wall-clock timestamp when the cash-out order closed (ISO 8601).
          example: "2026-05-15T14:30:00.000Z"
        filledQuantity:
          type: string
          description: Quantity sold (cumulative filled quantity on the cash-out order).
          example: "10"
        side:
          type: string
          enum: [sell]
          description: Always `sell` for cash-outs.
          example: "sell"
        proceeds:
          type: string
          description: Amount received from the sale in USD. For prediction sells, proceeds flow through `cash_balance` rather than `closed_orders.total_spend`, so the value is derived from position-balance snapshots before/after the fill.
          example: "10.50"
        costBasis:
          type: string
          description: Cost basis allocated proportionally to the filled quantity (`(costBasisSpend / costBasisPositionBalance) * filledQuantity`).
          example: "10.00"
        netProfit:
          type: string
          description: Realized P&L from this cash-out fill (`proceeds - costBasis`). Equals the ledger `realized_pl` delta on the position-balance row pair around the fill; falls back to `0` under transient market-data lag so a missing post-fill snapshot can't poison the page.
          example: "0.50"
        contractMetadata:
          $ref: '#/components/schemas/ContractMetadata'

    ContractShareVolume:
      type: object
      properties:
        symbol:
          type: string
          description: Contract instrument symbol
          example: "GEMI-FED260318-CUT25"
        totalQty:
          type: string
          description: Total taker volume across all participants (in shares)
          example: "94625"
        userAggressorQty:
          type: string
          nullable: true
          description: The authenticated user's taker (aggressor) volume (in shares)
          example: "1"
        userRestingQty:
          type: string
          nullable: true
          description: The authenticated user's maker (resting) volume (in shares)
          example: "0"

    VolumeMetricsResponse:
      type: object
      properties:
        eventTicker:
          type: string
          description: The event ticker
          example: "FED260318"
        contracts:
          type: array
          items:
            $ref: '#/components/schemas/ContractShareVolume'

    MakerRebateRateRule:
      type: object
      required:
        - id
        - rebate_multiplier_bps
        - effective_from
      properties:
        id:
          type: integer
          format: int64
          description: Stable identifier for this rate rule.
          example: 12
        rebate_multiplier_bps:
          type: integer
          format: int32
          description: Portion of the maker fee that is rebated, in basis points (10000 bps = 100%).
          example: 5000
        effective_from:
          type: string
          format: date-time
          nullable: true
          description: ISO-8601 timestamp at which this rule becomes effective. Always present; in practice never `null`.
          example: "2026-03-19T00:00:00Z"
        category:
          type: string
          description: Market category this rule applies to. When absent, the rule applies to all categories.
          example: "Crypto"
        effective_to:
          type: string
          format: date-time
          description: ISO-8601 timestamp after which this rule is superseded. Omitted when the rule is still current.
          example: "2026-04-19T00:00:00Z"

    MakerRebateRatesResponse:
      type: object
      required:
        - rate_rules
      properties:
        rate_rules:
          type: array
          items:
            $ref: '#/components/schemas/MakerRebateRateRule'

    MakerRebatePayout:
      type: object
      required:
        - id
        - total_volume_usd
        - total_rebate_usd
        - total_fill_count
        - status
        - paid_at
        - created_at
      properties:
        id:
          type: integer
          format: int64
          description: Stable payout identifier.
          example: 9182
        total_volume_usd:
          type: string
          description: Total qualifying maker volume contributing to this payout, in USD.
          example: "12450.00"
        total_rebate_usd:
          type: string
          description: Total rebate paid, in USD.
          example: "6.23"
        total_fill_count:
          type: integer
          format: int32
          description: Number of qualifying maker fills that contributed to the payout.
          example: 187
        status:
          type: string
          description: Payout status (e.g. `PENDING`, `PAID`).
          example: "PAID"
        paid_at:
          type: string
          format: date-time
          nullable: true
          description: ISO-8601 timestamp at which the rebate was credited. Always present; `null` for payouts that have not yet been paid.
          example: "2026-05-20T21:00:00Z"
        created_at:
          type: string
          format: date-time
          nullable: true
          description: ISO-8601 timestamp at which the payout row was created. Always present.
          example: "2026-05-20T20:55:12Z"

    MakerRebatePayoutsResponse:
      type: object
      required:
        - payouts
      properties:
        payouts:
          type: array
          items:
            $ref: '#/components/schemas/MakerRebatePayout'

    MakerRebateLifetimeSummary:
      type: object
      required:
        - total_earned_usd
        - total_fill_count
        - total_volume_usd
        - payout_count
        - first_payout_date
        - last_payout_date
      properties:
        total_earned_usd:
          type: string
          description: Sum of `total_rebate_usd` across payouts in the window.
          example: "152.40"
        total_fill_count:
          type: integer
          format: int64
          description: Sum of qualifying maker fills across payouts in the window.
          example: 4218
        total_volume_usd:
          type: string
          description: Sum of qualifying maker volume (USD) across payouts in the window.
          example: "304800.00"
        payout_count:
          type: integer
          format: int32
          description: Number of payouts in the window. Always present; `0` when no payouts exist in the window.
          example: 27
        first_payout_date:
          type: string
          format: date
          nullable: true
          description: Date of the earliest payout in the window, or `null` if no payouts exist.
          example: "2026-03-19"
        last_payout_date:
          type: string
          format: date
          nullable: true
          description: Date of the most recent payout in the window, or `null` if no payouts exist.
          example: "2026-05-20"

    LiquidityRewardsConfig:
      type: object
      required:
        - enabled
      properties:
        max_spread_cents:
          type: integer
          format: int32
          description: Quotes wider than this spread score zero in the scoring algorithm. Only present when `enabled` is `true`.
          example: 10
        min_payout_threshold_usd:
          type: string
          description: Daily reward amounts below this threshold are suppressed (sub-threshold accounts get no row at all). Only present when `enabled` is `true`.
          example: "1.00"
        enabled:
          type: boolean
          description: 'True when the program is fully configured upstream. When false, the response collapses to `{ "enabled": false }` only.'
          example: true

    LiquidityRewardEvent:
      type: object
      required:
        - event_ticker
        - title
        - category
        - daily_pool_usd
        - pool_source
        - ends_at
        - qualifying_maker_count
      properties:
        event_ticker:
          type: string
          description: Event ticker (e.g. `BTC2605202100`).
          example: "BTC2605202100"
        title:
          type: string
          description: Event title.
          example: "BTC above $95,000?"
        category:
          type: string
          description: Market category.
          example: "Crypto"
        daily_pool_usd:
          type: string
          description: Daily USD reward pool budgeted for this event.
          example: "500.00"
        pool_source:
          type: string
          enum:
            - event_override
            - category_default
            - unspecified
          description: Whether the pool came from a per-event override or the category default.
          example: "event_override"
        ends_at:
          type: string
          format: date-time
          nullable: true
          description: ISO-8601 timestamp at which the event ends and stops scoring. `null` when the underlying event has no end timestamp set.
          example: "2026-05-20T21:00:00Z"
        qualifying_maker_count:
          type: integer
          format: int32
          description: Number of accounts that met qualifying-maker criteria in the most recent snapshot window for this event.
          example: 14
        icon_url:
          type: string
          description: Optional URL for the event icon. Omitted when not configured.
          example: "https://example.com/btc.png"

    LiquidityRewardsEventsResponse:
      type: object
      required:
        - events
        - pagination
        - last_score_date
      properties:
        events:
          type: array
          items:
            $ref: '#/components/schemas/LiquidityRewardEvent'
        pagination:
          $ref: '#/components/schemas/Pagination'
        last_score_date:
          type: string
          format: date
          nullable: true
          description: Most recent date for which scoring has been written. `null` when no scoring has run yet.
          example: "2026-05-19"

    LiquidityEventScore:
      type: object
      required:
        - event_id
        - event_name
        - category_name
        - normalized_score
        - snapshot_count
        - total_snapshots
        - event_reward_usd
      properties:
        event_id:
          type: integer
          format: int64
          description: Stable event identifier.
          example: 1234567890
        event_name:
          type: string
          description: Event title.
          example: "BTC above $95,000?"
        category_name:
          type: string
          description: Market category.
          example: "Crypto"
        normalized_score:
          type: string
          description: This account's normalized score for the event on the scoring date (0-1 range as a decimal string).
          example: "0.4521"
        snapshot_count:
          type: integer
          format: int32
          description: Number of snapshots in which this account had a qualifying quote.
          example: 1180
        total_snapshots:
          type: integer
          format: int32
          description: Total snapshots taken for the event on the scoring date.
          example: 1440
        event_reward_usd:
          type: string
          description: Portion of the day's total reward attributed to this event.
          example: "8.20"

    LiquidityDailySummary:
      type: object
      required:
        - payout_date
        - total_reward_usd
        - payout_status
        - paid_at
        - events
      properties:
        payout_date:
          type: string
          format: date
          description: Date the payout applies to (Eastern Time).
          example: "2026-05-07"
        total_reward_usd:
          type: string
          description: Total USD reward for the day across all events the account scored on.
          example: "12.45"
        payout_status:
          type: string
          description: Status of the day's payout (e.g. `PENDING`, `PAID`, `ZERO_AMOUNT`).
          example: "PAID"
        paid_at:
          type: string
          format: date-time
          nullable: true
          description: ISO-8601 timestamp the day's payout was credited. Always present; `null` if not yet paid.
          example: "2026-05-08T21:00:00Z"
        events:
          type: array
          description: Per-event score breakdown showing how the day's total was distributed.
          items:
            $ref: '#/components/schemas/LiquidityEventScore'

    LiquidityRewardsDailySummaryResponse:
      type: object
      required:
        - daily_summaries
      properties:
        daily_summaries:
          type: array
          items:
            $ref: '#/components/schemas/LiquidityDailySummary'

    LiquidityRewardsLifetimeSummary:
      type: object
      required:
        - total_earned_usd
        - payout_count
        - first_payout_date
        - last_payout_date
      properties:
        total_earned_usd:
          type: string
          description: Sum of `total_reward_usd` across daily payouts in the window.
          example: "84.20"
        payout_count:
          type: integer
          format: int32
          description: Number of daily payouts in the window. Always present; `0` when no payouts exist in the window.
          example: 12
        first_payout_date:
          type: string
          format: date
          nullable: true
          description: Date of the earliest payout in the window, or `null` if no payouts exist.
          example: "2026-05-08"
        last_payout_date:
          type: string
          format: date
          nullable: true
          description: Date of the most recent payout in the window, or `null` if no payouts exist.
          example: "2026-05-20"
