openapi: 3.1.0
info:
  title: Unofficial Steam Community Market API
  version: '1.0.0'
  summary: Unofficial technical reference for Steam Market web endpoints.
  description: |
    Technical reference for the Steam Community Market HTTP operations: discovery and search,
    listings and order books, pricing, account state, and buy-order and sell-listing mutations.

    This is not an official Valve API contract. Routes, fields, and authentication behavior can
    change without notice.

    This is an unofficial reference, not affiliated with or endorsed by Valve Corporation.
  license:
    name: Documentation only; Steam terms apply to the underlying services
externalDocs:
  description: Integration guide
  url: https://steampriceapi.com/guide/overview
servers:
  - url: https://steamcommunity.com
    description: Steam Community
tags:
  - name: Discovery
    description: |
      Search, autocomplete, and the filter metadata that drives them.

      Search is expressed two ways. `GET /market/search` takes the selection as a query string and
      returns a page; `POST /market/search` takes the same selection as JSON and returns data.
      The query-string form is shareable but cannot express price bounds, numeric asset-property
      ranges, or paging, so non-trivial searches belong on the POST form.

      Filters come in three kinds:

      - **Catalog tags** — `category_{Category}` in the query string, `filters` in the body.
        Selected by tag internal name, such as `CSGO_Type_SniperRifle` or `WearCategory0`.
      - **Applied accessories** — `accessory_{Category}` in the query string, `accessoryFilters`
        in the body. Selected by display name, such as `Charm | Stitch-Loaded`, with `$any$` and
        `$none$` sentinels.
      - **Numeric asset properties** — `propertyFilters` in the body only, as inclusive ranges.

      Repeating a query parameter, or listing several values in one body array, ORs those values.
      Different categories are ANDed. Categories, tags, and accessory names are per-application
      and change with game updates; `GET /market/appfacets/{appid}` and
      `GET /market/appaccessories/{appid}` return the current vocabulary with localized labels
      and match counts.
    x-pagePath: discovery
  - name: Listings
    description: Listing pages, listing data, order depth, and recent activity.
    x-pagePath: listings
  - name: Pricing
    description: Current and historical Market prices.
    x-pagePath: pricing
  - name: Account
    description: Market eligibility, billing state, and active listings.
    x-pagePath: account
  - name: Mutations
    description: |
      Buying and selling: purchase a listing outright, place and cancel buy orders, list an owned
      asset, and remove a listing.

      Every operation here is a form POST authenticated by session cookies and guarded by a
      `sessionid` CSRF field. Steam also checks browser-shaped headers; see
      [Mutation headers](/guide/mutations) for the set a non-browser client has to send.
    x-pagePath: mutations
  - name: Confirmations
    description: |
      Steam Guard mobile confirmations. A sell listing is not live until confirmed, so this is part
      of the sell path rather than a separate concern.

      These routes live under `/mobileconf`, not `/market`, and authenticate with an HMAC of the
      account's `identity_secret` rather than the `sessionid` CSRF field.
    x-pagePath: confirmations
x-tagGroups:
  - name: Market data
    tags: [Discovery, Listings, Pricing]
  - name: Account operations
    tags: [Account, Mutations, Confirmations]

paths:
  /market/:
    get:
      operationId: getMarketHome
      tags: [Discovery]
      summary: Load the Market home page
      description: Returns the Steam Community Market HTML application. May redirect based on authentication or eligibility state.
      responses:
        '200':
          description: Market page.
          content:
            text/html:
              schema: { type: string }
        '302':
          $ref: '#/components/responses/Redirect'

  /market/search:
    get:
      operationId: getMarketSearchPage
      tags: [Discovery]
      summary: Load the Market search page
      description: |
        Returns HTML, or a serialized React Server Component loader payload, for a Market search URL.

        The query string is the canonical, shareable representation of a search. It carries the same
        selection that `POST /market/search` takes as a JSON body, so any search built here can be
        replayed against the structured endpoint. See the tag description for the full filter model.
      parameters:
        - $ref: '#/components/parameters/AppIdQuery'
        - $ref: '#/components/parameters/SearchQ'
        - $ref: '#/components/parameters/SearchDescriptions'
        - $ref: '#/components/parameters/SearchSort'
        - $ref: '#/components/parameters/SearchDir'
        - $ref: '#/components/parameters/CategoryType'
        - $ref: '#/components/parameters/CategoryWeapon'
        - $ref: '#/components/parameters/CategoryQuality'
        - $ref: '#/components/parameters/CategoryRarity'
        - $ref: '#/components/parameters/CategoryExterior'
        - $ref: '#/components/parameters/CategoryItemSet'
        - $ref: '#/components/parameters/CategoryTournament'
        - $ref: '#/components/parameters/CategoryTournamentTeam'
        - $ref: '#/components/parameters/CategoryProPlayer'
        - $ref: '#/components/parameters/AccessorySticker'
        - $ref: '#/components/parameters/AccessoryKeychain'
      responses:
        '200':
          description: Search page or SSR loader payload.
          content:
            text/html:
              schema: { type: string }
            application/json:
              schema:
                type: string
                description: Serialized loader payload. This is not a conventional JSON object despite the media type.
    post:
      operationId: searchMarketStructured
      tags: [Discovery]
      summary: Search structured Market data
      description: |
        Returns grouped catalog results, direct listing rows, or literal JSON `null`.

        The body is a JSON array containing exactly one request object. Every filter in the query
        string of `GET /market/search` has a body equivalent, and the body form is the one to use
        for anything beyond a trivial search: it is the only form that accepts price bounds,
        numeric asset-property ranges, and paging offsets.

        `filters` selects catalog tags by internal name; `accessoryFilters` selects applied
        stickers and charms by display name. Both map a key to an array, and values inside one
        array are ORed while separate keys are ANDed. `propertyFilters` constrains numeric asset
        properties by inclusive range.

        Results are grouped by default. `grouping: 1` in the response means rows are catalog
        entries keyed by `strHash`; a response carrying `listings` instead of `results` contains
        individual sell listings with owner-specific assets and fees.
      parameters:
        - $ref: '#/components/parameters/AppIdQuery'
        - $ref: '#/components/parameters/SearchQ'
        - $ref: '#/components/parameters/SearchDescriptions'
        - $ref: '#/components/parameters/SearchSort'
        - $ref: '#/components/parameters/SearchDir'
        - $ref: '#/components/parameters/CategoryType'
        - $ref: '#/components/parameters/CategoryWeapon'
        - $ref: '#/components/parameters/CategoryQuality'
        - $ref: '#/components/parameters/CategoryRarity'
        - $ref: '#/components/parameters/CategoryExterior'
        - $ref: '#/components/parameters/CategoryItemSet'
        - $ref: '#/components/parameters/CategoryTournament'
        - $ref: '#/components/parameters/CategoryTournamentTeam'
        - $ref: '#/components/parameters/CategoryProPlayer'
        - $ref: '#/components/parameters/AccessorySticker'
        - $ref: '#/components/parameters/AccessoryKeychain'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: array
              minItems: 1
              maxItems: 1
              items:
                $ref: '#/components/schemas/StructuredSearchRequest'
            examples:
              minimal:
                summary: First page of everything for one application
                value:
                  - appid: 730
                    filters: {}
                    accessoryFilters: {}
                    price: { eCurrency: 1 }
                    start: 0
              text_search:
                summary: Text query including item descriptions
                value:
                  - appid: 730
                    filters: {}
                    accessoryFilters: {}
                    price: { eCurrency: 1 }
                    strQuery: doppler
                    bSearchDescriptions: true
                    start: 0
              tag_filters:
                summary: Two ORed types, restricted to one rarity, sorted by price ascending
                value:
                  - appid: 730
                    filters:
                      Type: [CSGO_Type_SniperRifle, CSGO_Type_Rifle]
                      Rarity: [Rarity_Legendary_Weapon]
                      Exterior: [WearCategory0, WearCategory1]
                    accessoryFilters: {}
                    price: { eCurrency: 1, unMin: 2063, unMax: 89135 }
                    sort: 3
                    direction: 1
                    start: 0
              accessory_filters:
                summary: Applied charm and sticker filters, selected by display name
                value:
                  - appid: 730
                    filters:
                      Type: [CSGO_Type_SniperRifle]
                    accessoryFilters:
                      accessory_CSGO_Tool_Keychain: ["Charm | Stitch-Loaded"]
                      accessory_CSGO_Tool_Sticker:
                        - "Sticker | BLAST.tv (Gold) | Paris 2023"
                        - "Sticker | PGL (Gold) | Stockholm 2021"
                    price: { eCurrency: 1 }
                    start: 0
              any_none:
                summary: Any charm applied, no sticker applied
                value:
                  - appid: 730
                    filters: {}
                    accessoryFilters:
                      accessory_CSGO_Tool_Keychain: ["$any$"]
                      accessory_CSGO_Tool_Sticker: ["$none$"]
                    price: { eCurrency: 1 }
                    start: 0
              property_filters:
                summary: Numeric asset-property range
                value:
                  - appid: 730
                    filters: {}
                    accessoryFilters: {}
                    propertyFilters:
                      '1': { property_id: 1, int_min: '385', int_max: '678' }
                    price: { eCurrency: 1 }
                    start: 0
      responses:
        '200':
          description: Search data or a literal `null` payload.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/StructuredSearchResponse'
                  - $ref: '#/components/schemas/StructuredListingsResponse'
                  - type: 'null'
              examples:
                grouped:
                  summary: Grouped catalog results
                  value:
                    start: 0
                    total_count: 1
                    grouping: 1
                    facets: []
                    results:
                      - strHash: AK-47 | Redline (Field-Tested)
                        cSellOrders: 1200
                        cBuyOrders: 430
                        unSteamFee: 42
                        unPublisherFee: 84
                        eCurrency: 1
                        strMinSellSubtotal: $12.34
                        asset_description:
                          appid: 730
                          classid: '310777173'
                          market_hash_name: AK-47 | Redline (Field-Tested)
                          marketable: true
                direct_listings:
                  summary: Direct sell listings
                  value:
                    start: 0
                    total_count: 1
                    more: false
                    facets: []
                    listings:
                      - listingid: '1234567890123456789'
                        unPrice: 1200
                        unFee: 180
                        eCurrency: 1
                        strSubtotal: $13.80
                        asset:
                          appid: 730
                          contextid: '2'
                          assetid: '12345678901234567890'
                          classid: '310777173'
                          instanceid: '0'
                          amount: 1
                null_payload:
                  summary: Empty or transient payload
                  value: null

  /market/search/render/:
    get:
      operationId: renderMarketSearch
      tags: [Discovery]
      summary: Render legacy search results
      description: |
        Returns a JSON envelope containing server-rendered listing HTML. This is the pre-structured
        search endpoint; it accepts a text query, paging, a single sort, and price bounds, but none
        of the tag, accessory, or property filters. Use `POST /market/search` for filtered searches.

        `count` is capped server-side: the endpoint returns 10 results regardless of a larger value.
        Page with `start` instead. Roughly 20 requests per minute per client.
      parameters:
        - name: query
          in: query
          required: true
          schema: { type: string }
        - $ref: '#/components/parameters/Start'
        - $ref: '#/components/parameters/Count'
        - $ref: '#/components/parameters/NoRender'
        - name: sort_column
          in: query
          description: Sort column. Unlike the structured endpoint, this form names the column.
          schema: { type: string, enum: [popular, price, name, quantity], default: popular }
        - name: sort_dir
          in: query
          schema: { type: string, enum: [asc, desc], default: desc }
        - name: search_descriptions
          in: query
          description: Set to `1` to match the query against item descriptions as well as names.
          schema: { type: integer, enum: [0, 1], default: 0 }
        - name: price_min
          in: query
          description: Inclusive minimum price, in the minor units of the selected currency.
          schema: { type: integer, minimum: 0 }
        - name: price_max
          in: query
          description: Inclusive maximum price, in the minor units of the selected currency.
          schema: { type: integer, minimum: 0 }
        - $ref: '#/components/parameters/AppIdQuery'
      responses:
        '200':
          description: Rendered result page.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LegacySearchRenderResponse'
              example:
                success: true
                start: 0
                pagesize: 10
                total_count: 1
                tip: ''
                results_html: '<a class="market_listing_row">...</a>'

  /market/searchsuggestionsresults:
    get:
      operationId: getMarketSearchSuggestions
      tags: [Discovery]
      summary: Get search suggestions
      description: |
        Returns item-name autocomplete results and matching applications. `apps` can be empty.

        The Market UI calls this on each keystroke, so results are ranked by `search_score` rather
        than filtered; `listing_count` is the live sell-order count for the suggested item.
      parameters:
        - name: q
          in: query
          required: true
          schema: { type: string }
          description: Search prefix or text.
          example: doppler
        - $ref: '#/components/parameters/AppIdQuery'
        - name: debug
          in: query
          description: Set to `1` to include scoring detail in the response.
          schema: { type: integer, enum: [0, 1] }
      responses:
        '200':
          description: Suggestions.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchSuggestionsResponse'
              example:
                results:
                  - market_name: AK-47 | Redline (Field-Tested)
                    market_hash_name: AK-47 | Redline (Field-Tested)
                    app_id: 730
                    app_name: Counter-Strike 2
                    icon_url: image_hash
                    market_type: Rifle
                    listing_count: 1200
                    search_score: 100
                apps:
                  - appid: 730
                    name: Counter-Strike 2
                    icon: image_hash

  /market/appfacets/{appid}:
    get:
      operationId: getMarketAppFacets
      tags: [Discovery]
      summary: Get application filter facets
      description: |
        Returns the complete catalog-tag vocabulary for one application: every filter category, the
        tags inside it, their localized labels, and how many Market entries each tag matches.

        This is the authoritative source for `category_{Category}` query values and `filters` body
        keys. Category keys map to filter names by dropping the `category_` prefix, and tag keys
        are the internal names sent as filter values. Read it rather than hard-coding tags: CS2
        adds collections, tournaments, teams, and players with each release.
      parameters:
        - $ref: '#/components/parameters/AppIdPath'
      responses:
        '200':
          description: Facet map keyed by category name.
          content:
            application/json:
              schema:
                type: object
                required: [success, facets]
                properties:
                  success: { type: boolean }
                  facets:
                    type: object
                    additionalProperties:
                      $ref: '#/components/schemas/AppFacet'
              example:
                success: true
                facets:
                  item_class:
                    appid: 753
                    name: item_class
                    localized_name: Item type
                    tags:
                      item_class_2:
                        localized_name: Trading Card
                        matches: '1000'

  /market/appaccessories/{appid}:
    get:
      operationId: getMarketAppAccessories
      tags: [Discovery]
      summary: Get application accessory facets
      description: |
        Returns the applied-accessory vocabulary for one application: the sticker and charm names
        accepted by `accessory_{Category}` query parameters and `accessoryFilters` body keys.

        Accessories are matched by display name, so the names returned here are sent verbatim.
        `facets` is empty for applications with no applied-accessory system.
      parameters:
        - $ref: '#/components/parameters/AppIdPath'
      responses:
        '200':
          description: Accessory facets.
          content:
            application/json:
              schema:
                type: object
                required: [success, facets]
                properties:
                  success: { type: boolean }
                  facets:
                    type: array
                    items:
                      type: object
                      description: Accessory facet object. The array can be empty.
                      additionalProperties: true
              example:
                success: true
                facets: []

  /market/listings/{appid}/{market_hash_name}:
    get:
      operationId: getMarketListingPage
      tags: [Listings]
      summary: Load a listing page
      description: Returns the listing page as HTML or a serialized React Server Component loader payload. May redirect.
      parameters:
        - $ref: '#/components/parameters/AppIdPath'
        - $ref: '#/components/parameters/MarketHashNamePath'
        - $ref: '#/components/parameters/CategoryType'
        - $ref: '#/components/parameters/CategoryWeapon'
        - $ref: '#/components/parameters/CategoryQuality'
        - $ref: '#/components/parameters/CategoryTournament'
        - $ref: '#/components/parameters/CategoryTournamentTeam'
        - $ref: '#/components/parameters/AppIdQuery'
      responses:
        '200':
          description: Listing page or SSR loader payload.
          content:
            text/html:
              schema: { type: string }
            application/json:
              schema:
                type: string
                description: Serialized loader payload. This is not a conventional JSON object despite the media type.
        '302':
          $ref: '#/components/responses/Redirect'
    post:
      operationId: getMarketListingsStructured
      tags: [Listings]
      summary: Get structured sell listings
      description: |
        Returns paginated sell listings and matched facets, or literal JSON `null`. The body is a JSON array containing one request object.
      parameters:
        - $ref: '#/components/parameters/AppIdPath'
        - $ref: '#/components/parameters/MarketHashNamePath'
        - name: price_min
          in: query
          schema: { type: integer, minimum: 0 }
          description: Lower price bound in currency minor units.
        - name: price_max
          in: query
          schema: { type: integer, minimum: 0 }
          description: Upper price bound in currency minor units.
        - name: price_currency
          in: query
          schema: { type: integer }
          description: Steam currency enum for price bounds.
        - $ref: '#/components/parameters/AppIdQuery'
        - $ref: '#/components/parameters/CategoryType'
        - $ref: '#/components/parameters/CategoryExterior'
        - $ref: '#/components/parameters/CategoryQuality'
        - $ref: '#/components/parameters/CategoryWeapon'
        - $ref: '#/components/parameters/CategoryTournament'
        - $ref: '#/components/parameters/CategoryTournamentTeam'
        - $ref: '#/components/parameters/AccessorySticker'
        - $ref: '#/components/parameters/AccessoryKeychain'
        - name: assetproperty
          in: query
          schema: { type: string }
          description: Encoded asset property filter mirrored by `propertyFilters`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: array
              minItems: 1
              maxItems: 1
              items:
                $ref: '#/components/schemas/StructuredListingsRequest'
            example:
              - appid: 730
                strItemName: G180320E8083004
                filters: {}
                accessoryFilters: {}
                propertyFilters: {}
                price: { eCurrency: 1 }
                start: 0
      responses:
        '200':
          description: Listing data or a literal `null` payload.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/StructuredListingsResponse'
                  - type: 'null'
              examples:
                listings:
                  summary: Listing page
                  value:
                    more: false
                    start: 0
                    total_count: 1
                    facets: []
                    listings:
                      - listingid: '1234567890123456789'
                        unPrice: 1200
                        unFee: 180
                        unSteamFee: 60
                        unPublisherFee: 120
                        eCurrency: 1
                        strSubtotal: $13.80
                        bMine: false
                        asset:
                          appid: 730
                          contextid: '2'
                          assetid: '12345678901234567890'
                          classid: '310777173'
                          instanceid: '0'
                          amount: 1
                null_payload:
                  summary: Empty or transient payload
                  value: null

  /market/listings/{appid}/{market_hash_name}/render/:
    get:
      operationId: renderMarketListings
      tags: [Listings]
      summary: Render legacy listing rows
      description: Returns either an HTML fragment or a JSON listing envelope. Select the decoder from `Content-Type`.
      parameters:
        - $ref: '#/components/parameters/AppIdPath'
        - $ref: '#/components/parameters/MarketHashNamePath'
        - name: query
          in: query
          schema: { type: string }
        - $ref: '#/components/parameters/Start'
        - $ref: '#/components/parameters/Count'
        - $ref: '#/components/parameters/Country'
        - $ref: '#/components/parameters/Language'
        - $ref: '#/components/parameters/Currency'
      responses:
        '200':
          description: Listing fragment or JSON listing data.
          content:
            text/html:
              schema: { type: string }
            application/json:
              schema:
                $ref: '#/components/schemas/LegacyListingsRenderResponse'
              example:
                success: true
                start: 0
                pagesize: 10
                total_count: 1
                results_html: '<div class="market_listing_row">...</div>'
                listinginfo:
                  '1234567890123456789':
                    listingid: '1234567890123456789'
                    price: 1200
                    fee: 180
                    steam_fee: 60
                    publisher_fee: 120
                    currencyid: 2001
                    asset:
                      appid: 730
                      contextid: '2'
                      id: '12345678901234567890'
                      amount: '1'
                assets: {}
                currency: []
                hovers: ''
                app_data: {}

  /market/orderbook:
    get:
      operationId: getMarketOrderBook
      tags: [Listings]
      summary: Get compact order-book depth
      description: Returns current best prices, order counts, and flattened price/quantity arrays. An alternate HTML response is possible.
      parameters:
        - name: q
          in: query
          required: true
          schema: { type: string, const: Load }
        - name: qp
          in: query
          required: true
          schema: { type: string }
          description: JSON-encoded tuple `[appid, market_hash_name]`.
          example: '[730,"AK-47 | Redline (Field-Tested)"]'
      responses:
        '200':
          description: Compact order book or alternate HTML response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderBookResponse'
              example:
                data:
                  success: true
                  data:
                    amtMaxBuyOrder: 1200
                    amtMinSellOrder: 1380
                    eCurrency: 1
                    cBuyOrders: 430
                    cSellOrders: 1200
                    rgCompactBuyOrders: [1200, 5, 1199, 8]
                    rgCompactSellOrders: [1380, 2, 1381, 4]
            text/html:
              schema: { type: string }

  /market/itemordershistogram:
    get:
      operationId: getItemOrdersHistogram
      tags: [Listings]
      summary: Get order histogram
      description: |
        Returns best bid and ask strings, rendered order tables, and cumulative graph points for one
        catalog entry. This is the only route that exposes live buy-order depth.

        Keyed by `item_nameid`, not `market_hash_name` or `classid`. That ID is embedded in the
        listing page's inline state and has no lookup endpoint, so it must be scraped once per item
        and cached.

        The tightest limit on the Market: roughly 10 distinct items per hour per client. Re-polling
        the same item is far cheaper than widening the item set, so poll a small watchlist rather
        than sweeping the catalog.
      parameters:
        - $ref: '#/components/parameters/Country'
        - $ref: '#/components/parameters/Language'
        - $ref: '#/components/parameters/Currency'
        - $ref: '#/components/parameters/ItemNameId'
        - $ref: '#/components/parameters/NoRender'
        - $ref: '#/components/parameters/TwoFactor'
      responses:
        '200':
          description: Order histogram.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderHistogramResponse'
              example:
                success: 1
                highest_buy_order: '1200'
                lowest_sell_order: '1380'
                buy_order_graph: [[12.0, 5, '$12.00']]
                sell_order_graph: [[13.8, 2, '$13.80']]
                graph_max_y: 5
                graph_min_x: 12.0
                graph_max_x: 13.8
                price_prefix: $
                price_suffix: ''
                buy_order_table: '<table>...</table>'
                buy_order_summary: '<span>...</span>'
                sell_order_table: '<table>...</table>'
                sell_order_summary: '<span>...</span>'

  /market/itemordersactivity:
    get:
      operationId: getItemOrdersActivity
      tags: [Listings]
      summary: Get recent order activity
      description: |
        Returns recent order activity for one catalog entry plus a cursor timestamp. The activity
        array can be empty and the timestamp can be `0`. Keyed by `item_nameid`, like the histogram.
      parameters:
        - $ref: '#/components/parameters/Country'
        - $ref: '#/components/parameters/Language'
        - $ref: '#/components/parameters/Currency'
        - $ref: '#/components/parameters/ItemNameId'
        - $ref: '#/components/parameters/TwoFactor'
      responses:
        '200':
          description: Activity feed.
          content:
            application/json:
              schema:
                type: object
                required: [success, activity, timestamp]
                properties:
                  success: { type: integer, examples: [1] }
                  activity:
                    type: array
                    items:
                      type: object
                      description: Activity record. The array can be empty.
                      additionalProperties: true
                  timestamp: { type: integer, format: int64 }
              example:
                success: 1
                activity: []
                timestamp: 0

  /market/priceoverview/:
    get:
      operationId: getMarketPriceOverview
      tags: [Pricing]
      summary: Get current price overview
      description: |
        Returns localized lowest price, median price, and recent volume for one catalog entry.

        `volume` counts sales in the last 24 hours and is omitted entirely when it is zero, so
        treat it as optional rather than defaulting to `0`.

        This route is rate limited more tightly than the rest of the Market: roughly 20 requests
        per minute and 1,000 per day per client. Cache aggressively and back off on `429`.
      parameters:
        - $ref: '#/components/parameters/Country'
        - $ref: '#/components/parameters/Currency'
        - $ref: '#/components/parameters/AppIdQueryRequired'
        - $ref: '#/components/parameters/MarketHashNameQuery'
      responses:
        '200':
          description: Price overview.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PriceOverviewResponse'
              example:
                success: true
                lowest_price: $12.34
                volume: '1,234'
                median_price: $12.10

  /market/pricehistory/:
    get:
      operationId: getMarketPriceHistory
      tags: [Pricing]
      summary: Get historical prices
      description: Returns timestamped price and volume tuples.
      security:
        - sessionCookie: []
      parameters:
        - $ref: '#/components/parameters/AppIdQueryRequired'
        - $ref: '#/components/parameters/MarketHashNameQuery'
      responses:
        '200':
          description: Historical price series.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PriceHistoryResponse'
              example:
                success: true
                price_prefix: $
                price_suffix: ''
                prices:
                  - ['Jul 01 2026 01: +0', 12.34, '120']

  /market/eligibilitycheck/:
    get:
      operationId: checkMarketEligibility
      tags: [Account]
      summary: Check Market eligibility
      description: Evaluates account eligibility and redirects to the requested destination.
      security:
        - sessionCookie: []
      parameters:
        - name: goto
          in: query
          required: true
          schema: { type: string }
          example: /market/
      responses:
        '302':
          $ref: '#/components/responses/Redirect'

  /market/userbillinginfo:
    get:
      operationId: getMarketUserBillingInfo
      tags: [Account]
      summary: Get billing and wallet state
      description: Returns sensitive billing address, wallet, tax, agreement, and confirmation state. Do not log the response.
      security:
        - sessionCookie: []
      responses:
        '200':
          description: Account billing state.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserBillingInfoResponse'
              example:
                billing_address:
                  firstname: Jane
                  lastname: Doe
                  address1: 1 Example Street
                  address2: ''
                  city: Example City
                  state: NY
                  countrycode: US
                  postcode: '10001'
                  phone: ''
                require_billing_info: true
                country_code: US
                billing_states: {}
                localized_country: United States
                wallet_info:
                  success: 1
                  wallet_currency: 1
                  wallet_country: US
                  wallet_balance: '2500'
                account_name: example
                ssa:
                  last_update: 0
                  latest_accepted: true
                  eu_ssa: false
                confirmation_type: 2
                tax_rate:
                  success: true
                  tradefee_addtax: 0
                  tradefee_taxrate: 0
                  tax_region: ''

  /market/mylistings:
    get:
      operationId: getMyMarketListings
      tags: [Account]
      summary: Get active listings and buy orders
      description: |
        Returns account listing state, related assets, and server-rendered rows. Send `norender=1`
        for a JSON body instead of an HTML page.
      security:
        - sessionCookie: []
      parameters:
        - $ref: '#/components/parameters/NoRender'
        - $ref: '#/components/parameters/Start'
        - name: count
          in: query
          schema: { type: integer, minimum: 1 }
          example: 10
      responses:
        '200':
          description: Active Market state.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MyListingsResponse'
              example:
                success: true
                pagesize: 10
                total_count: 1
                start: 0
                num_active_listings: 1
                assets: {}
                hovers: ''
                results_html: '<div class="market_listing_row">...</div>'

  /mobileconf/getlist:
    get:
      operationId: getPendingConfirmations
      tags: [Confirmations]
      summary: List pending confirmations
      description: |
        Returns the account's outstanding Steam Guard confirmations, including the one a new sell
        listing is waiting on. Match a confirmation to its listing by the asset ID in its details.

        Signed with `tag=conf`. The signature covers the tag, so a key generated for one tag is not
        valid for another.
      servers:
        - url: https://steamcommunity.com
      security:
        - sessionCookie: []
          confirmationKey: []
      parameters:
        - $ref: '#/components/parameters/ConfDeviceId'
        - $ref: '#/components/parameters/ConfSteamId'
        - $ref: '#/components/parameters/ConfKey'
        - $ref: '#/components/parameters/ConfTime'
        - $ref: '#/components/parameters/ConfDevice'
        - name: tag
          in: query
          required: true
          schema: { type: string, enum: [conf] }
      responses:
        '200':
          description: Pending confirmations.
          content:
            application/json:
              schema:
                type: object
                required: [success]
                properties:
                  success: { type: boolean }
                  conf:
                    type: array
                    items:
                      type: object
                      properties:
                        id: { type: string, description: Confirmation ID. Sent back as `cid`. }
                        nonce: { type: string, description: Per-confirmation nonce. Sent back as `ck`. }
                        creator_id: { type: string, description: Asset ID for a sell listing; trade offer ID for a trade. }
                        type: { type: integer }
                        headline: { type: string }
                      additionalProperties: true
  /mobileconf/details/{confirmationid}:
    get:
      operationId: getConfirmationDetails
      tags: [Confirmations]
      summary: Get confirmation details
      description: |
        Returns an HTML fragment describing one pending confirmation. Clients parse it to tie a
        confirmation to the listing or trade that created it.

        Signed with `tag=details{confirmationid}`, not a fixed string.
      servers:
        - url: https://steamcommunity.com
      security:
        - sessionCookie: []
          confirmationKey: []
      parameters:
        - name: confirmationid
          in: path
          required: true
          schema: { type: string }
        - $ref: '#/components/parameters/ConfDeviceId'
        - $ref: '#/components/parameters/ConfSteamId'
        - $ref: '#/components/parameters/ConfKey'
        - $ref: '#/components/parameters/ConfTime'
        - $ref: '#/components/parameters/ConfDevice'
        - name: tag
          in: query
          required: true
          schema: { type: string }
          example: details12345678901234567890
      responses:
        '200':
          description: Confirmation detail.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success: { type: boolean }
                  html: { type: string, description: HTML fragment. Treat as opaque markup. }
  /mobileconf/ajaxop:
    get:
      operationId: respondToConfirmation
      tags: [Confirmations]
      summary: Accept or reject a confirmation
      description: |
        Accepts or rejects one pending confirmation. Accepting the confirmation attached to a new
        sell listing is what actually publishes it; until then `POST /market/sellitem/` has only
        staged the listing.

        Signed with `tag=allow` or `tag=cancel`, matching `op`.
      servers:
        - url: https://steamcommunity.com
      security:
        - sessionCookie: []
          confirmationKey: []
      parameters:
        - name: op
          in: query
          required: true
          description: '`allow` accepts, `cancel` rejects.'
          schema: { type: string, enum: [allow, cancel] }
        - name: cid
          in: query
          required: true
          description: Confirmation ID from `/mobileconf/getlist`.
          schema: { type: string }
        - name: ck
          in: query
          required: true
          description: Confirmation nonce from `/mobileconf/getlist`.
          schema: { type: string }
        - $ref: '#/components/parameters/ConfDeviceId'
        - $ref: '#/components/parameters/ConfSteamId'
        - $ref: '#/components/parameters/ConfKey'
        - $ref: '#/components/parameters/ConfTime'
        - $ref: '#/components/parameters/ConfDevice'
        - name: tag
          in: query
          required: true
          schema: { type: string, enum: [allow, cancel] }
      responses:
        '200':
          description: Confirmation result.
          content:
            application/json:
              schema:
                type: object
                required: [success]
                properties:
                  success: { type: boolean }
                  message: { type: string }
              example:
                success: true
  /market/myhistory:
    get:
      operationId: getMyMarketHistory
      tags: [Account]
      summary: Get Market transaction history
      description: |
        Returns the authenticated account's completed Market purchases and sales, with the assets
        they refer to. Send `norender=1` for a JSON body instead of an HTML page.

        Assets are keyed three levels deep, by application, context, and asset ID, in the same shape
        the legacy listing endpoints use.
      security:
        - sessionCookie: []
      parameters:
        - $ref: '#/components/parameters/NoRender'
        - $ref: '#/components/parameters/Start'
        - name: count
          in: query
          schema: { type: integer, minimum: 1 }
          example: 100
      responses:
        '200':
          description: Market history page.
          content:
            application/json:
              schema:
                type: object
                required: [success]
                properties:
                  success: { type: boolean }
                  pagesize: { type: integer }
                  total_count: { type: integer }
                  start: { type: integer }
                  assets:
                    type: object
                    description: '`assets[appid][contextid][assetid]` to asset description.'
                    additionalProperties: true
                  hovers: { type: string }
                  results_html: { type: string }
        '302': { $ref: '#/components/responses/Redirect' }
  /market/popular:
    get:
      operationId: getMarketPopular
      tags: [Discovery]
      summary: List popular listings
      description: |
        Returns the listings shown on the Market home page, ordered by popularity. Send `norender=1`
        for a JSON body instead of an HTML page.

        `stop` reports whether the requested window ran past the end of the list.
      parameters:
        - $ref: '#/components/parameters/Country'
        - $ref: '#/components/parameters/Language'
        - $ref: '#/components/parameters/Currency'
        - $ref: '#/components/parameters/NoRender'
        - $ref: '#/components/parameters/Start'
        - name: count
          in: query
          schema: { type: integer, minimum: 1 }
          example: 10
      responses:
        '200':
          description: Popular listings.
          content:
            application/json:
              schema:
                type: object
                required: [success]
                properties:
                  success: { type: boolean }
                  stop: { type: boolean, description: True when the window ran past the end of the list. }
                  results_html: { type: string }
                  listinginfo:
                    type: object
                    additionalProperties:
                      $ref: '#/components/schemas/LegacyListingInfo'
                  assets:
                    type: object
                    additionalProperties: true
  /market/recent:
    get:
      operationId: getMarketRecent
      tags: [Discovery]
      summary: List recent listings
      description: |
        Returns the most recently created Market listings across all applications, as the home page
        activity feed shows them. Send `norender=1` for a JSON body instead of an HTML page.

        `more` reports whether further listings are available.
      parameters:
        - $ref: '#/components/parameters/Country'
        - $ref: '#/components/parameters/Language'
        - $ref: '#/components/parameters/Currency'
        - $ref: '#/components/parameters/NoRender'
      responses:
        '200':
          description: Recent listings.
          content:
            application/json:
              schema:
                type: object
                required: [success]
                properties:
                  success: { type: boolean }
                  more: { type: boolean }
                  results_html: { type: string }
                  listinginfo:
                    type: object
                    additionalProperties:
                      $ref: '#/components/schemas/LegacyListingInfo'
                  assets:
                    type: object
                    additionalProperties: true
  /market/buylisting/{listingid}:
    post:
      operationId: buyMarketListing
      tags: [Mutations]
      summary: Buy a listing
      description: |
        Purchases one specific sell listing outright, at its asking price, from the account's Steam
        Wallet. This is the instant-buy path; `POST /market/createbuyorder/` is the standing-order
        path and does not execute against a listing directly.

        The amounts are sent by the client and must reconcile: `total` has to equal
        `subtotal + fee`, and all three must match the listing as Steam currently prices it. Read
        them from the listing row rather than computing them, since the fee split depends on the
        publisher. A mismatch, a stale price, or a listing bought by someone else in the meantime
        all fail the same way.

        Unusually for the Market, success is reported inside `wallet_info` rather than at the top
        level: check `wallet_info.success == 1`. A failure carries a top-level `message`.
      security:
        - sessionCookie: []
      parameters:
        - name: listingid
          in: path
          required: true
          description: Listing to purchase, as returned by the listing page or search.
          schema: { type: string }
          example: '1234567890123456789'
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [sessionid, currency, subtotal, fee, total, quantity]
              properties:
                sessionid: { type: string, description: CSRF token matching the active Steam session. }
                currency: { type: integer, description: Steam currency ID. Must match the currency the listing was priced in., example: 1 }
                subtotal: { type: integer, description: Seller's take, in minor units. }
                fee: { type: integer, description: Combined Steam and publisher fee, in minor units. }
                total: { type: integer, description: '`subtotal + fee`, in minor units. What the buyer pays.' }
                quantity: { type: string, description: Units to buy. `1` for non-commodity items., example: '1' }
            example:
              sessionid: '<redacted>'
              currency: 1
              subtotal: 1200
              fee: 180
              total: 1380
              quantity: '1'
      responses:
        '200':
          description: |
            Purchase result. Check `wallet_info.success`; the HTTP status is `200` either way.
          content:
            application/json:
              schema:
                type: object
                properties:
                  wallet_info:
                    type: object
                    description: Post-purchase wallet state. `success` of `1` means the purchase completed.
                    properties:
                      success: { type: integer }
                      wallet_currency: { type: integer }
                      wallet_country: { type: string }
                      wallet_balance: { type: string }
                      wallet_delayed_balance: { type: string }
                      wallet_max_balance: { type: string }
                      wallet_trade_max_balance: { type: string }
                    additionalProperties: true
                  message: { type: string, description: Present when the purchase failed. }
              examples:
                purchased:
                  summary: Purchase completed
                  value:
                    wallet_info:
                      success: 1
                      wallet_currency: 1
                      wallet_country: US
                      wallet_balance: '4320'
                failed:
                  summary: Price or availability mismatch
                  value:
                    message: There was a problem with your purchase.
  /market/getbuyorderstatus:
    get:
      operationId: getMarketBuyOrderStatus
      tags: [Mutations]
      summary: Get buy-order status
      description: |
        Returns fill progress for one buy order: whether it is still active, how much of the
        requested quantity has been purchased, and what remains outstanding.

        This is the only way to observe a buy order filling. `GET /market/mylistings` lists orders
        but does not break down partial fills.
      security:
        - sessionCookie: []
      parameters:
        - name: sessionid
          in: query
          required: true
          schema: { type: string }
          description: CSRF token matching the active Steam session.
        - name: buy_orderid
          in: query
          required: true
          schema: { type: string }
          description: Buy-order ID.
          example: '1234567890'
      responses:
        '200':
          description: Buy-order status.
          content:
            application/json:
              schema:
                type: object
                required: [success]
                properties:
                  success: { type: integer, examples: [1] }
                  active: { type: integer, description: '`1` while the order is still open.' }
                  purchased: { type: integer, description: Units bought so far. }
                  quantity: { type: integer, description: Units originally requested. }
                  quantity_remaining: { type: integer, description: Units still outstanding. }
                  purchases:
                    type: array
                    description: Individual fills. Empty until the order starts filling.
                    items:
                      type: object
                      additionalProperties: true
              example:
                success: 1
                active: 1
                purchased: 2
                quantity: 5
                quantity_remaining: 3
                purchases: []
  /market/createbuyorder/:
    post:
      operationId: createMarketBuyOrder
      tags: [Mutations]
      summary: Create a buy order
      description: >-
        Creates an account buy order. Application failures still use HTTP `200`;
        `success: 25` indicates a rejected order and includes `message`.
      security:
        - sessionCookie: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/CreateBuyOrderRequest'
      responses:
        '200':
          description: Application-level result. `success` is an endpoint-specific numeric code.
          content:
            application/json:
              schema:
                type: object
                required: [success]
                properties:
                  success: { type: integer }
                  message: { type: string }
              examples:
                rejected:
                  value:
                    success: 25
                    message: This buy order cannot be placed.
                accepted:
                  value:
                    success: 1

  /market/cancelbuyorder/:
    post:
      operationId: cancelMarketBuyOrder
      tags: [Mutations]
      summary: Cancel a buy order
      description: Cancels an account buy order. A successful result is `{"success":1}`.
      security:
        - sessionCookie: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [sessionid, buy_orderid]
              properties:
                sessionid: { type: string, description: CSRF token matching the active Steam session. }
                buy_orderid: { type: string, description: Buy-order ID., example: '1234567890' }
            example:
              sessionid: '<redacted>'
              buy_orderid: '1234567890'
      responses:
        '200':
          description: Cancellation result.
          content:
            application/json:
              schema:
                type: object
                required: [success]
                properties:
                  success: { type: integer, examples: [1] }
              example:
                success: 1

  /market/sellitem/:
    post:
      operationId: createMarketSellListing
      tags: [Mutations]
      summary: Create a sell listing
      description: Creates a sell listing for an owned asset. A successful response can still require mobile or email confirmation.
      security:
        - sessionCookie: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/SellItemRequest'
      responses:
        '200':
          description: Listing creation and confirmation requirements.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SellItemResponse'
              example:
                success: true
                requires_confirmation: 1
                needs_mobile_confirmation: true
                needs_email_confirmation: false
                email_domain: ''

  /market/removelisting/{listingid}:
    post:
      operationId: removeMarketListing
      tags: [Mutations]
      summary: Remove a sell listing
      description: Removes an account sell listing. Success returns an empty JSON array.
      security:
        - sessionCookie: []
      parameters:
        - name: listingid
          in: path
          required: true
          schema: { type: string }
          example: '1234567890123456789'
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required: [sessionid]
              properties:
                sessionid: { type: string, description: CSRF token matching the active Steam session. }
            example:
              sessionid: '<redacted>'
      responses:
        '200':
          description: Empty JSON array.
          content:
            application/json:
              schema:
                type: array
                maxItems: 0
                items: {}
              example: []

components:
  securitySchemes:
    confirmationKey:
      type: apiKey
      in: query
      name: k
      description: |
        Base64 HMAC-SHA1 of the request `tag` and Unix timestamp, keyed by the account's
        `identity_secret` from its Steam Guard mobile authenticator. Sent alongside `p`, `a`, `t`,
        and `m`. This is not the session cookie and not the `sessionid` CSRF field.
    sessionCookie:
      type: apiKey
      in: header
      name: Cookie
      description: Authenticated Steam Community cookies, including `steamLoginSecure`; mutations also carry `sessionid` in the form body.

  parameters:
    AppIdPath:
      name: appid
      in: path
      required: true
      schema: { type: integer }
      description: Steam application ID.
      example: 730
    AppIdQuery:
      name: appid
      in: query
      schema: { type: integer }
      description: Steam application ID.
      example: 730
    AppIdQueryRequired:
      name: appid
      in: query
      required: true
      schema: { type: integer }
      description: Steam application ID.
      example: 730
    MarketHashNamePath:
      name: market_hash_name
      in: path
      required: true
      allowReserved: false
      schema: { type: string }
      description: URL-encoded Market hash name or opaque structured Market `G…` group name.
      example: AK-47 | Redline (Field-Tested)
    MarketHashNameQuery:
      name: market_hash_name
      in: query
      required: true
      schema: { type: string }
      description: Locale-independent Market hash name.
      example: AK-47 | Redline (Field-Tested)
    Country:
      name: country
      in: query
      required: true
      schema: { type: string, minLength: 2, maxLength: 2 }
      example: US
    Language:
      name: language
      in: query
      required: true
      schema: { type: string }
      example: english
    Currency:
      name: currency
      in: query
      required: true
      description: |
        Steam currency ID. Prices in the response are converted and formatted for this currency.
      schema:
        type: integer
        example: 1
        enum: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
               24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40, 41]
        x-enum-descriptions:
          1: USD
          2: GBP
          3: EUR
          4: CHF
          5: RUB
          6: PLN
          7: BRL
          8: JPY
          9: NOK
          10: IDR
          11: MYR
          12: PHP
          13: SGD
          14: THB
          15: VND
          16: KRW
          17: TRY
          18: UAH
          19: MXN
          20: CAD
          21: AUD
          22: NZD
          23: CNY
          24: INR
          25: CLP
          26: PEN
          27: COP
          28: ZAR
          29: HKD
          30: TWD
          31: SAR
          32: AED
          33: SEK
          34: ARS
          35: ILS
          37: KZT
          38: KWD
          39: QAR
          40: CRC
          41: UYU
    ItemNameId:
      name: item_nameid
      in: query
      required: true
      schema: { type: string }
      description: Internal Market item-name ID, distinct from `classid`.
      example: '176024744'
    SearchQ:
      name: q
      in: query
      description: Free-text query. Matches Market hash names, and item descriptions when `descriptions=1`.
      schema: { type: string }
      example: doppler
    SearchDescriptions:
      name: descriptions
      in: query
      description: Set to `1` to extend the text query to item descriptions.
      schema: { type: integer, enum: [0, 1] }
    SearchSort:
      name: sort
      in: query
      description: |
        Sort column. `0` and `4` both mean popularity, which is the default and ignores `dir`.
      schema:
        type: integer
        enum: [0, 1, 2, 3, 4]
        default: 0
        x-enum-descriptions:
          0: Popularity
          1: Name
          2: Quantity
          3: Price
          4: Popularity
    SearchDir:
      name: dir
      in: query
      description: Sort direction. `1` ascending, `2` descending.
      schema: { type: integer, enum: [1, 2] }
    CategoryType:
      name: category_Type
      in: query
      description: |
        Item type. Repeat the parameter to select several types; repeated values are ORed.
      schema:
        type: array
        items:
          type: string
          enum:
            - CSGO_Type_Pistol
            - CSGO_Type_SMG
            - CSGO_Type_Rifle
            - CSGO_Type_SniperRifle
            - CSGO_Type_Shotgun
            - CSGO_Type_Machinegun
            - CSGO_Type_Knife
            - Type_Hands
            - CSGO_Type_WeaponCase
            - CSGO_Tool_Sticker
            - CSGO_Type_Spray
            - CSGO_Type_Collectible
            - Type_CustomPlayer
      explode: true
      style: form
      example: [CSGO_Type_SniperRifle, CSGO_Type_Rifle]
    CategoryWeapon:
      name: category_Weapon
      in: query
      description: |
        Weapon. Repeat the parameter to select several weapons.
      schema:
        type: array
        items:
          type: string
          enum:
            - weapon_ak47
            - weapon_aug
            - weapon_awp
            - weapon_bizon
            - weapon_famas
            - weapon_fiveseven
            - weapon_g3sg1
            - weapon_galilar
            - weapon_hkp2000
            - weapon_knife_flip
            - weapon_m4a1
            - weapon_m4a1_silencer
            - weapon_mag7
            - weapon_mp5sd
            - weapon_mp9
            - weapon_p250
            - weapon_p90
            - weapon_revolver
            - weapon_sawedoff
            - weapon_scar20
            - weapon_sg556
            - weapon_ssg08
      explode: true
      style: form
      example: [weapon_awp]
    CategoryQuality:
      name: category_Quality
      in: query
      description: |
        Item category, shown as "Category" in the Market UI. Covers StatTrak, Souvenir, and the
        star-prefixed knife and glove qualities.
      schema:
        type: array
        items:
          type: string
          enum: [normal, strange, tournament, unusual, unusual_strange, highlight]
          x-enum-descriptions:
            normal: Normal
            strange: StatTrak
            tournament: Souvenir
            unusual: Star, for knives and gloves
            unusual_strange: Star with StatTrak
            highlight: Highlight
      explode: true
      style: form
      example: [strange]
    CategoryRarity:
      name: category_Rarity
      in: query
      description: |
        Rarity, shown as "Quality" in the Market UI.
      schema:
        type: array
        items:
          type: string
          enum:
            - Rarity_Common_Weapon
            - Rarity_Uncommon_Weapon
            - Rarity_Rare_Weapon
            - Rarity_Mythical_Weapon
            - Rarity_Legendary_Weapon
            - Rarity_Ancient_Weapon
            - Rarity_Ancient
          x-enum-descriptions:
            Rarity_Common_Weapon: Consumer Grade
            Rarity_Uncommon_Weapon: Industrial Grade
            Rarity_Rare_Weapon: Mil-Spec Grade
            Rarity_Mythical_Weapon: Restricted
            Rarity_Legendary_Weapon: Classified
            Rarity_Ancient_Weapon: Covert
            Rarity_Ancient: Extraordinary
      explode: true
      style: form
      example: [Rarity_Legendary_Weapon]
    CategoryExterior:
      name: category_Exterior
      in: query
      description: Exterior wear band.
      schema:
        type: array
        items:
          type: string
          enum: [WearCategory0, WearCategory1, WearCategory2, WearCategory3, WearCategory4]
          x-enum-descriptions:
            WearCategory0: Factory New
            WearCategory1: Minimal Wear
            WearCategory2: Field-Tested
            WearCategory3: Well-Worn
            WearCategory4: Battle-Scarred
      explode: true
      style: form
      example: [WearCategory0, WearCategory1]
    CategoryItemSet:
      name: category_ItemSet
      in: query
      description: |
        Collection. Values are `set_` identifiers such as `set_anubis`, `set_dust_2`, or
        `set_community_31`. The set is release-dependent; read the current list from
        `GET /market/appfacets/{appid}`.
      schema:
        type: array
        items: { type: string }
      explode: true
      style: form
      example: [set_community_31]
    CategoryTournament:
      name: category_Tournament
      in: query
      description: |
        Tournament, as `Tournament{n}`. New majors add values, so read the current list from
        `GET /market/appfacets/{appid}`.
      schema:
        type: array
        items: { type: string }
      explode: true
      style: form
      example: [Tournament25]
    CategoryTournamentTeam:
      name: category_TournamentTeam
      in: query
      description: |
        Tournament team, as `Team{n}`. Read the current list from `GET /market/appfacets/{appid}`.
      schema:
        type: array
        items: { type: string }
      explode: true
      style: form
      example: [Team12]
    CategoryProPlayer:
      name: category_ProPlayer
      in: query
      description: |
        Professional player, as a lowercase handle such as `s1mple` or `zywoo`. Read the current
        list from `GET /market/appfacets/{appid}`.
      schema:
        type: array
        items: { type: string }
      explode: true
      style: form
      example: [zywoo]
    AccessorySticker:
      name: accessory_CSGO_Tool_Sticker
      in: query
      description: |
        Applied sticker, selected by full display name, for example
        `Sticker | BLAST.tv (Gold) | Paris 2023`. Repeat the parameter to OR several stickers.
        `$any$` matches any applied sticker and `$none$` matches items with none. Read the
        current list from `GET /market/appaccessories/{appid}`.
      schema:
        type: array
        items: { type: string }
      explode: true
      style: form
      example: ["Sticker | BLAST.tv (Gold) | Paris 2023"]
    AccessoryKeychain:
      name: accessory_CSGO_Tool_Keychain
      in: query
      description: |
        Applied charm, selected by full display name, for example `Charm | Stitch-Loaded`. Repeat
        the parameter to OR several charms. `$any$` matches any applied charm and `$none$` matches
        items with none. Read the current list from `GET /market/appaccessories/{appid}`.
      schema:
        type: array
        items: { type: string }
      explode: true
      style: form
      example: ["Charm | Stitch-Loaded"]
    ConfDeviceId:
      name: p
      in: query
      required: true
      description: Device identifier, derived from the SteamID by the mobile authenticator.
      schema: { type: string }
    ConfSteamId:
      name: a
      in: query
      required: true
      description: SteamID64 of the account.
      schema: { type: string }
    ConfKey:
      name: k
      in: query
      required: true
      description: Base64 HMAC-SHA1 over the tag and timestamp, keyed by `identity_secret`.
      schema: { type: string }
    ConfTime:
      name: t
      in: query
      required: true
      description: Unix seconds. Must match the timestamp the key was generated for.
      schema: { type: integer, format: int64 }
    ConfDevice:
      name: m
      in: query
      required: true
      description: Client kind. Confirmations are an authenticator flow, so this is `android`.
      schema: { type: string, enum: [android, react] }
    NoRender:
      name: norender
      in: query
      description: |
        Set to `1` to receive a JSON body instead of server-rendered HTML. Without it these
        endpoints answer with an HTML page.
      schema: { type: integer, enum: [0, 1], default: 0 }
      example: 1
    TwoFactor:
      name: two_factor
      in: query
      description: Sent as `0` by the Market UI. No observed effect on the response.
      schema: { type: integer, enum: [0, 1] }
    Start:
      name: start
      in: query
      required: true
      schema: { type: integer, minimum: 0 }
      example: 0
    Count:
      name: count
      in: query
      required: true
      schema: { type: integer, minimum: 1 }
      example: 10

  responses:
    Redirect:
      description: Redirect based on authentication, eligibility, or canonical route.
      headers:
        Location:
          schema: { type: string, format: uri-reference }
  schemas:
    StructuredSearchRequest:
      type: object
      required: [appid, filters, price, accessoryFilters, start]
      description: |
        One structured search. Send it as the single element of a JSON array.

        `filters`, `accessoryFilters`, and `propertyFilters` are ANDed with each other and with
        the text query. Send `filters` and `accessoryFilters` as empty objects rather than
        omitting them.
      properties:
        appid: { type: integer, description: Steam application ID., example: 730 }
        filters:
          $ref: '#/components/schemas/FilterMap'
        accessoryFilters:
          $ref: '#/components/schemas/AccessoryFilterMap'
        propertyFilters:
          $ref: '#/components/schemas/PropertyFilterMap'
        price:
          $ref: '#/components/schemas/PriceFilter'
        strQuery:
          type: string
          description: Free-text query. Equivalent to `q` in the query string.
        bSearchDescriptions:
          type: boolean
          description: Extends the text query to item descriptions. Equivalent to `descriptions=1`.
        sort:
          type: integer
          enum: [0, 1, 2, 3, 4]
          default: 0
          description: |
            Sort column: `0` and `4` popularity, `1` name, `2` quantity, `3` price. Popularity
            ignores `direction`.
        direction:
          type: integer
          enum: [1, 2]
          description: '`1` ascending, `2` descending.'
        start:
          type: integer
          minimum: 0
          description: |
            Zero-based offset of the first result. The Market UI advances it in steps of 10 for
            grouped results and 30 for listing rows; `total_count` bounds it.
        strItemName:
          type: string
          description: |
            Restricts the search to one catalog entry, given as a Market hash name or an opaque
            `G…` group name. Used by the listing page rather than by search.

    StructuredListingsRequest:
      type: object
      required: [appid, strItemName, filters, accessoryFilters, propertyFilters, start]
      properties:
        appid: { type: integer }
        strItemName: { type: string, description: Market hash name or structured `G…` group name. }
        filters:
          $ref: '#/components/schemas/FilterMap'
        accessoryFilters:
          $ref: '#/components/schemas/FilterMap'
        propertyFilters:
          $ref: '#/components/schemas/PropertyFilterMap'
        price:
          $ref: '#/components/schemas/PriceFilter'
        start: { type: integer, minimum: 0 }

    FilterMap:
      type: object
      description: |
        Catalog tag selection, keyed by facet category name without the `category_` prefix
        (`Type`, `Weapon`, `Quality`, `Rarity`, `Exterior`, `ItemSet`, `Tournament`,
        `TournamentTeam`, `ProPlayer`). Values are tag internal names.

        Values within one array are ORed; separate keys are ANDed. An empty object applies no
        tag filtering.
      additionalProperties:
        type: array
        items: { type: string }
      example:
        Type: [CSGO_Type_SniperRifle, CSGO_Type_Rifle]
        Rarity: [Rarity_Legendary_Weapon]
    AccessoryFilterMap:
      type: object
      description: |
        Applied-accessory selection, keyed by the full `accessory_` parameter name
        (`accessory_CSGO_Tool_Sticker`, `accessory_CSGO_Tool_Keychain`).

        Unlike `filters`, values are accessory display names rather than internal names, for
        example `Sticker | BLAST.tv (Gold) | Paris 2023`. Two sentinels are accepted: `$any$`
        matches items carrying any accessory of that kind, `$none$` matches items carrying none.

        Values within one array are ORed; separate keys are ANDed.
      additionalProperties:
        type: array
        items: { type: string }
      example:
        accessory_CSGO_Tool_Keychain: ["Charm | Stitch-Loaded"]
        accessory_CSGO_Tool_Sticker: ["$none$"]

    PriceFilter:
      type: object
      required: [eCurrency]
      description: |
        Currency selection and optional price bounds. Bounds are inclusive and expressed in the
        minor units of `eCurrency`, so `unMin: 2063` is $20.63 when `eCurrency` is `1`. Omit a
        bound to leave that end open. Price bounds have no query-string equivalent.
      properties:
        eCurrency: { type: integer, description: Steam currency enum. `1` is USD., example: 1 }
        unMin: { type: integer, minimum: 0, description: Minimum price in minor units. }
        unMax: { type: integer, minimum: 0, description: Maximum price in minor units. }

    PropertyFilterMap:
      type: object
      description: |
        Numeric asset-property constraints, keyed by asset property ID as a string. The key
        repeats the `property_id` inside the value.

        Bounds are inclusive. Integer-valued properties use `int_min` and `int_max`, which Steam
        sends as strings; continuous properties use `float_min` and `float_max`. Property IDs and
        their value ranges are application-specific.

        Property filters have no query-string equivalent, so a search using them can only be
        issued against `POST /market/search`.
      additionalProperties:
        type: object
        required: [property_id]
        properties:
          property_id: { type: integer }
          int_min: { type: string }
          int_max: { type: string }
          float_min: { type: number }
          float_max: { type: number }
      example:
        '1': { property_id: 1, int_min: '385', int_max: '678' }

    StructuredSearchResponse:
      type: object
      required: [start, total_count, grouping, facets, results]
      properties:
        start: { type: integer }
        total_count: { type: integer }
        grouping: { type: integer }
        facets:
          type: array
          items:
            $ref: '#/components/schemas/ListingFacet'
        results:
          type: array
          items:
            $ref: '#/components/schemas/SearchResult'

    StructuredListingsResponse:
      type: object
      required: [more, start, total_count, listings, facets]
      properties:
        more: { type: boolean }
        start: { type: integer }
        total_count: { type: integer }
        listings:
          type: array
          items:
            $ref: '#/components/schemas/MarketListing'
        facets:
          type: array
          items:
            $ref: '#/components/schemas/ListingFacet'

    SearchResult:
      type: object
      properties:
        strHash: { type: string }
        cSellOrders: { type: integer }
        cBuyOrders: { type: integer }
        unSteamFee: { type: integer }
        unPublisherFee: { type: integer }
        eCurrency: { type: integer }
        strMinSellSubtotal: { type: string }
        asset_description:
          $ref: '#/components/schemas/AssetDescription'
        app:
          type: object
          properties:
            appid: { type: integer }
            strName: { type: string }
            strIcon: { type: string }

    MarketListing:
      type: object
      properties:
        listingid: { type: string }
        unPrice: { type: integer, description: Subtotal in minor units. }
        unFee: { type: integer, description: Total fee in minor units. }
        publisherFeeApp: { type: integer }
        publisherFeePct: { type: number }
        eCurrency: { type: integer }
        strSubtotal: { type: string }
        enhanced_appearances:
          type: array
          items:
            type: object
            properties:
              mime_type: { type: string }
              url: { type: string, format: uri }
        description:
          $ref: '#/components/schemas/AssetDescription'
        bMine: { type: boolean }
        unSteamFee: { type: integer }
        unPublisherFee: { type: integer }
        unPricePerUnit: { type: integer }
        unFeePerUnit: { type: integer }
        unSteamFeePerUnit: { type: integer }
        unPublisherFeePerUnit: { type: integer }
        asset:
          $ref: '#/components/schemas/MarketAsset'

    MarketAsset:
      type: object
      properties:
        id: { type: string }
        assetid: { type: string }
        instanceid: { type: string }
        classid: { type: string }
        amount: { oneOf: [{ type: integer }, { type: string }] }
        appid: { type: integer }
        contextid: { type: string }
        asset_properties:
          type: array
          items:
            $ref: '#/components/schemas/AssetProperty'
        asset_accessories:
          type: array
          items:
            $ref: '#/components/schemas/AssetAccessory'

    AssetDescription:
      type: object
      properties:
        appid: { type: integer }
        classid: { type: string }
        instanceid: { type: string }
        currency: { oneOf: [{ type: boolean }, { type: integer }] }
        background_color: { type: string }
        icon_url: { type: string }
        icon_url_large: { type: string }
        descriptions:
          type: array
          items:
            $ref: '#/components/schemas/DescriptionLine'
        tradable: { oneOf: [{ type: boolean }, { type: integer }] }
        actions:
          type: array
          items:
            $ref: '#/components/schemas/ItemAction'
        owner_descriptions:
          type: array
          items:
            $ref: '#/components/schemas/DescriptionLine'
        owner_actions:
          type: array
          items:
            $ref: '#/components/schemas/ItemAction'
        fraudwarnings:
          type: array
          items: { type: string }
        name: { type: string }
        name_color: { type: string }
        type: { type: string }
        market_name: { type: string }
        market_hash_name: { type: string }
        market_actions:
          type: array
          items:
            $ref: '#/components/schemas/ItemAction'
        commodity: { oneOf: [{ type: boolean }, { type: integer }] }
        market_tradable_restriction: { type: integer }
        market_marketable_restriction: { type: integer }
        marketable: { oneOf: [{ type: boolean }, { type: integer }] }
        tags:
          type: array
          items:
            $ref: '#/components/schemas/ItemTag'
        sealed: { oneOf: [{ type: boolean }, { type: integer }] }
        sealed_type: { type: integer }
        market_bucket_id: { type: string }
        market_bucket_group_id: { type: string }
        market_bucket_group_name: { type: string }
        market_name_inside_group: { type: string }
        container_properties:
          type: object
          properties:
            contained_items:
              type: array
              items:
                type: object
                properties:
                  classid: { type: string }
                  instanceid: { type: string }
                additionalProperties: true

    DescriptionLine:
      type: object
      properties:
        type: { type: string }
        value: { type: string }
        name: { type: string }
        color: { type: string }

    ItemAction:
      type: object
      properties:
        type: { type: string }
        name: { type: string }
        link: { type: string }

    ItemTag:
      type: object
      properties:
        category: { type: string }
        internal_name: { type: string }
        localized_category_name: { type: string }
        localized_tag_name: { type: string }
        category_name: { type: string }
        name: { type: string }
        color: { type: string }

    ListingFacet:
      type: object
      properties:
        tag:
          type: object
          properties:
            appid: { type: integer }
            category: { type: string }
            internal_name: { type: string }
            localized_category_name: { type: string }
            localized_tag_name: { type: string }
            color: { type: string }
        listings: { type: integer }

    SearchSuggestionsResponse:
      type: object
      required: [results, apps]
      properties:
        results:
          type: array
          items:
            type: object
            properties:
              market_name: { type: string }
              market_hash_name: { type: string }
              app_id: { type: integer }
              app_name: { type: string }
              icon_url: { type: string }
              market_type: { type: string }
              listing_count: { type: integer }
              search_score: { type: integer }
        apps:
          type: array
          items:
            type: object
            properties:
              appid: { type: integer }
              name: { type: string }
              icon: { type: string }

    LegacySearchRenderResponse:
      type: object
      required: [success, start, pagesize, total_count, results_html]
      properties:
        success: { type: boolean }
        start: { type: integer }
        pagesize: { type: integer }
        total_count: { type: integer }
        tip: { type: string }
        results_html: { type: string }

    LegacyListingsRenderResponse:
      type: object
      properties:
        success: { type: boolean }
        start: { type: integer }
        pagesize: { type: integer }
        total_count: { type: integer }
        results_html: { type: string }
        listinginfo:
          type: object
          description: Map keyed by listing ID.
          additionalProperties:
            $ref: '#/components/schemas/LegacyListingInfo'
        assets:
          type: object
          description: Nested `appid → contextid → assetid → asset` map.
          additionalProperties:
            type: object
            additionalProperties:
              type: object
              additionalProperties:
                $ref: '#/components/schemas/LegacyMarketAsset'
        currency:
          type: array
          items: { type: object, additionalProperties: true }
        hovers: { type: string }
        app_data:
          type: object
          additionalProperties:
            type: object
            properties:
              appid: { type: integer }
              name: { type: string }
              icon: { type: string }
              link: { type: string }

    LegacyListingInfo:
      type: object
      description: Listing record keyed by `listingid` in legacy renderer responses.
      properties:
        listingid: { type: string }
        price: { type: integer, description: Seller subtotal in minor units. }
        fee: { type: integer, description: Total fee in minor units. }
        publisher_fee: { type: integer }
        publisher_fee_app: { type: integer }
        publisher_fee_percent: { type: string }
        steam_fee: { type: integer }
        currencyid: { type: integer }
        converted_price: { type: integer }
        converted_fee: { type: integer }
        converted_publisher_fee: { type: integer }
        converted_steam_fee: { type: integer }
        converted_currencyid: { type: integer }
        converted_price_per_unit: { type: integer }
        converted_fee_per_unit: { type: integer }
        converted_publisher_fee_per_unit: { type: integer }
        converted_steam_fee_per_unit: { type: integer }
        asset:
          type: object
          properties:
            appid: { type: integer }
            contextid: { type: string }
            id: { type: string }
            amount: { type: string }
            currency: { type: integer }
            market_actions:
              type: array
              items:
                $ref: '#/components/schemas/ItemAction'

    LegacyMarketAsset:
      allOf:
        - $ref: '#/components/schemas/AssetDescription'
        - type: object
          properties:
            id: { type: string }
            amount: { type: string }
            original_amount: { type: string }
            owner: { type: integer }
            status: { type: integer }
            contextid: { type: string }
            app_icon: { type: string }
            unowned_contextid: { type: string }
            unowned_id: { type: string }
            asset_properties:
              type: array
              items:
                $ref: '#/components/schemas/AssetProperty'

    OrderBookResponse:
      type: object
      required: [data]
      properties:
        data:
          type: object
          required: [success, data]
          properties:
            success: { type: boolean }
            data:
              type: object
              properties:
                amtMaxBuyOrder: { type: [integer, 'null'], description: Best buy price in minor units. }
                amtMinSellOrder: { type: integer, description: Best sell price in minor units. }
                eCurrency: { type: integer }
                cBuyOrders: { type: integer }
                cSellOrders: { type: integer }
                rgCompactBuyOrders:
                  type: array
                  items: { type: integer }
                  description: Flat alternating `[price, quantity, price, quantity, …]` array.
                rgCompactSellOrders:
                  type: array
                  items: { type: integer }
                  description: Flat alternating `[price, quantity, price, quantity, …]` array.

    OrderHistogramResponse:
      type: object
      required: [success]
      properties:
        success: { type: integer, examples: [1] }
        sell_order_table: { type: string, description: Server-rendered HTML table. }
        sell_order_summary: { type: string, description: Server-rendered HTML summary. }
        buy_order_table: { type: string, description: Server-rendered HTML table. }
        buy_order_summary: { type: string, description: Server-rendered HTML summary. }
        highest_buy_order: { type: string, description: Integer minor units encoded as a string. }
        lowest_sell_order: { type: string, description: Integer minor units encoded as a string. }
        buy_order_graph:
          type: array
          items:
            type: array
            prefixItems:
              - { type: number, description: Price. }
              - { type: integer, description: Cumulative quantity. }
              - { type: string, description: Formatted label. }
        sell_order_graph:
          type: array
          items:
            type: array
            prefixItems:
              - { type: number, description: Price. }
              - { type: integer, description: Cumulative quantity. }
              - { type: string, description: Formatted label. }
        graph_max_y: { type: integer }
        graph_min_x: { type: number }
        graph_max_x: { type: number }
        price_prefix: { type: string }
        price_suffix: { type: string }

    PriceOverviewResponse:
      type: object
      required: [success]
      properties:
        success: { type: boolean }
        lowest_price: { type: string, description: Localized formatted value. }
        volume: { type: string, description: Localized volume string. }
        median_price: { type: string, description: Localized formatted value. }

    PriceHistoryResponse:
      type: object
      required: [success, price_prefix, price_suffix, prices]
      properties:
        success: { type: boolean }
        price_prefix: { type: string }
        price_suffix: { type: string }
        prices:
          type: array
          items:
            type: array
            prefixItems:
              - { type: string, description: Steam date string. }
              - { type: number, description: Price in major currency units. }
              - { type: string, description: Volume encoded as a string. }

    AppFacet:
      type: object
      properties:
        appid: { type: integer }
        name: { type: string }
        localized_name: { type: string }
        tags:
          type: object
          additionalProperties:
            type: object
            properties:
              localized_name: { type: string }
              matches: { type: string }

    UserBillingInfoResponse:
      type: object
      properties:
        billing_address:
          $ref: '#/components/schemas/BillingAddress'
        require_billing_info: { type: boolean }
        country_code: { type: string }
        billing_states:
          type: object
          additionalProperties:
            type: object
            properties:
              state_code: { type: string }
              support_shipping: { type: integer }
              state_name: { type: string }
        localized_country: { type: string }
        wallet_info:
          $ref: '#/components/schemas/WalletInfo'
        account_name: { type: string }
        ssa:
          type: object
          properties:
            last_update: { type: integer, format: int64 }
            latest_accepted: { type: boolean }
            eu_ssa: { type: boolean }
        confirmation_type: { type: integer }
        tax_rate:
          $ref: '#/components/schemas/TaxRate'

    WalletInfo:
      type: object
      properties:
        success: { type: integer }
        wallet_currency: { type: integer }
        wallet_country: { type: string }
        wallet_state: { type: string }
        wallet_balance: { type: string, description: Minor units encoded as a string. }
        wallet_delayed_balance: { type: string }
        wallet_currency_increment: { type: string }
        wallet_fee: { type: string }
        wallet_fee_base: { type: string }
        wallet_fee_minimum: { type: string }
        wallet_fee_percent: { type: string }
        wallet_market_minimum: { type: string }
        wallet_max_balance: { type: string }
        wallet_trade_max_balance: { type: string }
        wallet_publisher_fee_percent_default: { type: string }
        rwgrsn: { type: integer }

    TaxRate:
      type: object
      properties:
        success: { type: boolean }
        tradefee_addtax: { type: integer }
        tradefee_taxrate: { type: integer }
        tax_region: { type: string }

    BillingAddress:
      type: object
      properties:
        firstname: { type: string }
        lastname: { type: string }
        address1: { type: string }
        address2: { type: string }
        city: { type: string }
        state: { type: string }
        countrycode: { type: string }
        postcode: { type: string }
        phone: { type: string }

    MyListingsResponse:
      type: object
      properties:
        success: { type: boolean }
        pagesize: { type: integer }
        total_count: { type: integer }
        start: { type: integer }
        num_active_listings: { type: integer }
        assets:
          type: object
          description: Nested `appid → contextid → assetid → asset description` map.
          additionalProperties:
            type: object
            additionalProperties:
              type: object
              additionalProperties:
                $ref: '#/components/schemas/LegacyMarketAsset'
        hovers: { type: string }
        results_html: { type: string }

    CreateBuyOrderRequest:
      type: object
      required: [sessionid, currency, appid, market_hash_name, price_total, quantity]
      properties:
        sessionid: { type: string, description: CSRF token matching the active Steam session., example: '<redacted>' }
        currency: { type: string, pattern: '^\d+$', description: Steam currency enum., example: '1' }
        appid: { type: string, pattern: '^\d+$', example: '730' }
        market_hash_name: { type: string, example: 'AK-47 | Redline (Field-Tested)' }
        price_total: { type: string, pattern: '^\d+$', description: Total order price in minor units., example: '1200' }
        tradefee_tax: { type: string, pattern: '^\d+$' }
        quantity: { type: string, pattern: '^\d+$', example: '1' }
        first_name: { type: string }
        last_name: { type: string }
        billing_address: { type: string }
        billing_address_two: { type: string }
        billing_country: { type: string }
        billing_city: { type: string }
        billing_state: { type: string }
        billing_postal_code: { type: string }
        confirmation: { type: string, pattern: '^\d+$' }
        save_my_address: { type: string, enum: ['0', '1'] }

    SellItemRequest:
      type: object
      required: [sessionid, appid, contextid, assetid, amount, price]
      properties:
        sessionid: { type: string, description: CSRF token matching the active Steam session., example: '<redacted>' }
        appid: { type: string, pattern: '^\d+$', example: '730' }
        contextid: { type: string, example: '2' }
        assetid: { type: string, example: '12345678901234567890' }
        amount: { type: string, pattern: '^\d+$', example: '1' }
        price: { type: string, pattern: '^\d+$', description: Seller price in minor units., example: '1200' }

    SellItemResponse:
      type: object
      required: [success]
      properties:
        success: { type: boolean }
        requires_confirmation: { type: integer }
        needs_mobile_confirmation: { type: boolean }
        needs_email_confirmation: { type: boolean }
        email_domain: { type: string }

    AssetProperty:
      type: object
      properties:
        propertyid: { type: integer }
        string_value: { type: string }
        int_value: { type: string }
        float_value: { type: number }

    AssetAccessory:
      type: object
      properties:
        classid: { type: string }
        instanceid: { type: string }
        description:
          $ref: '#/components/schemas/AssetDescription'
        nested_accessories:
          type: array
          items:
            type: object
            properties:
              classid: { type: string }
              instanceid: { type: string }
            additionalProperties: true
        parent_relationship_properties:
          type: array
          items:
            $ref: '#/components/schemas/AssetProperty'
        standalone_properties:
          type: array
          items:
            $ref: '#/components/schemas/AssetProperty'
