Appearance
Create Deposit
POST /api/v1/merchant/create-deposit
Creates a deposit with specific Steam items. Used in the API-only integration flow after fetching inventory.
Request
Headers
| Header | Required | Description |
|---|---|---|
X-Api-Key | ✅ | Your merchant API key |
Content-Type | ✅ | application/json |
Body
| Parameter | Type | Required | Description |
|---|---|---|---|
merchant_tx_id | string | ✅ | Your unique transaction/order ID |
game | string | ✅ | Game code: csgo, rust, dota2, tf2 |
partner | integer | ✅ | Steam trade partner ID |
token | string | ✅ | Steam trade token |
asset_ids | string[] | ✅ | Item IDs from the inventory response |
result_url | string | — | Webhook URL — overrides your merchant-level webhook URL for this deposit (must be valid URL) |
success_url | string | — | Success redirect URL (must be valid URL) |
fail_url | string | — | Failure redirect URL (must be valid URL) |
custom_currency | string | — | Custom currency code (1–4 chars, e.g. BTC, EUR). Requires all 3 currency fields |
custom_currency_multiplier | number | — | Currency multiplier (0.5–2.0) |
custom_currency_rate | number | — | Currency exchange rate (≥ 0.1) |
min_prices | object | — | Per-item price floor in USD, keyed by asset_id (e.g. {"38029384123": 19.50}). If an item's price at deposit time is below its floor, the deposit is rejected with item_specified_price_not_found and no trade is created. Entries ≤ 0 are ignored |
Pricing & Price Lock
The deposit amount is derived from the inventory snapshot of your most recent Get Inventory call for the same Steam account (partner + token). That snapshot is cached for 5 minutes.
- If you call
create-depositmore than 5 minutes after fetching the inventory, the request fails withinventory_reload— re-fetch the inventory and retry. - Without
min_prices, the creditedamountis the price cached at deposit time, not the moment you displayed it to the user.
Protect against price drift with min_prices
Pass the optional min_prices map (keyed by asset_id, in USD) to set a per-item floor. If any item's price at deposit time is below its floor, the deposit is rejected with item_specified_price_not_found and no trade is created — so you are never credited less than you displayed. Set each floor slightly below the price you showed the user (e.g. quoted minus 1–2%). Prices are USD regardless of any custom_currency fields.
Alternative: hash-name flow
Get Prices → Create Deposit by Hash Name offers the same per-item min_price protection plus a per-transaction quote snapshot (by id), so the quote cannot be overwritten by a concurrent inventory fetch.
Response
json
{
"success": true,
"message": "Deposit processing with selected items",
"data": {
"id": 42,
"merchant_tx_id": "order-12345",
"status": "active",
"amount": 36.25,
"bot_name": "Skinslink Bot #3",
"bot_steam_id": 76561199012345678,
"trade_offer_id": "6912345678",
"trade_offer_expiry_at": "2026-02-16T12:30:00Z",
"success_url": "https://yoursite.com/deposit/success",
"fail_url": "https://yoursite.com/deposit/failed"
}
}Response Fields
| Field | Type | Description |
|---|---|---|
id | integer | Internal trade ID |
merchant_tx_id | string | Your transaction ID (echoed back) |
status | string | Trade status (active on success, failed on error) |
amount | number | Total deposit amount (USD) |
bot_name | string | null | Name of the Steam bot sending the offer |
bot_steam_id | integer | null | Steam ID of the bot |
trade_offer_id | string | null | Steam trade offer ID |
trade_offer_expiry_at | string | null | ISO 8601 timestamp when the offer expires |
success_url | string | Success redirect URL (only present if provided in request) |
fail_url | string | Failure redirect URL (only present if provided in request) |
INFO
Custom currency fields (custom_currency, custom_currency_multiplier, custom_currency_rate, custom_currency_sum) are not included in the create-deposit response. Use Deposit Status to retrieve them once the trade reaches hold or completed status.
Example
bash
curl -X POST https://api.skinslink.com/api/v1/merchant/create-deposit \
-H "X-Api-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"merchant_tx_id": "order-12345",
"game": "csgo",
"partner": 123456789,
"token": "AbCdEfGh",
"asset_ids": ["38029384123", "38029384124"]
}'To add a per-item price floor, include min_prices in the request body:
json
{
"merchant_tx_id": "order-12346",
"game": "csgo",
"partner": 123456789,
"token": "AbCdEfGh",
"asset_ids": ["38029384123", "38029384124"],
"min_prices": {
"38029384123": 19.50,
"38029384124": 4.20
}
}After Creating a Deposit
- Show the trade offer info to the user (bot name, offer ID)
- User accepts the trade offer in Steam
- Listen for webhooks or poll
/merchant/deposit/statusfor updates
TIP
Store the trade_offer_expiry_at and remind users to accept before expiry. Expired offers are automatically canceled.
Errors
| Status | Message | Cause |
|---|---|---|
400 | invalid request body | Malformed JSON |
400 | validation error | Missing or invalid fields (see data array for details). Includes inventory_reload — the inventory price snapshot expired (> 5 min since Get Inventory); re-fetch and retry |
400 | item_specified_price_not_found | An item's price at deposit time dropped below its min_prices floor. No trade is created; re-fetch the inventory for current prices |
401 | missing authorization header | X-Api-Key header not provided |
401 | invalid API key | API key not found or inactive |
403 | merchant account is disabled | Merchant account deactivated |
403 | invalid IP: <ip> | Request IP not in whitelist |
404 | not found error | Trade or items not found |
409 | already exist error | Duplicate merchant_tx_id |
500 | internal error | Something went wrong on our side |
→ For domain-specific validation codes (Steam account issues, trade eligibility), see Errors.
