Skip to content

Create Deposit by Hash Name

POST /api/v1/merchant/create-deposit-by-hash-name

Commits a deposit using a previously quoted trade ID from Get Prices. Unlike Create Deposit, this endpoint identifies items by market hash name plus the user's Steam asset_id — no inventory pre-fetch required.

This is step 2 of the hash-name integration flow.

Request

Headers

HeaderRequiredDescription
X-Api-KeyYour merchant API key
Content-Typeapplication/json

Body

ParameterTypeRequiredDescription
idintegerTrade ID returned by get-prices. Min 1
merchant_tx_idstringYour unique transaction/order ID. Overwrites the temporary ID assigned at get-prices
gamestringGame code: csgo, rust, dota2, tf2
partnerintegerSteam trade partner ID
tokenstringSteam trade token (exactly 8 characters)
itemsobject[]Items to deposit (min 1)
items[].asset_idstringSteam asset ID (numeric string — required in practice; validated as numeric)
items[].namestringMarket hash name — must match a name quoted in get-prices
items[].min_pricenumberMinimum acceptable price (USD). If the current price drops below this, the request fails. Values ≤ 0 are ignored
result_urlstringWebhook URL — overrides your merchant-level webhook URL for this deposit (must be valid URL)
success_urlstringSuccess redirect URL (must be valid URL)
fail_urlstringFailure redirect URL (must be valid URL)

Response

json
{
  "success": true,
  "message": "Deposit processing with selected items",
  "data": {
    "id": 742,
    "merchant_tx_id": "order-9999",
    "status": "active",
    "amount": 45.50,
    "bot_name": "Skinslink Bot #3",
    "bot_steam_id": 76561199012345678,
    "trade_offer_id": "6912345678",
    "trade_offer_expiry_at": "2026-05-01T14:30:00Z"
  }
}

On provider failure, the response returns HTTP 200 with status: "failed" and a fail_reason:

json
{
  "success": true,
  "message": "Deposit processing with selected items",
  "data": {
    "id": 742,
    "merchant_tx_id": "order-9999",
    "status": "failed",
    "amount": 45.50,
    "bot_name": null,
    "bot_steam_id": null,
    "trade_offer_id": null,
    "trade_offer_expiry_at": null,
    "fail_reason": "provider_unavailable"
  }
}

Response Fields

FieldTypeDescription
idintegerInternal trade ID (same as request)
merchant_tx_idstringYour transaction ID (echoed back)
statusstringTrade status — active on success, failed on error
amountnumberTotal deposit amount (USD)
bot_namestring | nullName of the Steam bot sending the offer
bot_steam_idinteger | nullSteam ID of the bot
trade_offer_idstring | nullSteam trade offer ID
trade_offer_expiry_atstring | nullISO 8601 timestamp when the offer expires
fail_reasonstring | nullPresent when status is failed. See Fail Reasons below

INFO

Custom currency fields (custom_currency, custom_currency_multiplier, custom_currency_rate, custom_currency_sum) are not included in this response. Use Deposit Status once the trade reaches hold or completed status.

Processing Steps

  1. Validates the Steam trade key (partner + token).
  2. Loads the trade by id, verifies it belongs to your merchant and is in status new.
  3. Locks merchant_tx_id — written along with game/partner/token/URLs in a DB transaction; the trade transitions to pending. Duplicate merchant_tx_id values are rejected here.
  4. Checks the 5-minute price window — if the original get-prices call was more than 5 minutes ago, the request fails with inventory_reload and you must call get-prices again.
  5. Recalculates resale margin using the inventory data cached at get-prices time.
  6. Per-item min_price check — if any item's current price is below the supplied min_price, the request fails with item_specified_price_not_found.
  7. Inserts trade items into the DB.
  8. Dispatches to provider (10-second timeout, detached from the client connection).
  9. On provider failure → trade set to failed, fail_reason: provider_unavailable.
  10. On success → trade set to active and the response is returned.

5-minute price expiry

Prices quoted by get-prices expire after 5 minutes. After that, you must call get-prices again to obtain a fresh id.

min_price

min_price protects you from price drift inside the 5-minute window. Set it slightly below the price you displayed to the user (e.g. quoted price minus 1–2%). If you don't supply min_price, the deposit will go through at whatever the current price is.

Example

bash
curl -X POST https://api.skinslink.com/api/v1/merchant/create-deposit-by-hash-name \
  -H "X-Api-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "id": 742,
    "merchant_tx_id": "order-9999",
    "game": "csgo",
    "partner": 123456789,
    "token": "AbCdEfGh",
    "items": [
      {
        "asset_id": "38029384123",
        "name": "AK-47 | Redline (Field-Tested)",
        "min_price": 20.00
      }
    ]
  }'

After Creating a Deposit

  1. Show the trade offer info to the user (bot name, offer ID).
  2. User accepts the trade offer in Steam.
  3. Listen for webhooks or poll Deposit Status for updates.

TIP

Store trade_offer_expiry_at and remind users to accept before expiry. Expired offers are automatically canceled.

Errors

StatusMessageCause
400invalid request bodyMalformed JSON
400validation errorMissing or invalid fields (see data array). Includes inventory_reload (price quote expired) and item_specified_price_not_found (item below min_price)
401missing authorization headerX-Api-Key header not provided
401invalid API keyAPI key not found or inactive
403merchant account is disabledMerchant account deactivated
403IP not whitelisted: <ip>Request IP not in merchant's allowed list
400validation errorTrade id is not in new status — already activated or expired. Check data[].code for status: denied
404not found errorTrade id not found or does not belong to this merchant
409already exist errorDuplicate merchant_tx_id
500internal errorSomething went wrong on our side

Fail Reasons

Some failures return HTTP 200 with status: "failed" in the response body; others return an HTTP error directly. All are persisted on the trade and visible via Deposit Status.

In-band (HTTP 200, status: "failed"):

Fail ReasonMeaning
provider_unavailableProvider rejected the trade, timed out (10s), or an internal error occurred before dispatch (e.g. DB failure saving trade items)

Out-of-band (HTTP 400 error response):

These are returned immediately in the HTTP 400 response body. The trade is also persisted with the corresponding fail_reason, so it is additionally visible via Deposit Status.

Fail ReasonHTTP body formatMeaning
inventory_reloadvalidation error with data[{field: "inventory", code: "inventory_reload"}]Price quote expired (> 5 minutes since get-prices), or no provider was selected
item_specified_price_not_foundmessage: "item_specified_price_not_found"An item's current price dropped below its min_price

→ For domain-specific validation codes, see Errors.