openapi: 3.0.3
info:
  title: Polymarket Data API
  version: 1.0.0
  description: 'HTTP API for Polymarket data. This specification documents all public routes.

    '
servers:
- url: https://data-api.polymarket.com
  description: Relative server (same host)
tags:
- name: Data API Status
  description: Data API health check
- name: Core
- name: Builders
- name: Misc
components:
  schemas:
    Address:
      type: string
      description: User Profile Address (0x-prefixed, 40 hex chars)
      pattern: ^0x[a-fA-F0-9]{40}$
      example: '0x56687bf447db6ffa42ffe2204a05edaa20f55839'
    Hash64:
      type: string
      description: 0x-prefixed 64-hex string
      pattern: ^0x[a-fA-F0-9]{64}$
      example: '0xdd22472e552920b8438158ea7238bfadfa4f736aa4cee91a6b86c39ead110917'
    HealthResponse:
      type: object
      properties:
        data:
          type: string
          example: OK
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
      required:
      - error
    Position:
      type: object
      properties:
        proxyWallet:
          $ref: '#/components/schemas/Address'
        asset:
          type: string
        conditionId:
          $ref: '#/components/schemas/Hash64'
        size:
          type: number
        avgPrice:
          type: number
        initialValue:
          type: number
        grossInitialValue:
          type: number
          description: >-
            Remaining entry basis including attributed BUY fees, at six-decimal
            source precision. `initialValue` and `avgPrice` keep their
            fee-exclusive semantics, so the fee-exclusive basis is
            `grossInitialValue - entryFeesUsdc`. Optional: treat an omitted
            field as unavailable rather than as zero.
        entryFeesUsdc:
          type: number
          description: >-
            Attributed BUY-fee component of `grossInitialValue`, at six-decimal
            source precision. SELL fees are exit costs and are never included.
            Returned as an explicit `0` when the fee component is zero.
            Optional: treat an omitted field as unavailable rather than as zero.
        currentValue:
          type: number
        cashPnl:
          type: number
        percentPnl:
          type: number
        totalBought:
          type: number
        realizedPnl:
          type: number
        percentRealizedPnl:
          type: number
        curPrice:
          type: number
        redeemable:
          type: boolean
        mergeable:
          type: boolean
        title:
          type: string
        slug:
          type: string
        icon:
          type: string
        eventSlug:
          type: string
        outcome:
          type: string
        outcomeIndex:
          type: integer
        oppositeOutcome:
          type: string
        oppositeAsset:
          type: string
        endDate:
          type: string
        negativeRisk:
          type: boolean
    ClosedPosition:
      type: object
      properties:
        proxyWallet:
          $ref: '#/components/schemas/Address'
        asset:
          type: string
        conditionId:
          $ref: '#/components/schemas/Hash64'
        avgPrice:
          type: number
        totalBought:
          type: number
        realizedPnl:
          type: number
        curPrice:
          type: number
        timestamp:
          type: integer
          format: int64
        title:
          type: string
        slug:
          type: string
        icon:
          type: string
        eventSlug:
          type: string
        outcome:
          type: string
        outcomeIndex:
          type: integer
        oppositeOutcome:
          type: string
        oppositeAsset:
          type: string
        endDate:
          type: string
    Trade:
      type: object
      properties:
        proxyWallet:
          $ref: '#/components/schemas/Address'
        side:
          type: string
          enum:
          - BUY
          - SELL
        asset:
          type: string
        conditionId:
          $ref: '#/components/schemas/Hash64'
        size:
          type: number
        price:
          type: number
        timestamp:
          type: integer
          format: int64
        title:
          type: string
        slug:
          type: string
        icon:
          type: string
          description: >-
            Market artwork. Falls back to the market image, then to the parent
            event's icon and image, when the market has no icon of its own.
        eventSlug:
          type: string
        outcome:
          type: string
        outcomeIndex:
          type: integer
        name:
          type: string
        pseudonym:
          type: string
        bio:
          type: string
        profileImage:
          type: string
        profileImageOptimized:
          type: string
        transactionHash:
          type: string
    Activity:
      type: object
      properties:
        proxyWallet:
          $ref: '#/components/schemas/Address'
        timestamp:
          type: integer
          format: int64
        conditionId:
          $ref: '#/components/schemas/Hash64'
        type:
          type: string
          enum:
          - TRADE
          - SPLIT
          - MERGE
          - REDEEM
          - REWARD
          - CONVERSION
          - DEPOSIT
          - WITHDRAWAL
          - YIELD
          - MAKER_REBATE
          - TAKER_REBATE
          - REFERRAL_REWARD
        size:
          type: number
          description: >-
            Token amount for this row. On `REDEEM` rows it is the number of
            tokens burned for this row's outcome, so redeeming both sides of a
            market returns one row per outcome instead of a single combined row.
        usdcSize:
          type: number
          description: >-
            USDC amount for this row. On `REDEEM` rows it is the payout for this
            row's outcome and is `0` for a losing outcome; the rows of one
            redemption sum to the total payout.
        transactionHash:
          type: string
        price:
          type: number
        asset:
          type: string
          description: >-
            Token ID this row refers to. Populated on `REDEEM` rows with the
            token that row settles. Empty when the row is not token-specific.
        side:
          type: string
          enum:
          - BUY
          - SELL
        outcomeIndex:
          type: integer
          description: >-
            Zero-based index of this row's outcome in the market's `outcomes`
            array, so `outcome` always equals `outcomes[outcomeIndex]`. On
            `REDEEM` rows it identifies the outcome the row settles, not the
            market's winning outcome. `999` means the outcome could not be
            determined, in which case `outcome` is empty.
        title:
          type: string
        slug:
          type: string
        icon:
          type: string
          description: >-
            Market artwork. Falls back to the market image, then to the parent
            event's icon and image, when the market has no icon of its own.
            Empty on `CONVERSION` rows.
        eventSlug:
          type: string
        outcome:
          type: string
        name:
          type: string
        pseudonym:
          type: string
        bio:
          type: string
        profileImage:
          type: string
        profileImageOptimized:
          type: string
        isCombo:
          type: boolean
          description: >-
            True when this row is part of a combinatorial (multi-market) position.
            Flag only — combo detail is not embedded here. The row's conditionId
            equals the combo's combo_condition_id; pass it to /v1/activity/combos
            or /v1/positions/combos via market_id to fetch legs and detail.
            Omitted on non-combo rows.
    Holder:
      type: object
      properties:
        proxyWallet:
          $ref: '#/components/schemas/Address'
        bio:
          type: string
        asset:
          type: string
        pseudonym:
          type: string
        amount:
          type: number
        displayUsernamePublic:
          type: boolean
        outcomeIndex:
          type: integer
        name:
          type: string
        profileImage:
          type: string
        profileImageOptimized:
          type: string
    MetaHolder:
      type: object
      properties:
        token:
          type: string
        holders:
          type: array
          items:
            $ref: '#/components/schemas/Holder'
    Traded:
      type: object
      properties:
        user:
          $ref: '#/components/schemas/Address'
        traded:
          type: integer
    RevisionEntry:
      type: object
      properties:
        revision:
          type: string
        timestamp:
          type: integer
    RevisionPayload:
      type: object
      properties:
        questionID:
          $ref: '#/components/schemas/Hash64'
        revisions:
          type: array
          items:
            $ref: '#/components/schemas/RevisionEntry'
    Value:
      type: object
      properties:
        user:
          $ref: '#/components/schemas/Address'
        value:
          type: number
    OpenInterest:
      type: object
      properties:
        market:
          $ref: '#/components/schemas/Hash64'
        value:
          type: number
    MarketVolume:
      type: object
      properties:
        market:
          $ref: '#/components/schemas/Hash64'
        value:
          type: number
    LiveVolume:
      type: object
      properties:
        total:
          type: number
        markets:
          type: array
          items:
            $ref: '#/components/schemas/MarketVolume'
    OtherSize:
      type: object
      properties:
        id:
          type: integer
        user:
          $ref: '#/components/schemas/Address'
        size:
          type: number
    LeaderboardEntry:
      type: object
      properties:
        rank:
          type: string
          description: The rank position of the builder
        builder:
          type: string
          description: The builder name or identifier
        builderCode:
          type: string
          description: The builder's onchain attribution code as attached to orders via `builderCode` (see CLOB V2). Empty string for legacy builders without a registered code.
        volume:
          type: number
          description: Total trading volume attributed to this builder
        activeUsers:
          type: integer
          description: Number of active users for this builder
        verified:
          type: boolean
          description: Whether the builder is verified
        builderLogo:
          type: string
          description: URL to the builder's logo image
    BuilderVolumeEntry:
      type: object
      properties:
        dt:
          type: string
          format: date-time
          description: The timestamp for this volume entry in ISO 8601 format
          example: '2025-11-15T00:00:00Z'
        builder:
          type: string
          description: The builder name or identifier
        builderCode:
          type: string
          description: The builder's onchain attribution code as attached to orders via `builderCode` (see CLOB V2). Empty string for legacy builders without a registered code.
        builderLogo:
          type: string
          description: URL to the builder's logo image
        verified:
          type: boolean
          description: Whether the builder is verified
        volume:
          type: number
          description: Trading volume for this builder on this date
        activeUsers:
          type: integer
          description: Number of active users for this builder on this date
        rank:
          type: string
          description: The rank position of the builder on this date
    MarketPositionV1:
      type: object
      properties:
        proxyWallet:
          $ref: '#/components/schemas/Address'
        name:
          type: string
        profileImage:
          type: string
        verified:
          type: boolean
        asset:
          type: string
        conditionId:
          $ref: '#/components/schemas/Hash64'
        avgPrice:
          type: number
        size:
          type: number
        currPrice:
          type: number
        currentValue:
          type: number
        cashPnl:
          type: number
        totalBought:
          type: number
        realizedPnl:
          type: number
        totalPnl:
          type: number
        outcome:
          type: string
        outcomeIndex:
          type: integer
    MetaMarketPositionV1:
      type: object
      properties:
        token:
          type: string
          description: The outcome token asset ID
        positions:
          type: array
          items:
            $ref: '#/components/schemas/MarketPositionV1'
    TraderLeaderboardEntry:
      type: object
      properties:
        rank:
          type: string
          description: The rank position of the trader
        proxyWallet:
          $ref: '#/components/schemas/Address'
        userName:
          type: string
          description: The trader's username
        vol:
          type: number
          description: Trading volume for this trader
        pnl:
          type: number
          description: Profit and loss for this trader
        profileImage:
          type: string
          description: URL to the trader's profile image
        xUsername:
          type: string
          description: The trader's X (Twitter) username
        verifiedBadge:
          type: boolean
          description: Whether the trader has a verified badge
    ComboConditionId:
      type: string
      description: >-
        Combo condition ID (0x-prefixed, 62 hex chars / bytes31). Equals the
        market_id (unified) / conditionId (legacy) of isCombo rows on /activity.
      pattern: ^0x[a-fA-F0-9]{62}$
      example: '0x0391ab0ebea17b65ba87e071b0566e816b0000000000000000000000000000'
    Pagination:
      type: object
      description: >-
        Standard pagination metadata. No total count; has_more is derived from
        page fullness. next_cursor is opaque.
      properties:
        limit:
          type: integer
        offset:
          type: integer
        has_more:
          type: boolean
        next_cursor:
          type: string
          nullable: true
          description: >-
            Opaque signed cursor for the next page; null when has_more is false.
            Pass it back verbatim as ?cursor= on the next request (keep the same
            sort where the endpoint has one). Never parse or construct it. On
            cursor-enabled endpoints this makes deep pagination O(page) and
            stable against concurrent inserts.
    ComboEvent:
      type: object
      properties:
        event_id:
          type: string
        event_slug:
          type: string
        event_title:
          type: string
        event_image:
          type: string
    ComboMarket:
      type: object
      properties:
        market_id:
          type: string
        slug:
          type: string
        title:
          type: string
        outcome:
          type: string
        image_url:
          type: string
        icon_url:
          type: string
        category:
          type: string
        subcategory:
          type: string
        tags:
          type: array
          items:
            type: string
        end_date:
          type: string
          description: RFC3339 UTC
        event:
          $ref: '#/components/schemas/ComboEvent'
    ComboLeg:
      type: object
      properties:
        leg_index:
          type: integer
        leg_position_id:
          type: string
        leg_condition_id:
          type: string
          description: The leg market's condition ID (distinct from the combo's).
        leg_outcome_index:
          type: integer
        leg_outcome_label:
          type: string
        leg_status:
          type: string
          enum:
          - OPEN
          - RESOLVED_PARTIAL
          - RESOLVED_WIN
          - RESOLVED_LOSS
          description: >-
            Live per-leg resolution state, derived from the leg market's
            on-chain payout vector. Markets resolved with a fractional payout
            (e.g. a 50/50 void) surface as RESOLVED_PARTIAL with
            leg_resolved_at set.
        leg_resolved_at:
          type: string
          nullable: true
          description: >-
            RFC3339 UTC. Set once the leg's market resolves on-chain, including
            fractional resolutions that still report leg_status OPEN.
        leg_current_price:
          type: string
          description: >-
            Live price for the leg outcome (decimal string, 0–1). "0" when no
            price is available.
        market:
          $ref: '#/components/schemas/ComboMarket'
    ComboPosition:
      type: object
      properties:
        combo_condition_id:
          $ref: '#/components/schemas/ComboConditionId'
        combo_position_id:
          type: string
        module_id:
          type: integer
          description: 3 = Combinatorial
        user_address:
          $ref: '#/components/schemas/Address'
        shares_balance:
          type: string
          description: Decimal string (precision-preserving).
        entry_avg_price_usdc:
          type: string
        entry_cost_usdc:
          type: string
          description: >-
            REMAINING cost basis (entry_avg_price × shares_balance). Reads ~0
            after a winning combo is redeemed — use total_cost_usdc to display
            what was paid on closed positions.
        realized_payout_usdc:
          type: string
          description: >-
            Gross redemption proceeds (winning combo shares redeem 1:1 at $1).
            "0.00" while OPEN / unredeemed / RESOLVED_LOSS; accumulates under
            PARTIAL. Gross payout, not net PnL — net = realized_payout_usdc −
            total_cost_usdc.
        total_cost_usdc:
          type: string
          description: >-
            Original cost basis = entry_avg_price × (shares_balance +
            realized_payout). Survives redemption burning the shares; equals
            entry_cost_usdc while OPEN.
        gross_entry_cost_usdc:
          type: string
          description: >-
            Exact gross entry basis including attributed BUY fees, as a
            six-decimal precision-preserving string (e.g. "8999.997488") —
            parse it as a decimal, never through a float. Tracks the remaining
            basis while the position is live and freezes once it is terminal.
            Exact net basis = gross_entry_cost_usdc − entry_fees_usdc.
        entry_fees_usdc:
          type: string
          description: >-
            BUY-fee portion of the same basis, as a six-decimal
            precision-preserving string. SELL fees are excluded; always ≤
            gross_entry_cost_usdc.
        status:
          type: string
          enum:
          - OPEN
          - PARTIAL
          - RESOLVED_PARTIAL
          - RESOLVED_WIN
          - RESOLVED_LOSS
          description: >-
            RESOLVED_PARTIAL = the combo resolved at a fractional payout (e.g.
            a leg voided 50/50) — redemption pays the fractional value per
            share.
        first_entry_at:
          type: string
          description: RFC3339 UTC
        resolved_at:
          type: string
          nullable: true
        updated_at:
          type: string
          description: >-
            Last-modified time (UTC, ISO 8601). Bumps on any recompute of the
            row (trade, redemption, resolution classification) — the
            incremental-sync watermark field. Omitted on responses served by
            the legacy backend.
        legs_total:
          type: integer
        legs_resolved:
          type: integer
        legs_pending:
          type: integer
        legs:
          type: array
          items:
            $ref: '#/components/schemas/ComboLeg'
    ComboActivity:
      type: object
      properties:
        id:
          type: string
        event_kind:
          type: string
          deprecated: true
          description: Deprecated. Use `type` instead.
        side:
          type: string
          deprecated: true
          description: Deprecated. Use `type` instead.
          enum:
          - Split
          - Merge
          - Convert
          - Compress
          - Wrap
          - Unwrap
          - Redeem
        module_kind:
          type: string
          description: Always Combinatorial.
        user_address:
          $ref: '#/components/schemas/Address'
        combo_condition_id:
          $ref: '#/components/schemas/ComboConditionId'
        combo_position_id:
          type: string
        module_id:
          type: integer
        amount_usdc:
          type: number
          nullable: true
          description: Lifecycle amount; null on redeems.
        payout_usdc:
          type: number
          nullable: true
          description: Redeem payout; null on lifecycle events.
        timestamp:
          type: integer
          format: int64
        tx_dttm:
          type: string
          description: RFC3339 UTC
        tx_hash:
          type: string
        log_index:
          type: integer
        block_number:
          type: integer
          format: int64
        legs:
          type: array
          items:
            $ref: '#/components/schemas/ComboLeg'
    CombosResponse:
      type: object
      properties:
        combos:
          type: array
          items:
            $ref: '#/components/schemas/ComboPosition'
        pagination:
          $ref: '#/components/schemas/Pagination'
    CombosActivityResponse:
      type: object
      properties:
        activity:
          type: array
          items:
            $ref: '#/components/schemas/ComboActivity'
        pagination:
          $ref: '#/components/schemas/Pagination'
    ApprovalContract:
      type: object
      description: >-
        Approval state for one token and spender pair.
      properties:
        id:
          type: string
          description: >-
            Stable identifier for the token and spender pair, such as
            `UsdcExchange` or `CtfExchangeIsApprovedForAll`.
          example: UsdcExchange
        feature:
          type: string
          description: What the approval unlocks.
          enum:
          - trading
          - perps
          - rewards
          - auto-redeem
        token:
          $ref: '#/components/schemas/Address'
        spender:
          $ref: '#/components/schemas/Address'
        standard:
          type: string
          description: >-
            Token standard of the approval. `ERC20` entries carry an allowance
            amount; `ERC1155` entries are an operator flag with no amount.
          enum:
          - ERC20
          - ERC1155
        amount:
          type: string
          description: >-
            Allowance semantics for `ERC20` entries. Entries that require an
            unlimited allowance always report the constant `max`, describing
            what the feature needs rather than what the wallet granted — read
            `approved` for the granted state. Entries that accept any positive
            allowance report the wallet's current allowance in the token's base
            units as a decimal string. Omitted for `ERC1155` entries.
          example: max
        approved:
          type: boolean
          description: >-
            Whether the approval is sufficient for its feature. Unlimited
            trading approvals require the maximum allowance, `perps` and
            `rewards` approvals require any positive allowance, and `ERC1155`
            entries reflect the operator flag.
      required:
      - id
      - feature
      - token
      - spender
      - standard
      - approved
    ApprovalsResponse:
      type: object
      properties:
        address:
          $ref: '#/components/schemas/Address'
        chainId:
          type: integer
          description: Chain the approvals were read on.
          example: 137
        checkedAt:
          type: string
          format: date-time
          description: >-
            RFC 3339 timestamp of when this response was generated. Approval
            state is tracked from onchain events, so this is not the timestamp
            of a fresh onchain read.
          example: '2026-08-10T12:34:56Z'
        contracts:
          type: array
          description: >-
            Every approval Polymarket tracks, in a stable display order. Pairs
            the wallet has never approved are still present with `approved`
            false, so the array length does not change with wallet state.
          items:
            $ref: '#/components/schemas/ApprovalContract'
      required:
      - address
      - chainId
      - checkedAt
      - contracts
paths:
  /:
    get:
      tags:
      - Data API Status
      summary: Data API Health check
      operationId: getDataApiHealth
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'
  /v1/accounting/snapshot:
    get:
      tags:
      - Misc
      summary: Download an accounting snapshot (ZIP of CSVs)
      parameters:
      - in: query
        name: user
        required: true
        schema:
          $ref: '#/components/schemas/Address'
        description: User address (0x-prefixed)
      responses:
        '200':
          description: ZIP file containing `positions.csv` and `equity.csv`.
          content:
            application/zip:
              schema:
                type: string
                format: binary
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v1/approvals:
    get:
      tags:
      - Misc
      summary: Get token approval state for a wallet
      description: >-
        Reports whether a wallet has granted the token approvals Polymarket
        needs, so a client can prompt for the missing ones instead of reading
        each allowance onchain. Every tracked token and spender pair is
        returned, including pairs the wallet has never approved.
      parameters:
      - in: query
        name: user
        required: true
        schema:
          $ref: '#/components/schemas/Address'
        description: User address (0x-prefixed)
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApprovalsResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /positions:
    get:
      tags:
      - Core
      summary: Get current positions for a user
      parameters:
      - in: query
        name: user
        required: true
        schema:
          $ref: '#/components/schemas/Address'
        description: User address (required)
      - in: query
        name: market
        style: form
        explode: false
        schema:
          type: array
          items:
            $ref: '#/components/schemas/Hash64'
        description: Comma-separated list of condition IDs. Mutually exclusive with eventId.
      - in: query
        name: eventId
        style: form
        explode: false
        schema:
          type: array
          items:
            type: integer
            minimum: 1
        description: Comma-separated list of event IDs. Mutually exclusive with market.
      - in: query
        name: sizeThreshold
        schema:
          type: number
          default: 1.0
          minimum: 0
      - in: query
        name: redeemable
        schema:
          type: boolean
          default: false
      - in: query
        name: mergeable
        schema:
          type: boolean
          default: false
      - in: query
        name: includeArchived
        schema:
          type: boolean
          default: false
        description: >-
          Include positions in archived markets that are still active. Archived
          positions are excluded by default.
      - in: query
        name: limit
        schema:
          type: integer
          default: 100
          minimum: 0
          maximum: 500
      - in: query
        name: offset
        schema:
          type: integer
          default: 0
          minimum: 0
          maximum: 10000
      - in: query
        name: sortBy
        schema:
          type: string
          enum:
          - CURRENT
          - INITIAL
          - TOKENS
          - CASHPNL
          - PERCENTPNL
          - TITLE
          - RESOLVING
          - PRICE
          - AVGPRICE
          default: TOKENS
      - in: query
        name: sortDirection
        schema:
          type: string
          enum:
          - ASC
          - DESC
          default: DESC
      - in: query
        name: title
        schema:
          type: string
          maxLength: 100
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Position'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /trades:
    get:
      tags:
      - Core
      summary: Get trades for a user or markets
      parameters:
      - in: query
        name: limit
        schema:
          type: integer
          default: 100
          minimum: 0
          maximum: 10000
        description: Page size. Values above the maximum are clamped to 10000.
      - in: query
        name: offset
        schema:
          type: integer
          default: 0
          minimum: 0
          maximum: 10000
        description: >-
          Starting index for pagination. Requests past the cap are rejected
          with a 400 (never silently clamped). To read history deeper than
          offset 10000, page inside `start`/`end` windows — each window has its
          own offset budget.
      - in: query
        name: takerOnly
        schema:
          type: boolean
          default: true
      - in: query
        name: filterType
        schema:
          type: string
          enum:
          - CASH
          - TOKENS
        description: Must be provided together with filterAmount.
      - in: query
        name: filterAmount
        schema:
          type: number
          minimum: 0
        description: Must be provided together with filterType.
      - in: query
        name: market
        style: form
        explode: false
        schema:
          type: array
          items:
            $ref: '#/components/schemas/Hash64'
        description: Comma-separated list of condition IDs. Mutually exclusive with eventId.
      - in: query
        name: eventId
        style: form
        explode: false
        schema:
          type: array
          items:
            type: integer
            minimum: 1
        description: Comma-separated list of event IDs. Mutually exclusive with market.
      - in: query
        name: user
        schema:
          $ref: '#/components/schemas/Address'
      - in: query
        name: side
        schema:
          type: string
          enum:
          - BUY
          - SELL
      - in: query
        name: start
        schema:
          type: integer
          minimum: 0
        description: >-
          Lower-bound timestamp (epoch seconds) for the trade window. Omit or
          pass `0` for the default window (most recent ~3 years); pass a positive
          epoch (e.g. `1`) to retrieve full history on user-scoped requests.
          Market/event-scoped requests keep the ~3-year floor — `start` can only
          narrow their window, not extend it.
      - in: query
        name: end
        schema:
          type: integer
          minimum: 0
        description: >-
          Upper-bound timestamp (epoch seconds) for the trade window. Omit for
          the default (current time); rows newer than `end` are excluded.
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Trade'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /activity:
    get:
      tags:
      - Core
      summary: Get user activity
      parameters:
      - in: query
        name: limit
        schema:
          type: integer
          default: 100
          minimum: 0
          maximum: 500
        description: Page size. Values above the maximum are clamped to 500.
      - in: query
        name: offset
        schema:
          type: integer
          default: 0
          minimum: 0
          maximum: 5000
        description: >-
          Starting index for pagination. Requests past the cap are rejected
          with a 400 (never silently clamped). To read history deeper than
          offset 5000, page inside `start`/`end` windows — each window has its
          own offset budget.
      - in: query
        name: user
        required: true
        schema:
          $ref: '#/components/schemas/Address'
      - in: query
        name: market
        style: form
        explode: false
        schema:
          type: array
          items:
            $ref: '#/components/schemas/Hash64'
        description: Comma-separated list of condition IDs. Mutually exclusive with eventId.
      - in: query
        name: eventId
        style: form
        explode: false
        schema:
          type: array
          items:
            type: integer
            minimum: 1
        description: Comma-separated list of event IDs. Mutually exclusive with market.
      - in: query
        name: type
        style: form
        explode: false
        schema:
          type: array
          items:
            type: string
            enum:
            - TRADE
            - SPLIT
            - MERGE
            - REDEEM
            - REWARD
            - CONVERSION
            - DEPOSIT
            - WITHDRAWAL
            - YIELD
            - MAKER_REBATE
            - TAKER_REBATE
            - REFERRAL_REWARD
        description: >-
          Comma-separated list of activity types to include. DEPOSIT and
          WITHDRAWAL records also require `excludeDepositsWithdrawals=false`.
      - in: query
        name: excludeDepositsWithdrawals
        schema:
          type: boolean
          default: true
        description: >-
          Excludes deposit and withdrawal records. The default `true` applies
          even when `type` requests those records, so to get deposits and
          withdrawals you must pass `false`.
      - in: query
        name: start
        schema:
          type: integer
          minimum: 0
        description: >-
          Lower-bound timestamp (epoch seconds) for the activity window. Omit or
          pass `0` for the default window (most recent ~3 years); pass a positive
          epoch (e.g. `1`) to retrieve full history. With `sortDirection=ASC`,
          omitting `start` already reads from the beginning of the account's
          history (no default window).
      - in: query
        name: end
        schema:
          type: integer
          minimum: 0
        description: >-
          Upper-bound timestamp (epoch seconds) for the activity window. Omit
          for the default (current time); rows newer than `end` are excluded.
      - in: query
        name: sortBy
        schema:
          type: string
          enum:
          - TIMESTAMP
          - TOKENS
          - CASH
          default: TIMESTAMP
      - in: query
        name: sortDirection
        schema:
          type: string
          enum:
          - ASC
          - DESC
          default: DESC
        description: >-
          `DESC` (default) returns the newest rows first; `ASC` the oldest
          first. Both orders are stable — the same query returns the same rows
          at any `limit`/`offset`, so pages compose without gaps or repeats.
      - in: query
        name: side
        schema:
          type: string
          enum:
          - BUY
          - SELL
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Activity'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v1/activity/combos:
    get:
      tags:
      - Core
      summary: Get user combo activity
      description: >-
        Combo lifecycle and redeem events (split / merge / convert / compress /
        wrap / unwrap / redeem) for a user, with per-leg breakdown. The combo
        counterpart to /activity trade rows. Also available at
        /v1/data/user/{address}/activity/combos (address from the path).
      parameters:
      - in: query
        name: user
        required: true
        schema:
          $ref: '#/components/schemas/Address'
      - in: query
        name: market_id
        style: form
        explode: false
        schema:
          type: array
          items:
            $ref: '#/components/schemas/ComboConditionId'
        description: >-
          Comma-separated combo_condition_id values to filter to specific combos.
          These equal the market_id of isCombo rows on /activity. Omit for all of
          the user's combo activity.
      - in: query
        name: limit
        schema:
          type: integer
          default: 50
          minimum: 0
          maximum: 500
      - in: query
        name: offset
        schema:
          type: integer
          default: 0
          minimum: 0
          maximum: 10000
      - in: query
        name: cursor
        schema:
          type: string
        description: >-
          Opaque continuation token from a previous response's
          pagination.next_cursor. When present it supersedes offset (which is
          ignored). Invalid, tampered, or cross-endpoint tokens return 400.
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CombosActivityResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v1/positions/combos:
    get:
      tags:
      - Core
      summary: Get user combo positions
      description: >-
        Combinatorial (multi-market) positions held by a user, with per-leg
        breakdown. Also available at /v1/data/user/{address}/positions/combos
        (address from the path). Open positions with shares_balance below
        0.001 are omitted (dust floor — e.g. sub-0.001 remainders left by
        "sell all" cashouts); resolved positions are served regardless of
        balance.
      parameters:
      - in: query
        name: user
        required: true
        schema:
          $ref: '#/components/schemas/Address'
      - in: query
        name: status
        style: form
        explode: false
        schema:
          type: array
          items:
            type: string
            enum:
            - OPEN
            - PARTIAL
            - RESOLVED_PARTIAL
            - RESOLVED_WIN
            - RESOLVED_LOSS
        description: >-
          One or more statuses, comma-separated (e.g.
          status=RESOLVED_WIN,RESOLVED_PARTIAL,RESOLVED_LOSS). Values are
          case-insensitive; any invalid member is a 400. Omit for the default
          listing (open positions plus resolved positions with a recorded
          resolution).
      - in: query
        name: sort
        schema:
          type: string
          enum:
          - current_value_desc
          - first_entry_desc
          - entry_cost_desc
          - resolved_at_desc
          - updated_asc
          default: current_value_desc
      - in: query
        name: market_id
        style: form
        explode: false
        schema:
          type: array
          items:
            $ref: '#/components/schemas/ComboConditionId'
        description: >-
          Comma-separated combo_condition_id values to filter to specific combos.
          These equal the market_id of isCombo rows on /activity. Omit for all of
          the user's combos.
      - in: query
        name: limit
        schema:
          type: integer
          default: 20
          minimum: 0
          maximum: 1000
      - in: query
        name: offset
        schema:
          type: integer
          default: 0
          minimum: 0
          maximum: 100000
      - in: query
        name: updatedAfter
        schema:
          type: integer
        description: >-
          Incremental-sync watermark (epoch seconds, inclusive): only rows whose
          updated_at is at or after this time. Positions mutate on resolution and
          redemption, so this catches changes a creation-time filter cannot. In
          sync mode (updatedAfter/updatedBefore/sort=updated_asc) every live row
          is returned regardless of balance, and the effective upper bound is
          clamped ~90s behind now (commit-visibility safety lag) — very recent
          rows appear on the next poll. Rows at the boundary may re-deliver:
          upsert by (combo_condition_id, combo_position_id).
      - in: query
        name: updatedBefore
        schema:
          type: integer
        description: >-
          Optional upper bound (epoch seconds, inclusive) for updated_at;
          clamped to the safety lag. Must be >= updatedAfter.
      - in: query
        name: cursor
        schema:
          type: string
        description: >-
          Opaque continuation token from a previous response's
          pagination.next_cursor. When present it supersedes offset (which is
          ignored). Invalid, tampered, or cross-endpoint tokens return 400.
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CombosResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /holders:
    get:
      tags:
      - Core
      summary: Get top holders for markets
      parameters:
      - in: query
        name: limit
        schema:
          type: integer
          default: 20
          minimum: 0
          maximum: 20
        description: Maximum number of holders to return per token. Capped at 20.
      - in: query
        name: market
        required: true
        style: form
        explode: false
        schema:
          type: array
          items:
            $ref: '#/components/schemas/Hash64'
        description: Comma-separated list of condition IDs.
      - in: query
        name: minBalance
        schema:
          type: integer
          default: 1
          minimum: 0
          maximum: 999999
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/MetaHolder'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /traded:
    get:
      tags:
      - Misc
      summary: Get total markets a user has traded
      parameters:
      - in: query
        name: user
        required: true
        schema:
          $ref: '#/components/schemas/Address'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Traded'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /revisions:
    get:
      tags:
      - Misc
      x-excluded: true
      summary: Get moderated revisions for a question
      parameters:
      - in: query
        name: questionID
        required: true
        schema:
          $ref: '#/components/schemas/Hash64'
      - in: query
        name: limit
        schema:
          type: integer
          default: 100
          minimum: 0
          maximum: 500
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/RevisionPayload'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /value:
    get:
      tags:
      - Core
      summary: Get total value of a user's positions
      parameters:
      - in: query
        name: user
        required: true
        schema:
          $ref: '#/components/schemas/Address'
      - in: query
        name: market
        style: form
        explode: false
        schema:
          type: array
          items:
            $ref: '#/components/schemas/Hash64'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Value'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /oi:
    get:
      tags:
      - Misc
      summary: Get open interest
      parameters:
      - in: query
        name: market
        style: form
        explode: false
        schema:
          type: array
          items:
            $ref: '#/components/schemas/Hash64'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/OpenInterest'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /live-volume:
    get:
      tags:
      - Misc
      summary: Get live volume for an event
      parameters:
      - in: query
        name: id
        required: true
        schema:
          type: integer
          minimum: 1
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/LiveVolume'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /closed-positions:
    get:
      tags:
      - Core
      summary: Get closed positions for a user
      parameters:
      - in: query
        name: user
        required: true
        schema:
          $ref: '#/components/schemas/Address'
        description: The address of the user in question
      - in: query
        name: market
        style: form
        explode: false
        schema:
          type: array
          items:
            $ref: '#/components/schemas/Hash64'
        description: The conditionId of the market in question. Supports multiple csv separated values. Cannot be used with
          the eventId param.
      - in: query
        name: title
        schema:
          type: string
          maxLength: 100
        description: Filter by market title
      - in: query
        name: eventId
        style: form
        explode: false
        schema:
          type: array
          items:
            type: integer
            minimum: 1
        description: The event id of the event in question. Supports multiple csv separated values. Returns positions for
          all markets for those event ids. Cannot be used with the market param.
      - in: query
        name: limit
        schema:
          type: integer
          default: 10
          minimum: 0
          maximum: 50
        description: The max number of positions to return
      - in: query
        name: offset
        schema:
          type: integer
          default: 0
          minimum: 0
          maximum: 100000
        description: The starting index for pagination
      - in: query
        name: sortBy
        schema:
          type: string
          enum:
          - REALIZEDPNL
          - TITLE
          - PRICE
          - AVGPRICE
          - TIMESTAMP
          default: REALIZEDPNL
        description: The sort criteria
      - in: query
        name: sortDirection
        schema:
          type: string
          enum:
          - ASC
          - DESC
          default: DESC
        description: The sort direction
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ClosedPosition'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /other:
    get:
      tags:
      - Misc
      x-excluded: true
      summary: Get "Other" size for an augmented neg risk event and user
      parameters:
      - in: query
        name: id
        required: true
        schema:
          type: integer
          minimum: 1
      - in: query
        name: user
        required: true
        schema:
          $ref: '#/components/schemas/Address'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/OtherSize'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v1/market-positions:
    get:
      tags:
      - Core
      summary: Get positions for a market
      parameters:
      - in: query
        name: market
        required: true
        schema:
          $ref: '#/components/schemas/Hash64'
        description: The condition ID of the market to query positions for
      - in: query
        name: user
        schema:
          $ref: '#/components/schemas/Address'
        description: Filter to a single user by proxy wallet address
      - in: query
        name: status
        schema:
          type: string
          enum:
          - OPEN
          - CLOSED
          - ALL
          default: ALL
        description: 'Filter positions by status.

          - `OPEN` — Only positions with size > 0.01

          - `CLOSED` — Only positions with size <= 0.01

          - `ALL` — All positions regardless of size

          '
      - in: query
        name: sortBy
        schema:
          type: string
          enum:
          - TOKENS
          - CASH_PNL
          - REALIZED_PNL
          - TOTAL_PNL
          default: TOTAL_PNL
        description: 'Sort positions by:

          - `TOKENS` — Position size (number of tokens)

          - `CASH_PNL` — Unrealized cash PnL

          - `REALIZED_PNL` — Realized PnL

          - `TOTAL_PNL` — Total PnL (cash_pnl + realized_pnl)

          '
      - in: query
        name: sortDirection
        schema:
          type: string
          enum:
          - ASC
          - DESC
          default: DESC
      - in: query
        name: limit
        schema:
          type: integer
          default: 50
          minimum: 0
          maximum: 500
        description: Max number of positions to return per outcome token
      - in: query
        name: offset
        schema:
          type: integer
          default: 0
          minimum: 0
          maximum: 10000
        description: Pagination offset per outcome token
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/MetaMarketPositionV1'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v1/builders/leaderboard:
    get:
      tags:
      - Builders
      summary: Get aggregated builder leaderboard
      parameters:
      - in: query
        name: timePeriod
        schema:
          type: string
          enum:
          - DAY
          - WEEK
          - MONTH
          - ALL
          default: DAY
        description: 'The time period to aggregate results over.

          '
      - in: query
        name: limit
        schema:
          type: integer
          default: 25
          minimum: 0
          maximum: 50
        description: Maximum number of builders to return
      - in: query
        name: offset
        schema:
          type: integer
          default: 0
          minimum: 0
          maximum: 1000
        description: Starting index for pagination
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/LeaderboardEntry'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v1/builders/volume:
    get:
      tags:
      - Builders
      summary: Get daily builder volume time-series
      parameters:
      - in: query
        name: timePeriod
        schema:
          type: string
          enum:
          - DAY
          - WEEK
          - MONTH
          - ALL
          default: DAY
        description: 'The time period to fetch daily records for.

          '
      responses:
        '200':
          description: Success - Returns array of daily volume records
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/BuilderVolumeEntry'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v1/leaderboard:
    get:
      tags:
      - Core
      summary: Get trader leaderboard rankings
      parameters:
      - in: query
        name: category
        schema:
          type: string
          enum:
          - OVERALL
          - POLITICS
          - SPORTS
          - ESPORTS
          - CRYPTO
          - CULTURE
          - MENTIONS
          - WEATHER
          - ECONOMICS
          - TECH
          - FINANCE
          default: OVERALL
        description: Market category for the leaderboard
      - in: query
        name: timePeriod
        schema:
          type: string
          enum:
          - DAY
          - WEEK
          - MONTH
          - ALL
          default: DAY
        description: Time period for leaderboard results
      - in: query
        name: orderBy
        schema:
          type: string
          enum:
          - PNL
          - VOL
          default: PNL
        description: Leaderboard ordering criteria
      - in: query
        name: limit
        schema:
          type: integer
          default: 25
          minimum: 1
          maximum: 50
        description: Max number of leaderboard traders to return
      - in: query
        name: offset
        schema:
          type: integer
          default: 0
          minimum: 0
          maximum: 1000
        description: Starting index for pagination
      - in: query
        name: user
        schema:
          $ref: '#/components/schemas/Address'
        description: Limit leaderboard to a single user by address
      - in: query
        name: userName
        schema:
          type: string
        description: Limit leaderboard to a single username
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/TraderLeaderboardEntry'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
