openapi: 3.1.0
info:
  title: CSFloat Market API
  version: '1.0.0'
  summary: Unofficial market, item, order, offer, inventory, and trade reference.
  description: |
    Reference for the CSFloat market, item, order, offer, inventory, and trade APIs.

    CSFloat does not publish a complete contract for these routes. They can change without notice.

    This is an unofficial reference, not affiliated with or endorsed by CSFloat.

    All monetary integers are USD cents unless a field explicitly states otherwise. Numeric IDs
    are represented as strings because they exceed JavaScript's safe integer range.
  license:
    name: Unofficial documentation
    url: https://docs.csfloat.com/
externalDocs:
  description: Official CSFloat API reference
  url: https://docs.csfloat.com/
servers:
  - url: https://csfloat.com/api/v1
    description: CSFloat API
tags:
  - name: Market data
    description: Listings, price history, item schema, seller stalls, and currency conversion.
  - name: Buying
    description: Buying outright, bidding on auctions, and standing buy orders.
  - name: Selling
    description: Your inventory, and the listings you create from it.
  - name: Offers
    description: Negotiating price on a listing before it sells.
  - name: Trades
    description: Delivering a sale, from acceptance to settlement.
  - name: Account
    description: Balance ledger and watchlist.
paths:
  /listings:
    get:
      tags: [Market data]
      operationId: getListings
      summary: Get listings
      description: |
        Returns a cursor-paginated market page as `{ data, cursor }`. Filters combine freely; every
        parameter below is optional.
      security: []
      parameters:
        - $ref: '#/components/parameters/Cursor'
        - name: limit
          in: query
          description: Results per page. Official maximum is 50.
          schema: { type: integer, minimum: 1, maximum: 50, default: 50 }
        - name: sort_by
          in: query
          schema:
            type: string
            default: best_deal
            enum: [lowest_price, highest_price, most_recent, expires_soon, lowest_float, highest_float, best_deal, highest_discount, float_rank, num_bids]
        - name: category
          in: query
          description: 0 any, 1 normal, 2 StatTrak, 3 souvenir.
          schema: { type: integer, enum: [0, 1, 2, 3], default: 0 }
        - name: def_index
          in: query
          schema: { type: integer }
        - name: paint_index
          in: query
          schema: { type: integer }
        - name: paint_seed
          in: query
          schema: { type: integer }
        - name: min_float
          in: query
          schema: { type: number, minimum: 0, maximum: 1 }
        - name: max_float
          in: query
          schema: { type: number, minimum: 0, maximum: 1 }
        - name: rarity
          in: query
          schema: { type: integer }
        - name: user_id
          in: query
          description: Seller Steam ID64.
          schema: { $ref: '#/components/schemas/Id' }
        - name: collection
          in: query
          schema: { type: string }
        - name: min_price
          in: query
          schema: { $ref: '#/components/schemas/Money' }
        - name: max_price
          in: query
          schema: { $ref: '#/components/schemas/Money' }
        - name: market_hash_name
          in: query
          schema: { type: string }
        - name: type
          in: query
          schema: { type: string, enum: [buy_now, auction] }
        - name: stickers
          in: query
          description: Comma-separated `stickerId|slot` selectors. Slot is optional.
          schema: { type: string }
        - name: min_ref_qty
          in: query
          description: Minimum reference-price sample quantity.
          schema: { type: integer, minimum: 0 }
      responses:
        '200':
          description: Cursor-paginated listings.
          headers:
            X-RateLimit-Limit: { $ref: '#/components/headers/RateLimit' }
            X-RateLimit-Remaining: { $ref: '#/components/headers/RateLimitRemaining' }
            X-RateLimit-Reset: { $ref: '#/components/headers/RateLimitReset' }
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ListingPage' }
    post:
      tags: [Selling]
      operationId: createListing
      summary: Create a listing
      description: |
        Lists an inventory asset as buy-now or auction inventory.
      security: [{ ApiKeyAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CreateListingRequest' }
      responses:
        '200':
          description: Created listing.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Listing' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
  /listings/{listing_id}:
    get:
      tags: [Market data]
      operationId: getListing
      summary: Get a listing
      description: |
        Returns one listing regardless of active or inactive state. Optional fields depend on listing
        type, sale state, and item characteristics.
      security: []
      parameters:
        - $ref: '#/components/parameters/ListingId'
      responses:
        '200':
          description: Listing record.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Listing' }
        '404': { $ref: '#/components/responses/Error' }
    patch:
      tags: [Selling]
      operationId: updateListing
      summary: Update a listing
      description: |
        Changes the asking price of an active buy-now listing. Auction listings cannot be repriced
        once bidding has opened.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/ListingId'
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UpdateListingRequest' }
      responses:
        '200':
          description: Updated listing.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Listing' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
        '404': { $ref: '#/components/responses/Error' }
    delete:
      tags: [Selling]
      operationId: deleteListing
      summary: Remove a listing
      description: |
        Delists an active listing and returns the asset to the seller's inventory. A listing with a
        settled sale cannot be removed.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/ListingId'
      responses:
        '200':
          description: Removal confirmation.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Message' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
        '404': { $ref: '#/components/responses/Error' }
  /listings/buy:
    post:
      tags: [Buying]
      operationId: buyListings
      summary: Buy listings
      description: |
        Purchases one or more buy-now listings from market balance. `total_price` is the sum of the
        listed prices and is validated against them, so a listing that changed price or sold in the
        meantime fails the whole request.
      security: [{ ApiKeyAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/BuyListingsRequest' }
      responses:
        '200':
          description: |
            Succeeded. The web client discards this body, so its shape is not documented here.
            Treat the status as the result and do not depend on the payload.
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
  /listings/bulk-list:
    post:
      tags: [Selling]
      operationId: bulkCreateListings
      summary: Create listings in bulk
      description: |
        Lists several inventory assets in one request. Each entry takes the same fields as
        `POST /listings`; `notary_payload` is sent once for the batch rather than per item.
      security: [{ ApiKeyAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/BulkCreateListingsRequest' }
      responses:
        '200':
          description: Created listings.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ListingPageWrapped' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
  /listings/bulk-modify:
    patch:
      tags: [Selling]
      operationId: bulkModifyListings
      summary: Modify listings in bulk
      description: |
        Applies a per-listing change set. Each modification carries the listing `id` plus the fields
        to change, in the same shape `PATCH /listings/{listing_id}` accepts.
      security: [{ ApiKeyAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/BulkModifyListingsRequest' }
      responses:
        '200':
          description: Updated listings.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ListingPageWrapped' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
  /listings/bulk-delist:
    patch:
      tags: [Selling]
      operationId: bulkDelistListings
      summary: Delist listings in bulk
      description: |
        Removes several listings at once, returning their assets to the seller's inventory.
      security: [{ ApiKeyAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ContractIdsRequest' }
      responses:
        '200':
          description: |
            Succeeded. The web client discards this body, so its shape is not documented here.
            Treat the status as the result and do not depend on the payload.
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
  /listings/{listing_id}/bids:
    get:
      tags: [Market data]
      operationId: getListingBids
      summary: Get auction bid history
      description: Returns the bid history for an auction listing, most recent first.
      security: []
      parameters:
        - $ref: '#/components/parameters/ListingId'
      responses:
        '200':
          description: Bid history.
          content:
            application/json:
              schema:
                type: array
                items: { $ref: '#/components/schemas/Bid' }
  /listings/{listing_id}/bid:
    post:
      tags: [Buying]
      operationId: placeBid
      summary: Place a bid
      description: |
        Places a bid on an auction listing. `max_price` is a ceiling, not the amount bid: CSFloat
        raises the standing bid only as far as competing bids require, up to this value.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/ListingId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [max_price]
              properties:
                max_price: { $ref: '#/components/schemas/Money' }
            example:
              max_price: 25000
      responses:
        '200':
          description: Bid placed.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Bid' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
  /listings/{listing_id}/watchlist:
    post:
      tags: [Account]
      operationId: addToWatchlist
      summary: Add a listing to the watchlist
      description: Adds one listing to the authenticated user's watchlist. Takes no body.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/ListingId'
      responses:
        '200':
          description: |
            Succeeded. The web client discards this body, so its shape is not documented here.
            Treat the status as the result and do not depend on the payload.
        '401': { $ref: '#/components/responses/Error' }
    delete:
      tags: [Account]
      operationId: removeFromWatchlist
      summary: Remove a listing from the watchlist
      description: Removes one listing from the authenticated user's watchlist.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/ListingId'
      responses:
        '200':
          description: |
            Succeeded. The web client discards this body, so its shape is not documented here.
            Treat the status as the result and do not depend on the payload.
        '401': { $ref: '#/components/responses/Error' }
  /listings/{listing_id}/similar:
    get:
      tags: [Market data]
      operationId: getSimilarListings
      summary: Get similar listings
      description: |
        Returns comparable buy-now and auction listings for the selected contract.
      security: []
      parameters:
        - $ref: '#/components/parameters/ListingId'
      responses:
        '200':
          description: Comparable listings.
          content:
            application/json:
              schema:
                type: array
                items: { $ref: '#/components/schemas/Listing' }
  /listings/{listing_id}/buy-orders:
    get:
      tags: [Buying]
      operationId: getListingBuyOrders
      summary: Get matching buy orders
      description: |
        Returns aggregated buy orders compatible with a listing. Results contain price, quantity,
        market name, and any hybrid item constraints.
      security: []
      parameters:
        - $ref: '#/components/parameters/ListingId'
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, default: 10 }
      responses:
        '200':
          description: Matching order aggregates.
          content:
            application/json:
              schema:
                type: array
                items: { $ref: '#/components/schemas/BuyOrderAggregate' }
        '304': { description: Not modified. }
  /history/{market_hash_name}/graph:
    get:
      tags: [Market data]
      operationId: getPriceHistory
      summary: Get price history
      description: |
        Returns daily average sale price and sale count. URL-encode the complete market hash name.
      security: []
      parameters:
        - $ref: '#/components/parameters/MarketHashName'
        - name: paint_index
          in: query
          description: Restrict variants such as Doppler phase or knife finish.
          schema: { type: integer }
      responses:
        '200':
          description: Daily price series.
          content:
            application/json:
              schema:
                type: array
                items: { $ref: '#/components/schemas/HistoryPoint' }
        '304': { description: Not modified. }
  /history/{market_hash_name}/sales:
    get:
      tags: [Market data]
      operationId: getSalesHistory
      summary: Get individual sales
      description: |
        Returns recently completed listing records for an item and optional paint variant.
      security: []
      parameters:
        - $ref: '#/components/parameters/MarketHashName'
        - name: paint_index
          in: query
          schema: { type: integer }
      responses:
        '200':
          description: Completed sales.
          content:
            application/json:
              schema:
                type: array
                items: { $ref: '#/components/schemas/Listing' }
        '304': { description: Not modified. }
  /schema:
    get:
      tags: [Market data]
      operationId: getItemSchema
      summary: Get item schema
      description: |
        Returns catalog data for weapons, paints, stickers, keychains, collections, containers,
        agents, collectibles, music kits, rarities, custom stickers, and highlight reels.
      security: []
      responses:
        '200':
          description: Item catalog keyed by definition and paint identifiers.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ItemSchema' }
        '304': { description: Not modified. }
  /users/{steam_id}/stall:
    get:
      tags: [Market data]
      operationId: getUserStall
      summary: Get a user stall
      description: |
        Returns public sell listings and aggregate stall value. Private stalls return `403`.
      security: []
      parameters:
        - $ref: '#/components/parameters/SteamId'
        - $ref: '#/components/parameters/Cursor'
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, default: 40 }
        - name: filter
          in: query
          schema: { type: string, enum: [unique, sticker_combos] }
      responses:
        '200':
          description: Public stall listings and totals.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/StallPage' }
        '403':
          description: Private stall.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Error' }
              example: { code: 1, message: you cannot view a private stall }
  /me/watchlist:
    get:
      tags: [Account]
      operationId: getWatchlist
      summary: Get watchlist
      description: |
        Returns cursor-paginated watched listings.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/Cursor'
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, default: 40 }
      responses:
        '200':
          description: Watchlist page.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ListingPage' }
        '401': { $ref: '#/components/responses/Error' }
  /buy-orders:
    post:
      tags: [Buying]
      operationId: createBuyOrder
      summary: Create a buy order
      description: |
        Creates a quantity-based buy order. Takes `market_hash_name` plus optional constraints for
        float ranges, paint seeds, paint index, stickers, and keychains.
      security: [{ ApiKeyAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CreateBuyOrderRequest' }
      responses:
        '200':
          description: Created buy order.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/BuyOrder' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
  /buy-orders/similar-orders:
    post:
      tags: [Buying]
      operationId: getSimilarBuyOrders
      summary: Find similar buy orders
      description: |
        Returns competing orders for the same market name and hybrid properties. Use this before
        choosing a maximum price.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, default: 10 }
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/SimilarBuyOrdersRequest' }
      responses:
        '200':
          description: Similar order aggregates.
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items: { $ref: '#/components/schemas/BuyOrderAggregate' }
  /buy-orders/{order_id}:
    patch:
      tags: [Buying]
      operationId: updateBuyOrder
      summary: Update a buy order
      description: |
        Changes an open buy order. Send only the fields to change; quantity already matched into a
        trade is unaffected.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/BuyOrderId'
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UpdateBuyOrderRequest' }
      responses:
        '200':
          description: Updated buy order.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/BuyOrder' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
    delete:
      tags: [Buying]
      operationId: deleteBuyOrder
      summary: Remove a buy order
      description: |
        Cancels an open buy order. Any quantity already matched into a trade is unaffected.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/BuyOrderId'
      responses:
        '200':
          description: Removal confirmation.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Message' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
        '404': { $ref: '#/components/responses/Error' }
  /buy-orders/item:
    get:
      tags: [Buying]
      operationId: getBuyOrdersForItem
      summary: Get buy orders matching an inspected item
      description: |
        Returns the buy orders a specific in-game item would satisfy, given its inspect link. Unlike
        `GET /listings/{listing_id}/buy-orders`, which matches against a listing, this matches
        against an arbitrary item the caller can inspect.

        `sig` authenticates the inspect URL; it is issued alongside the link rather than derived
        from it.
      security: []
      parameters:
        - name: url
          in: query
          required: true
          description: Steam inspect link for the item.
          schema: { type: string }
        - name: market_hash_name
          in: query
          required: true
          schema: { type: string }
        - name: sig
          in: query
          required: true
          description: Signature accompanying the inspect link.
          schema: { type: string }
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, default: 3 }
      responses:
        '200':
          description: Matching buy orders.
          content:
            application/json:
              schema:
                type: array
                items: { $ref: '#/components/schemas/BuyOrder' }
  /me/auto-bids/{order_id}:
    delete:
      tags: [Buying]
      operationId: deleteAutoBid
      summary: Remove an auto-bid
      description: Cancels a standing automatic bid on an auction.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/BuyOrderId'
      responses:
        '200':
          description: |
            Succeeded. The web client discards this body, so its shape is not documented here.
            Treat the status as the result and do not depend on the payload.
        '401': { $ref: '#/components/responses/Error' }
        '404': { $ref: '#/components/responses/Error' }
  /me/buy-orders:
    get:
      tags: [Buying]
      operationId: getMyBuyOrders
      summary: Get my buy orders
      description: |
        Returns the authenticated user's buy orders.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/Limit'
        - name: order
          in: query
          schema: { type: string, enum: [asc, desc], default: desc }
      responses:
        '200':
          description: Paginated buy orders.
          content:
            application/json:
              schema:
                type: object
                required: [orders, count]
                properties:
                  orders:
                    type: array
                    items: { $ref: '#/components/schemas/BuyOrder' }
                  count: { type: integer, minimum: 0 }
  /me/auto-bids:
    get:
      tags: [Buying]
      operationId: getAutoBids
      summary: Get auto-bids
      description: |
        Returns active automatic auction bids. The array is empty when none are set.
      security: [{ ApiKeyAuth: [] }]
      responses:
        '200':
          description: Auto-bid records.
          content:
            application/json:
              schema:
                type: array
                items: { type: object, additionalProperties: true }
  /offers:
    post:
      tags: [Offers]
      operationId: createOffer
      summary: Create an offer
      description: |
        Creates a negotiated offer against a listing contract. Returns `400` with code `4` when the
        seller has offers disabled.
      security: [{ ApiKeyAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CreateOfferRequest' }
      responses:
        '200':
          description: Created offer.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Offer' }
        '400':
          description: Offer rejected.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Error' }
              example: { code: 4, message: offers aren't enabled }
  /offers/{offer_id}:
    delete:
      tags: [Offers]
      operationId: cancelOffer
      summary: Cancel an offer
      description: |
        Cancels an active offer.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/OfferId'
      responses:
        '200':
          description: Cancellation confirmation.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Message' }
        '400': { $ref: '#/components/responses/Error' }
  /offers/{offer_id}/accept:
    post:
      tags: [Offers]
      operationId: acceptOffer
      summary: Accept an offer
      description: Accepts an offer as the seller, creating a trade. Takes no body.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/OfferId'
      responses:
        '200':
          description: |
            Succeeded. The web client discards this body, so its shape is not documented here.
            Treat the status as the result and do not depend on the payload.
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
  /offers/{offer_id}/counter-offer:
    post:
      tags: [Offers]
      operationId: counterOffer
      summary: Counter an offer
      description: |
        Responds to an offer with a different price. The counter replaces the offer being answered.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/OfferId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [price]
              properties:
                price: { $ref: '#/components/schemas/Money' }
                message_id:
                  type: string
                  description: Optional message to attach to the counter.
            example:
              price: 18000
      responses:
        '200':
          description: Counter-offer created.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Offer' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
  /offers/{offer_id}/history:
    get:
      tags: [Offers]
      operationId: getOfferHistory
      summary: Get offer history
      description: |
        Returns the ordered negotiation history for one offer chain.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/OfferId'
      responses:
        '200':
          description: Offer history entries.
          content:
            application/json:
              schema:
                type: array
                items: { $ref: '#/components/schemas/OfferHistoryEntry' }
  /me/offers:
    get:
      tags: [Offers]
      operationId: getMyOffers
      summary: Get my offers
      description: |
        Returns profile-oriented offer history with a total count.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Paginated offers.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/OffersPage' }
  /me/offers-timeline:
    get:
      tags: [Offers]
      operationId: getOffersTimeline
      summary: Get offer timeline
      description: |
        Returns rich offer records. Repeat `states` to select multiple terminal states.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/Page'
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, default: 40 }
        - name: states
          in: query
          style: form
          explode: true
          schema:
            type: array
            items: { type: string, enum: [active, accepted, canceled, expired, declined] }
      responses:
        '200':
          description: Offer timeline.
          content:
            application/json:
              schema:
                type: object
                required: [offers]
                properties:
                  offers:
                    type: array
                    items: { $ref: '#/components/schemas/Offer' }
  /me/inventory:
    get:
      tags: [Selling]
      operationId: getInventory
      summary: Get inventory
      description: |
        Returns the authenticated user's CS2 assets with item, float, applied cosmetic, reference-price,
        inspect, and tradability data.
      security: [{ ApiKeyAuth: [] }]
      responses:
        '200':
          description: Inventory assets.
          content:
            application/json:
              schema:
                type: array
                items: { $ref: '#/components/schemas/Item' }
        '401': { $ref: '#/components/responses/Error' }
  /me/trades:
    get:
      tags: [Trades]
      operationId: getTrades
      summary: Get trades
      description: |
        Returns trades for the authenticated buyer or seller. `state` takes a comma-separated list;
        `page` is zero-based.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - name: state
          in: query
          description: Comma-separated trade states.
          schema: { type: string, example: queued,pending }
        - name: role
          in: query
          schema: { type: string, enum: [buyer, seller] }
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Paginated trades.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/TradesPage' }
        '401': { $ref: '#/components/responses/Error' }
  /trades/{trade_id}:
    get:
      tags: [Trades]
      operationId: getTrade
      summary: Get a trade
      description: |
        Returns complete buyer, seller, contract, Steam offer, verification, protection, and settlement
        detail for one trade.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/TradeId'
      responses:
        '200':
          description: Trade detail.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Trade' }
        '404': { $ref: '#/components/responses/Error' }
    delete:
      tags: [Trades]
      operationId: cancelTrade
      summary: Cancel a trade
      description: |
        Cancels a trade as the seller before it settles. Takes no body.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/TradeId'
      responses:
        '200':
          description: |
            Succeeded. The web client discards this body, so its shape is not documented here.
            Treat the status as the result and do not depend on the payload.
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
        '404': { $ref: '#/components/responses/Error' }
  /trades/{trade_id}/accept:
    post:
      tags: [Trades]
      operationId: acceptTrade
      summary: Accept a trade
      description: |
        Accepts one trade as the seller, committing to send the Steam offer. Takes no body; the
        trade must be in a state that is waiting on the seller.

        To accept several trades, prefer `POST /trades/bulk/accept`: it returns the updated trade
        objects, which this operation does not.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/TradeId'
      responses:
        '200':
          description: |
            Succeeded. The web client discards this body, so its shape is not documented here.
            Treat the status as the result and do not depend on the payload.
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
        '404': { $ref: '#/components/responses/Error' }
  /trades/{trade_id}/buyer-details:
    get:
      tags: [Trades]
      operationId: getTradeBuyerDetails
      summary: Get buyer delivery details
      description: |
        Returns the counterparty information the seller needs to send the Steam offer for one trade.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/TradeId'
      responses:
        '200':
          description: Buyer details.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401': { $ref: '#/components/responses/Error' }
        '404': { $ref: '#/components/responses/Error' }
  /trades/bulk/cancel:
    post:
      tags: [Trades]
      operationId: cancelTradesBulk
      summary: Cancel trades in bulk
      description: |
        Cancels several trades in one request. Each trade is evaluated independently.
      security: [{ ApiKeyAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/TradeIdsRequest' }
      responses:
        '200':
          description: Cancelled trades.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/TradePage' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
  /trades/bulk/accept:
    post:
      tags: [Trades]
      operationId: acceptTradesBulk
      summary: Accept trades in bulk
      description: |
        Accepts several trades in one request. Each trade is evaluated independently, so a partial
        failure leaves the remaining trades accepted.
      security: [{ ApiKeyAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/TradeIdsRequest' }
      responses:
        '200':
          description: Accepted trades.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/TradePage' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
  /me/transactions:
    get:
      tags: [Account]
      operationId: getTransactions
      summary: Get transactions
      description: |
        Returns the market balance ledger. Types include `deposit`, `bid_posted`,
        `contract_purchased`, `contract_sold`, refunds, `fine`, `rollback`, and `trade_verified`.
      security: [{ ApiKeyAuth: [] }]
      parameters:
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/Limit'
        - name: order
          in: query
          schema: { type: string, enum: [asc, desc], default: desc }
        - name: type
          in: query
          schema:
            type: string
            enum: [deposit, withdrawal, fine, bid_posted, trade_verified, contract_purchased, contract_sold, contract_purchase_refund, contract_sale_refund, rollback]
      responses:
        '200':
          description: Paginated transaction ledger.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/TransactionsPage' }
  /users/{steam_id}:
    get:
      tags: [Market data]
      operationId: getUser
      summary: Get a user profile
      description: |
        Returns the public profile for one Steam ID: display name, avatar, stall state, and trade
        statistics.
      security: []
      parameters:
        - $ref: '#/components/parameters/SteamId'
      responses:
        '200':
          description: User profile.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/User' }
        '404': { $ref: '#/components/responses/Error' }
  /meta/exchange-rates:
    get:
      tags: [Market data]
      operationId: getExchangeRates
      summary: Get exchange rates
      description: |
        Returns lowercase currency-code multipliers relative to USD, plus stablecoin and internal
        display currencies.

        The 32 currencies the site itself offers are `USD`, `EUR`, `GBP`, `CAD`, `AED`, `AUD`,
        `BRL`, `CHF`, `CNY`, `CZK`, `DKK`, `GEL`, `HKD`, `HUF`, `IDR`, `ILS`, `KHR`, `KZT`, `MYR`,
        `MXN`, `NOK`, `NZD`, `PLN`, `RON`, `RSD`, `SAR`, `SEK`, `SGD`, `THB`, `TRY`, `TWD`, and
        `UAH`. Keys in this response are lowercase.
      security: []
      responses:
        '200':
          description: Currency-code map.
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: object
                    additionalProperties: { type: number }
                example:
                  data: { usd: 1, eur: 0.86, gbp: 0.74 }
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: CSFloat developer API key. Do not prefix with `Bearer`.
  parameters:
    Cursor:
      name: cursor
      in: query
      description: Opaque cursor from the preceding page.
      schema: { type: string }
    Page:
      name: page
      in: query
      description: Zero-based page number.
      schema: { type: integer, minimum: 0, default: 0 }
    Limit:
      name: limit
      in: query
      schema: { type: integer, minimum: 1, default: 50 }
    ListingId:
      name: listing_id
      in: path
      required: true
      schema: { $ref: '#/components/schemas/Id' }
    OfferId:
      name: offer_id
      in: path
      required: true
      schema: { $ref: '#/components/schemas/Id' }
    BuyOrderId:
      name: order_id
      in: path
      required: true
      schema: { $ref: '#/components/schemas/Id' }
    TradeId:
      name: trade_id
      in: path
      required: true
      schema: { $ref: '#/components/schemas/Id' }
    SteamId:
      name: steam_id
      in: path
      required: true
      description: Steam ID64.
      schema: { $ref: '#/components/schemas/Id' }
    MarketHashName:
      name: market_hash_name
      in: path
      required: true
      description: Complete URL-encoded Steam market hash name.
      schema: { type: string, example: AWP | Graphite (Factory New) }
  headers:
    RateLimit:
      description: Request limit for the current route window.
      schema: { type: integer }
    RateLimitRemaining:
      description: Requests remaining in the current route window.
      schema: { type: integer }
    RateLimitReset:
      description: Unix timestamp at which the route window resets.
      schema: { type: integer, format: int64 }
  responses:
    Error:
      description: Application error.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
  schemas:
    Id:
      type: string
      pattern: '^\\d+$'
      description: Numeric identifier serialized as a string.
      example: '1000000000000000000'
    Money:
      type: integer
      format: int64
      minimum: 0
      description: USD cents.
      example: 50000
    Error:
      type: object
      required: [code, message]
      properties:
        code: { type: integer }
        message: { type: string }
      example: { code: 27, message: authorization not set }
    Message:
      type: object
      required: [message]
      properties:
        message: { type: string }
    UserStatistics:
      type: object
      properties:
        median_trade_time: { type: integer, description: Median trade completion time in seconds. }
        total_avoided_trades: { type: integer, minimum: 0 }
        total_failed_trades: { type: integer, minimum: 0 }
        total_trades: { type: integer, minimum: 0 }
        total_verified_trades: { type: integer, minimum: 0 }
    User:
      type: object
      properties:
        steam_id: { $ref: '#/components/schemas/Id' }
        obfuscated_id: { $ref: '#/components/schemas/Id' }
        username: { type: string }
        avatar: { type: string, format: uri }
        flags: { type: integer }
        online: { type: boolean }
        away: { type: boolean }
        stall_public: { type: boolean }
        statistics: { $ref: '#/components/schemas/UserStatistics' }
    ReferencePrice:
      type: object
      properties:
        base_price: { $ref: '#/components/schemas/Money' }
        predicted_price: { $ref: '#/components/schemas/Money' }
        keychain_price: { $ref: '#/components/schemas/Money' }
        float_factor: { type: number }
        quantity: { type: integer, minimum: 0 }
        last_updated: { type: string, format: date-time }
        buy_order:
          type: object
          properties:
            max_price: { $ref: '#/components/schemas/Money' }
            quantity: { type: integer, minimum: 0 }
    AppliedReference:
      type: object
      properties:
        price: { $ref: '#/components/schemas/Money' }
        quantity: { type: integer, minimum: 0 }
        updated_at: { type: string, format: date-time }
    Sticker:
      type: object
      properties:
        stickerId: { type: integer }
        slot: { type: integer, minimum: 0 }
        wear: { type: number, minimum: 0, maximum: 1 }
        name: { type: string }
        icon_url: { type: string }
        offset_x: { type: number }
        offset_y: { type: number }
        reference: { $ref: '#/components/schemas/AppliedReference' }
    Keychain:
      type: object
      properties:
        stickerId: { type: integer }
        slot: { type: integer, minimum: 0 }
        pattern: { type: integer }
        wrapped_sticker: { type: integer }
        name: { type: string }
        icon_url: { type: string }
        offset_x: { type: number }
        offset_y: { type: number }
        offset_z: { type: number }
        reference: { $ref: '#/components/schemas/AppliedReference' }
    Fade:
      type: object
      properties:
        percentage: { type: number }
        rank: { type: integer }
        seed: { type: integer }
        type: { type: string }
    BlueGem:
      type: object
      properties:
        playside_blue: { type: number }
        playside_gold: { type: number }
        playside_purple: { type: number }
        backside_blue: { type: number }
        backside_gold: { type: number }
        backside_purple: { type: number }
    Item:
      type: object
      required: [asset_id, market_hash_name, def_index, paint_index, paint_seed]
      properties:
        asset_id: { $ref: '#/components/schemas/Id' }
        market_hash_name: { type: string }
        item_name: { type: string }
        type: { type: string }
        type_name: { type: string }
        wear_name: { type: string }
        collection: { type: string }
        description: { type: string }
        def_index: { type: integer }
        paint_index: { type: integer }
        paint_seed: { type: integer }
        float_value: { type: number, minimum: 0, maximum: 1 }
        rarity: { type: integer }
        rarity_name: { type: string }
        quality: { type: integer }
        is_stattrak: { type: boolean }
        is_souvenir: { type: boolean }
        is_commodity: { type: boolean }
        tradable: { type: integer, description: Integer tradeability indicator. }
        icon_url: { type: string }
        inspect_link: { type: string }
        d_param: { type: string }
        serialized_inspect: { type: string }
        gs_sig: { type: string }
        cs2_screenshot_id: { type: string }
        cs2_screenshot_at: { type: string, format: date-time }
        phase: { type: string }
        low_rank: { type: integer }
        high_rank: { type: integer }
        sticker_index: { type: integer }
        keychain_index: { type: integer }
        keychain_pattern: { type: integer }
        stickers:
          type: array
          items: { $ref: '#/components/schemas/Sticker' }
        keychains:
          type: array
          items: { $ref: '#/components/schemas/Keychain' }
        badges:
          type: array
          items: { type: string }
        reference: { $ref: '#/components/schemas/ReferencePrice' }
        fade: { $ref: '#/components/schemas/Fade' }
        blue_gem: { $ref: '#/components/schemas/BlueGem' }
      example:
        asset_id: '50000000000'
        market_hash_name: AWP | Graphite (Factory New)
        item_name: AWP | Graphite
        wear_name: Factory New
        def_index: 9
        paint_index: 212
        paint_seed: 317
        float_value: 0.0217
        is_stattrak: false
        is_souvenir: false
        tradable: 1
    AuctionBid:
      type: object
      properties:
        id: { $ref: '#/components/schemas/Id' }
        contract_id: { $ref: '#/components/schemas/Id' }
        obfuscated_buyer_id: { $ref: '#/components/schemas/Id' }
        price: { $ref: '#/components/schemas/Money' }
        state: { type: string }
        created_at: { type: string, format: date-time }
    AuctionDetails:
      type: object
      properties:
        expires_at: { type: string, format: date-time }
        reserve_price: { $ref: '#/components/schemas/Money' }
        min_next_bid: { $ref: '#/components/schemas/Money' }
        top_bid: { $ref: '#/components/schemas/AuctionBid' }
    Listing:
      type: object
      required: [id, created_at, type, price, state, item]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        created_at: { type: string, format: date-time }
        sold_at: { type: string, format: date-time }
        type: { type: string, enum: [buy_now, auction] }
        price: { $ref: '#/components/schemas/Money' }
        state: { type: string, example: listed }
        description: { type: string, maxLength: 180 }
        seller: { $ref: '#/components/schemas/User' }
        item: { $ref: '#/components/schemas/Item' }
        reference: { $ref: '#/components/schemas/ReferencePrice' }
        is_seller: { type: boolean }
        min_offer_price: { $ref: '#/components/schemas/Money' }
        max_offer_discount: { $ref: '#/components/schemas/Money' }
        is_watchlisted: { type: boolean }
        watchers: { type: integer, minimum: 0 }
        auction_details: { $ref: '#/components/schemas/AuctionDetails' }
      example:
        id: '1000000000000000000'
        created_at: '2026-08-18T15:40:05Z'
        type: buy_now
        price: 50000
        state: listed
        item:
          asset_id: '50000000000'
          market_hash_name: AWP | Graphite (Factory New)
          def_index: 9
          paint_index: 212
          paint_seed: 317
          float_value: 0.0217
    ListingPage:
      type: object
      required: [data]
      properties:
        data:
          type: array
          items: { $ref: '#/components/schemas/Listing' }
        cursor:
          type: string
          description: Opaque next-page cursor. Omitted at the end of the collection.
    StallPage:
      allOf:
        - $ref: '#/components/schemas/ListingPage'
        - type: object
          properties:
            total_count: { type: integer, minimum: 0 }
            total_price: { $ref: '#/components/schemas/Money' }
    CreateListingRequest:
      type: object
      required: [asset_id]
      properties:
        asset_id: { $ref: '#/components/schemas/Id' }
        type: { type: string, enum: [buy_now, auction], default: buy_now }
        price: { $ref: '#/components/schemas/Money' }
        max_offer_discount: { $ref: '#/components/schemas/Money' }
        reserve_price: { $ref: '#/components/schemas/Money' }
        duration_days: { type: integer, enum: [1, 3, 5, 7, 14] }
        description: { type: string, maxLength: 180 }
        private: { type: boolean, default: false }
      example:
        asset_id: '50000000000'
        type: buy_now
        price: 50000
        private: false
    UpdateListingRequest:
      type: object
      minProperties: 1
      description: |
        Partial update. The web client sends only the fields that changed, so every property is
        optional; sending an unchanged field is harmless.
      properties:
        price: { $ref: '#/components/schemas/Money' }
        description: { type: string, maxLength: 180 }
        private: { type: boolean }
        max_offer_discount: { $ref: '#/components/schemas/Money' }
        use_default_offer_discount:
          type: boolean
          description: Applies the account's default offer discount instead of `max_offer_discount`.
      example:
        price: 47500
    TradeIdsRequest:
      type: object
      required: [trade_ids]
      properties:
        trade_ids:
          type: array
          minItems: 1
          items: { $ref: '#/components/schemas/Id' }
      example:
        trade_ids: ['1000000000000000000', '1000000000000000001']
    TradePage:
      type: object
      required: [data]
      properties:
        data:
          type: array
          items: { $ref: '#/components/schemas/Trade' }
    ContractIdsRequest:
      type: object
      required: [contract_ids]
      properties:
        contract_ids:
          type: array
          minItems: 1
          items: { $ref: '#/components/schemas/Id' }
      example:
        contract_ids: ['1000000000000000000', '1000000000000000001']
    ListingPageWrapped:
      type: object
      required: [data]
      properties:
        data:
          type: array
          items: { $ref: '#/components/schemas/Listing' }
    BuyListingsRequest:
      type: object
      required: [total_price, contract_ids]
      properties:
        total_price:
          $ref: '#/components/schemas/Money'
        contract_ids:
          type: array
          minItems: 1
          items: { $ref: '#/components/schemas/Id' }
      example:
        total_price: 34500
        contract_ids: ['1000000000000000000', '1000000000000000001']
    BulkCreateListingsRequest:
      type: object
      required: [items]
      properties:
        items:
          type: array
          minItems: 1
          items: { $ref: '#/components/schemas/CreateListingRequest' }
        notary_payload:
          type: string
          description: Signed inventory attestation, sent once for the whole batch.
      example:
        items:
          - asset_id: '50000000000'
            type: buy_now
            price: 50000
          - asset_id: '50000000001'
            type: buy_now
            price: 62000
    BulkModifyListingsRequest:
      type: object
      required: [modifications]
      properties:
        modifications:
          type: array
          minItems: 1
          description: |
            One entry per listing. Each carries `contract_id` — not `id` — plus the fields to
            change, which are the same ones `PATCH /listings/{listing_id}` accepts.
          items:
            allOf:
              - type: object
                required: [contract_id]
                properties:
                  contract_id: { $ref: '#/components/schemas/Id' }
              - $ref: '#/components/schemas/UpdateListingRequest'
      example:
        modifications:
          - contract_id: '1000000000000000000'
            price: 47500
          - contract_id: '1000000000000000001'
            price: 58000
    UpdateBuyOrderRequest:
      type: object
      description: |
        Updates price, quantity, and item constraints on an open order.

        Constraints are sent flat here, not nested under `hybrid_properties` as on creation, and
        they are absolute rather than a patch: the client sends every constraint field on every
        update, using `null` to clear one. A field left out is not preserved.
      properties:
        max_price: { $ref: '#/components/schemas/Money' }
        quantity: { type: integer, minimum: 1 }
        min_float: { type: [number, 'null'], minimum: 0, maximum: 1 }
        max_float: { type: [number, 'null'], minimum: 0, maximum: 1 }
        paint_seeds:
          type: [array, 'null']
          items: { type: integer }
        min_keychain_pattern: { type: [integer, 'null'] }
        max_keychain_pattern: { type: [integer, 'null'] }
        applied_stickers:
          type: [array, 'null']
          items: { $ref: '#/components/schemas/AppliedConstraint' }
        applied_keychains:
          type: [array, 'null']
          items: { $ref: '#/components/schemas/AppliedConstraint' }
      example:
        max_price: 21000
        quantity: 3
        min_float: null
        max_float: 0.03
        paint_seeds: [317]
        min_keychain_pattern: null
        max_keychain_pattern: null
        applied_stickers: null
        applied_keychains: null
    Bid:
      type: object
      required: [id, contract_id, price]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        contract_id: { $ref: '#/components/schemas/Id' }
        price: { $ref: '#/components/schemas/Money' }
        state: { type: string, description: 'Observed value: `active`.' }
        obfuscated_buyer_id:
          type: string
          description: Publicly safe buyer identifier. Bidders are not named.
        created_at: { type: string, format: date-time }
      example:
        id: '1000000000000000000'
        contract_id: '1000000000000000001'
        price: 17900
        state: active
        obfuscated_buyer_id: '16000000000000000000'
    HistoryPoint:
      type: object
      required: [day, avg_price, count]
      properties:
        day: { type: string, format: date }
        avg_price: { $ref: '#/components/schemas/Money' }
        count: { type: integer, minimum: 0, description: Number of sales. }
      example: { day: '2026-08-17', avg_price: 48250, count: 14 }
    ItemSchema:
      type: object
      required: [weapons, stickers, keychains, collections, rarities]
      properties:
        weapons: { type: object, additionalProperties: true }
        stickers: { type: object, additionalProperties: true }
        keychains: { type: object, additionalProperties: true }
        collections: { type: object, additionalProperties: true }
        containers: { type: object, additionalProperties: true }
        agents: { type: object, additionalProperties: true }
        collectibles: { type: object, additionalProperties: true }
        music_kits: { type: object, additionalProperties: true }
        rarities: { type: object, additionalProperties: true }
        custom_stickers: { type: object, additionalProperties: true }
        highlight_reels: { type: object, additionalProperties: true }
      additionalProperties: true
    AppliedConstraint:
      type: object
      required: [sId]
      properties:
        sId: { type: integer, description: Sticker or keychain definition ID. }
    HybridProperties:
      type: object
      properties:
        min_float: { type: number, minimum: 0, maximum: 1 }
        max_float: { type: number, minimum: 0, maximum: 1 }
        paint_index: { type: integer }
        paint_seeds:
          type: array
          items: { type: integer }
        applied_stickers:
          type: array
          items: { $ref: '#/components/schemas/AppliedConstraint' }
        applied_keychains:
          type: array
          items: { $ref: '#/components/schemas/AppliedConstraint' }
        min_keychain_pattern: { type: integer }
        max_keychain_pattern: { type: integer }
      additionalProperties: false
    CreateBuyOrderRequest:
      type: object
      required: [market_hash_name, max_price, quantity]
      properties:
        market_hash_name: { type: string }
        max_price: { $ref: '#/components/schemas/Money' }
        quantity: { type: integer, minimum: 1 }
        hybrid_properties: { $ref: '#/components/schemas/HybridProperties' }
      example:
        market_hash_name: AWP | Graphite (Factory New)
        max_price: 50000
        quantity: 1
        hybrid_properties:
          max_float: 0.03
          paint_seeds: [317]
          applied_stickers: [{ sId: 37 }]
    SimilarBuyOrdersRequest:
      type: object
      required: [market_hash_name, hybrid_properties]
      properties:
        market_hash_name: { type: string }
        hybrid_properties: { $ref: '#/components/schemas/HybridProperties' }
    BuyOrder:
      type: object
      required: [id, created_at, market_hash_name, price, qty]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        created_at: { type: string, format: date-time }
        market_hash_name: { type: string }
        price: { $ref: '#/components/schemas/Money' }
        qty: { type: integer, minimum: 0 }
        bought_item_count: { type: integer, minimum: 0 }
        hybrid_properties: { $ref: '#/components/schemas/HybridProperties' }
    BuyOrderAggregate:
      type: object
      required: [market_hash_name, price, qty, hybrid_properties]
      properties:
        market_hash_name: { type: string }
        price: { $ref: '#/components/schemas/Money' }
        qty: { type: integer, minimum: 0 }
        hybrid_properties: { $ref: '#/components/schemas/HybridProperties' }
    CreateOfferRequest:
      type: object
      required: [contract_id, price, cancel_previous_offer]
      properties:
        contract_id: { $ref: '#/components/schemas/Id' }
        price: { $ref: '#/components/schemas/Money' }
        cancel_previous_offer: { type: boolean, default: false }
        message_id: { $ref: '#/components/schemas/Id' }
      example:
        contract_id: '1000000000000000000'
        price: 45000
        cancel_previous_offer: false
    OfferHistoryEntry:
      type: object
      required: [id, created_at, expires_at, contract_id, contract_price, buyer_id, price, type, state]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        created_at: { type: string, format: date-time }
        expires_at: { type: string, format: date-time }
        contract_id: { $ref: '#/components/schemas/Id' }
        contract_price: { $ref: '#/components/schemas/Money' }
        buyer_id: { $ref: '#/components/schemas/Id' }
        price: { $ref: '#/components/schemas/Money' }
        type: { type: string }
        state: { type: string }
        message_id: { $ref: '#/components/schemas/Id' }
    Offer:
      allOf:
        - $ref: '#/components/schemas/OfferHistoryEntry'
        - type: object
          properties:
            buyer: { $ref: '#/components/schemas/User' }
            contract: { $ref: '#/components/schemas/Listing' }
    OffersPage:
      type: object
      required: [offers, count]
      properties:
        offers:
          type: array
          items: { $ref: '#/components/schemas/Offer' }
        count: { type: integer, minimum: 0 }
    SteamOffer:
      type: object
      required: [id, state, is_from_seller]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        state: { type: integer }
        is_from_seller: { type: boolean }
        sent_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        deadline_at: { type: string, format: date-time }
        can_cancel_at: { type: string, format: date-time }
    Trade:
      type: object
      required: [id, created_at, buyer_id, seller_id, contract_id, state]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        created_at: { type: string, format: date-time }
        accepted_at: { type: string, format: date-time }
        verified_at: { type: string, format: date-time }
        expires_at: { type: string, format: date-time }
        buyer_id: { $ref: '#/components/schemas/Id' }
        seller_id: { $ref: '#/components/schemas/Id' }
        contract_id: { $ref: '#/components/schemas/Id' }
        buyer: { $ref: '#/components/schemas/User' }
        seller: { $ref: '#/components/schemas/User' }
        contract: { $ref: '#/components/schemas/Listing' }
        state: { type: string, example: pending }
        verification_mode: { type: string, example: escrow }
        trade_token: { type: string, writeOnly: true }
        trade_url: { type: string, format: uri, writeOnly: true }
        steam_offer: { $ref: '#/components/schemas/SteamOffer' }
        inventory_check_status: { type: integer }
        verify_sale_at: { type: string, format: date-time }
        trade_protection_ends_at: { type: string, format: date-time }
        wait_for_cancel_ping: { type: boolean }
        is_settlement_period: { type: boolean }
        seller_blocked_buyer_at: { type: string, format: date-time }
        sent_to_different_user_id: { $ref: '#/components/schemas/Id' }
    TradesPage:
      type: object
      required: [trades, count]
      properties:
        trades:
          type: array
          items: { $ref: '#/components/schemas/Trade' }
        count: { type: integer, minimum: 0 }
    TransactionDetails:
      type: object
      description: Type-specific ledger metadata. Fields are present only for relevant transaction types.
      properties:
        bid_id: { $ref: '#/components/schemas/Id' }
        listing_id: { $ref: '#/components/schemas/Id' }
        contract_id: { $ref: '#/components/schemas/Id' }
        trade_id: { $ref: '#/components/schemas/Id' }
        original_tx: { $ref: '#/components/schemas/Id' }
        session_id: { type: string }
        type: { type: string }
        reason: { type: string }
        grantor: { type: string }
        fee_amount: { $ref: '#/components/schemas/Money' }
        fee: { type: string, description: Decimal fee string. }
        exchange_rate: { type: string, description: Decimal exchange-rate string. }
        payment_method: { type: string }
        payment_processor: { type: string }
    Transaction:
      type: object
      required: [id, created_at, user_id, type, details, balance_offset, pending_offset]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        created_at: { type: string, format: date-time }
        user_id: { $ref: '#/components/schemas/Id' }
        type:
          type: string
          enum: [deposit, withdrawal, bid_posted, contract_purchased, contract_sold, contract_purchase_refund, contract_sale_refund, fine, rollback, trade_verified]
        details: { $ref: '#/components/schemas/TransactionDetails' }
        balance_offset:
          type: integer
          format: int64
          description: Signed settled-balance change in cents.
        pending_offset:
          type: integer
          format: int64
          description: Signed pending-balance change in cents.
    TransactionsPage:
      type: object
      required: [transactions, count]
      properties:
        transactions:
          type: array
          items: { $ref: '#/components/schemas/Transaction' }
        count: { type: integer, minimum: 0 }
