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

# List trades

> **Auth context:** merchant only. Cursor-paginated.

Returns your sub-users' trades, **buy and sell** (as of v0.4.x — previously
buy-only). Filters: `type` (`buy`/`sell`), `status`, `subUserId` (UUID or
externalId), `itemName`, `externalId` (your trade externalId), `offerId`,
`tradeId`, `from`, `to`.




## OpenAPI

````yaml /openapi.yaml get /merchant/trades
openapi: 3.1.0
info:
  title: SkinShark Merchant API
  description: >
    REST + WebSocket surface that you call **server-to-server** with your API
    key.

    Use it to manage sub-users, query wallets and trades, and act on behalf of
    any

    of your sub-users from a single key.


    ## Authentication


    Send your API key on every request:


    ```

    api-key: <your-key>

    ```


    Keys are hashed at rest and may be restricted to specific source IPs.
    Requests

    from a non-allowlisted IP are rejected with `API_KEY_IP_DENIED`.


    ### Acting on behalf of a sub-user


    For routes **outside** `/merchant/...`, add a header to scope the call to a

    specific sub-user:


    ```

    On-Behalf-Of: <subUserId | externalId>

    ```


    Both the UUID and the `externalId` you assigned are accepted; the server

    resolves either, scoped to your merchant. A UUID that belongs to a different

    merchant returns `USER_NOT_FOUND`.


    Without `On-Behalf-Of`, calls run **as your merchant account itself**. For

    example, `POST /market/buy` without the header buys for the merchant — its

    own spot wallet, its own Steam trade URL.


    ### Route groups


    | Prefix | What it does | `On-Behalf-Of` |

    |---|---|---|

    | `/merchant/...` | Merchant-level reads/writes (sub-users, trades
    aggregation, wallet, profile, fees). | Rejected — sub-users do not hold the
    merchant role. |

    | Everything else (`/user/...`, `/market/...`, `/auth/ws-token`) |
    User-scope operations. | Accepted — call runs as the targeted sub-user. |


    Each operation states the required context under **Auth context**.


    ## Dashboard-only operations


    A few account-management operations are not exposed to API key auth — they

    require signing in to the merchant dashboard:


    - Creating, rotating, and revoking API keys

    - Configuring webhook endpoints, secrets, and inspecting deliveries

    - Adjusting merchant fees

    - Account settings (password, email, 2FA, account deletion)

    - Audit logs and CSV exports


    Everything else in this document is available via API key.


    ## Response envelope


    Every JSON response is wrapped. Successful responses:


    ```json

    {
      "requestId": "req-...",
      "success": true,
      "data": { }
    }

    ```


    Error responses:


    ```json

    {
      "requestId": "req-...",
      "success": false,
      "error": {
        "code": 1500,
        "key": "INSUFFICIENT_BALANCE",
        "message": "Insufficient balance"
      }
    }

    ```


    Schemas below describe only the inner `data` shape — the envelope is
    implicit.


    ## Money format


    - Fields suffixed `Cents` are integer cents as JSON numbers
      (`15000` = $150.00).
    - Decimal-currency fields like `balance`, `totalPrice`, `gmv` are JSON
    numbers
      in the wallet currency (`5.23` = $5.23 in a USD wallet).
    - Amount **inputs** (e.g. `fund`, deposit `amount`) accept decimal strings
      (`"5.50"`) to avoid floating-point loss on the wire.

    ## Pagination


    Two styles are used, documented per endpoint:


    - **Page-based** — `?page=1&limit=25`. Response contains
      `{ items|users, total, page, limit, totalPages }`.
    - **Cursor-based** — `?cursor=<id>&limit=25`. Response contains
      `{ items|trades|transactions, nextCursor }`. `nextCursor` is `null` on the
      last page.

    ## Idempotency


    `POST /merchant/users/{id}/fund` requires an `Idempotency-Key` header.
    Replays

    with the same key return `idempotent: true` alongside the original

    transaction id, so retries are safe.


    ## Sub-user identifiers


    Anywhere a sub-user is referenced — the `On-Behalf-Of` header, `{id}` path

    params under `/merchant/users/...`, the `subUserId` filter on trade lists —

    the value can be **either**:


    - the sub-user's UUID, or

    - the `externalId` you assigned.


    The server resolves both, scoped to your merchant.
  version: 0.4.3
  contact:
    name: SkinShark Engineering
    email: support@skinshark.gg
  license:
    name: Proprietary
    url: https://skinshark.gg/terms
servers:
  - url: https://api.skinshark.gg
    description: Production
  - url: https://api-staging.skinshark.gg
    description: Staging
security:
  - apiKeyAuth: []
tags:
  - name: Account
    description: Merchant identity, fees, stats, wallet, ledger. Merchant context only.
  - name: Users
    description: >-
      Sub-user CRUD plus per-user wallet, ledger, trades, and funding. Merchant
      context only.
  - name: Trades
    description: Aggregate trade list across all sub-users. Merchant context only.
  - name: Profile
    description: >-
      Read the actor's profile (Steam link, Discord link, wallet snapshot).
      Merchant or sub-user context.
  - name: Trade URLs
    description: Manage Steam trade URLs for the actor. Merchant or sub-user context.
  - name: Wallet
    description: Actor's spot balance and ledger. Merchant or sub-user context.
  - name: Deposits
    description: >-
      Fund the actor's wallet via Gate Pay, on-ramp (card), or self-hosted EVM
      crypto. Merchant or sub-user context.
  - name: Partner Payout Custody
    description: >
      Separate per-merchant USD-denominated crypto custody (USDT/USDC at MVP).
      Funds deposited here

      are **not** spendable in the spot/skin-buying pipeline; they're
      withdrawable on-chain to any

      partner-supplied destination. All withdrawals require a synchronous
      approval callback to the

      merchant's registered `CallbackUrl` and a partner-supplied `externalId`
      for idempotency.

      Toggleable per merchant (`cryptoPayoutEnabled`).
  - name: Market
    description: >-
      Catalog search, listings, buy / quick-buy, and the actor's own trades.
      Merchant or sub-user context.
  - name: WebSocket
    description: >-
      Real-time trade and deposit events for a single sub-user
      (consumer-facing). Sub-user context only.
paths:
  /merchant/trades:
    get:
      tags:
        - Trades
      summary: List trades
      description: >
        **Auth context:** merchant only. Cursor-paginated.


        Returns your sub-users' trades, **buy and sell** (as of v0.4.x —
        previously

        buy-only). Filters: `type` (`buy`/`sell`), `status`, `subUserId` (UUID
        or

        externalId), `itemName`, `externalId` (your trade externalId),
        `offerId`,

        `tradeId`, `from`, `to`.
      operationId: listMerchantTrades
      parameters:
        - name: type
          in: query
          schema:
            $ref: '#/components/schemas/TradeType'
        - name: status
          in: query
          schema:
            $ref: '#/components/schemas/TradeStatus'
        - name: hideResolved
          in: query
          schema:
            type: boolean
          description: >-
            Excludes failed + reverted (auto-refunded) trades. Ignored when
            status is set.
        - name: subUserId
          in: query
          schema:
            type: string
            minLength: 1
            maxLength: 128
        - name: itemName
          in: query
          schema:
            type: string
            minLength: 1
            maxLength: 128
        - name: externalId
          in: query
          schema:
            type: string
            minLength: 1
            maxLength: 128
        - name: offerId
          in: query
          schema:
            type: string
            minLength: 1
            maxLength: 128
        - name: tradeId
          in: query
          schema:
            type: string
            minLength: 1
            maxLength: 128
        - name: from
          in: query
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          schema:
            type: string
            format: date-time
        - name: cursor
          in: query
          schema:
            type: string
            format: uuid
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
      responses:
        '200':
          description: OK.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/MerchantTradeListResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
components:
  schemas:
    TradeType:
      type: string
      enum:
        - buy
        - sell
      description: >-
        `buy` = purchased from a marketplace; `sell` = sold to a SkinShark bot
        for a payout.
    TradeStatus:
      type: string
      enum:
        - initiated
        - pending
        - active
        - hold
        - completed
        - failed
        - canceled
        - declined
        - reverted
      description: >
        Terminal outcomes — `completed` (delivered), `failed` (couldn't be
        placed/delivered; see item `error`),

        `canceled` (canceled before delivery — full refund, no penalty),
        `declined` (buyer-fault decline after the

        Steam offer was sent — refund minus a 2% penalty), `reverted` (delivered
        then recalled by the supplier).
    Envelope:
      type: object
      required:
        - requestId
        - success
      properties:
        requestId:
          type: string
        success:
          type: boolean
        data:
          description: 'Present when `success: true`. Shape varies per endpoint.'
        error:
          $ref: '#/components/schemas/Error'
    MerchantTradeListResponse:
      type: object
      description: >-
        Merchant-scope trade list (`/merchant/trades`,
        `/merchant/users/:id/trades`).
      required:
        - items
        - nextCursor
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Trade'
        nextCursor:
          type:
            - string
            - 'null'
    Error:
      type: object
      required:
        - code
        - key
        - message
      properties:
        code:
          type: integer
          example: 1500
        key:
          type: string
          example: INSUFFICIENT_BALANCE
        message:
          type: string
          example: Insufficient balance
      additionalProperties: true
    Trade:
      type: object
      required:
        - id
        - type
        - userId
        - steamId
        - tradeUrl
        - status
        - game
        - items
        - summary
        - totalPrice
        - currency
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          format: uuid
        type:
          type: string
          enum:
            - buy
            - sell
        userId:
          type: string
        steamId:
          type: string
        tradeUrl:
          type: string
        offerId:
          type: string
        externalId:
          type: string
        status:
          $ref: '#/components/schemas/TradeStatus'
        game:
          type: string
          example: '730'
        items:
          type: array
          items:
            $ref: '#/components/schemas/TradeItem'
        summary:
          type: object
          required:
            - total
            - delivered
            - completed
            - failed
          properties:
            total:
              type: number
            delivered:
              type: number
              description: >-
                Items delivered to the buyer: hold (in the trade-hold window) +
                completed.
            completed:
              type: number
              description: Items whose hold has passed and settled.
            failed:
              type: number
        totalPrice:
          type: number
        currency:
          $ref: '#/components/schemas/Currency'
        holdEndDate:
          type: string
          format: date-time
        settledAt:
          type: string
          format: date-time
        revertedBy:
          type: string
          enum:
            - supplier
            - user
        error:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    TradeItem:
      type: object
      required:
        - id
        - name
        - marketHashName
        - type
        - iconUrl
        - price
      properties:
        id:
          type: string
          description: >-
            Stable handle for this item, for its whole life. Pass it as `itemId`
            when cancelling.
        externalId:
          type: string
          description: >-
            Your own reference for this item, echoed back when you supplied one
            at buy time. Also accepted as `itemId` when cancelling.
        name:
          type:
            - string
            - 'null'
        marketHashName:
          type:
            - string
            - 'null'
        type:
          type:
            - string
            - 'null'
        iconUrl:
          type:
            - string
            - 'null'
        price:
          type: number
        exterior:
          type: string
        rarity:
          type: string
        color:
          type: string
        phase:
          type: string
        wear:
          type: string
        paintSeed:
          type: number
        stickers:
          type: array
          items:
            type: object
            required:
              - name
              - slot
              - iconUrl
            properties:
              name:
                type: string
              slot:
                type: number
              wear:
                type: number
              iconUrl:
                type: string
        charm:
          type: object
          required:
            - name
            - iconUrl
          properties:
            name:
              type: string
            pattern:
              type: string
            iconUrl:
              type: string
        delivery:
          type: string
        status:
          $ref: '#/components/schemas/TradeStatus'
        tradable:
          type: boolean
        error:
          type: string
          enum:
            - LISTING_UNAVAILABLE
            - NO_LISTING_AT_PRICE
            - PRICE_CHANGED
            - TRADE_URL_INVALID
            - STEAM_ACCOUNT_RESTRICTED
            - BUYER_TRADE_RESTRICTED
            - MARKET_UNAVAILABLE
            - PURCHASE_FAILED
          description: >
            Set when the item `status` is `failed`. Stable partner-facing code:

            `LISTING_UNAVAILABLE` (the listing sold/was delisted — retry another
            listing),

            `NO_LISTING_AT_PRICE` (nothing on sale at or below your max —
            re-quote higher or wait for restock),

            `PRICE_CHANGED` (price moved above your max), `TRADE_URL_INVALID`
            (buyer's Steam trade URL is invalid),

            `STEAM_ACCOUNT_RESTRICTED` (buyer's Steam account can't trade),

            `BUYER_TRADE_RESTRICTED` (the marketplace suspended this buyer, e.g.
            for repeated trade-offer no-shows,

            usually until a stated time — retrying sooner cannot succeed),
            `MARKET_UNAVAILABLE` (temporary upstream/our-side

            issue — retry later), `PURCHASE_FAILED` (unexpected).
            `canceled`/`declined` items carry no code; the status is the
            outcome.
        errorDetail:
          type: string
          description: >-
            Raw marketplace reason for debugging (e.g. "c5:ITEM_SOLD item
            already sold"). Not stable — do not branch on it.
        refund:
          type: object
          description: >
            Present only on refunded items (status
            `failed`/`canceled`/`declined`/`reverted`), carried on every

            trade snapshot and webhook. `amount + penalty == price`. On a
            buyer-fault `declined` a 2% penalty is

            withheld; otherwise `penalty` is 0 and `amount` equals `price`. Buy
            trades only — sell items never carry it.
          required:
            - amount
            - penalty
            - buyerFault
          properties:
            amount:
              type: number
              description: Returned to the buyer.
            penalty:
              type: number
              description: Withheld on buyer fault, else 0.
            buyerFault:
              type: boolean
              description: True when the item was declined as the buyer's fault.
    Currency:
      type: string
      enum:
        - USD
        - EUR
  responses:
    Unauthorized:
      description: >
        Missing/invalid credentials. `key` is one of `UNAUTHORIZED`,
        `MISSING_API_KEY`,

        `INVALID_API_KEY`, `API_KEY_REVOKED`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Envelope'
    Forbidden:
      description: |
        Authenticated but not authorized. `key` is one of `FORBIDDEN`,
        `ACCOUNT_SUSPENDED`, `ACCOUNT_DELETED`, `API_KEY_IP_DENIED`,
        `USER_NOT_OWNED`, `EMAIL_NOT_VERIFIED`. `requireMerchant` routes
        return `FORBIDDEN` when `On-Behalf-Of` is set (sub-user lacks the
        merchant role).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Envelope'
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: api-key
      description: |
        Your raw API key. Generate, rotate, and revoke keys from the merchant
        dashboard. Keys can optionally be bound to one or more allowed source
        IPs — requests from any other IP are rejected with `API_KEY_IP_DENIED`.

````