POST /v1/orders — 使用余额购买 CS2 挂单
在单次原子请求中按 ID 购买 1–10 件 CS2 挂单,从您的 CSBoard 余额中扣款。需要启用交易的 API 密钥以及已绑定的 Steam 账户。
curl --request POST \
--url https://csboard.com/v1/orders \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"item_ids": [
"itm_8841201",
"itm_8841340"
],
"max_price_usd": 30,
"idempotency_key": "6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f"
}
'import requests
url = "https://csboard.com/v1/orders"
payload = {
"item_ids": ["itm_8841201", "itm_8841340"],
"max_price_usd": 30,
"idempotency_key": "6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
item_ids: ['itm_8841201', 'itm_8841340'],
max_price_usd: 30,
idempotency_key: '6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f'
})
};
fetch('https://csboard.com/v1/orders', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://csboard.com/v1/orders",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'item_ids' => [
'itm_8841201',
'itm_8841340'
],
'max_price_usd' => 30,
'idempotency_key' => '6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://csboard.com/v1/orders"
payload := strings.NewReader("{\n \"item_ids\": [\n \"itm_8841201\",\n \"itm_8841340\"\n ],\n \"max_price_usd\": 30,\n \"idempotency_key\": \"6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://csboard.com/v1/orders")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"item_ids\": [\n \"itm_8841201\",\n \"itm_8841340\"\n ],\n \"max_price_usd\": 30,\n \"idempotency_key\": \"6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://csboard.com/v1/orders")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"item_ids\": [\n \"itm_8841201\",\n \"itm_8841340\"\n ],\n \"max_price_usd\": 30,\n \"idempotency_key\": \"6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f\"\n}"
response = http.request(request)
puts response.read_body/v1/listings 时看到的价格。为防止查询与下单之间的价格波动,请始终包含 max_price_usd 作为总价上限。该端点是幂等的:使用相同的 Idempotency-Key 重试会重放原始订单,而非产生重复扣款。
需要身份验证。 请将密钥作为 Authorization: Bearer csb_pub_... 发送。
需要交易能力。 API 密钥必须启用购买功能。请在您的 CSBoard 个人资料中进行配置。
前置条件
下单前,请确保:- 启用交易的密钥——必须在您的 CSBoard 个人资料设置中为该 API 密钥开启购买功能。
- 已绑定的 Steam 账户与交易链接——您的 CSBoard 账户必须已绑定 Steam 账户并配置有效的交易链接,以便商品可以交付。
- 充足的余额——您的 CSBoard 余额必须能够覆盖所有商品按实时价格的总成本。
请求头
200、附带 Idempotent-Replayed: true 响应头以及原始订单响应,而不会执行第二次购买。若第一次请求仍在处理中,重试将返回 409 idempotency_in_progress。借此可在网络超时时安全重试而无重复扣款风险。请求体
GET /v1/listings 响应的 id 字段获取。每个 ID 在一次请求中只能出现一次。price_moved 错误被拒绝,且不会扣款。强烈建议使用——若无此值,您将无任何超额扣款保护。Idempotency-Key 请求头的替代方案。如果两者都提供,则以请求头为准。请二选一使用,不要同时使用。item_ids 所属的游戏:730 = CS2,570 = Dota 2,252490 = Rust。不传则为 CS2。请使用您从 GET /v1/listings 读取这些 id 时所用的同一个 appId。查看 GET /v1/games 中的 tradable,了解您的密钥可以在哪些游戏中购买。响应字段
新订单返回201 Created。幂等重放返回 200,响应体相同。
GET /v1/orders/{id} 以跟踪交付。paid 或 pending_delivery。这不是 GET /v1/orders 中规范化的 status 取值——请在那里或通过 Webhooks 跟踪订单。USD。instant(机器人交付)或 pending(仍需卖家或供应商发起交易)。Dota 2 和 Rust 订单始终返回 pending。null。示例请求
curl -X POST https://csboard.com/v1/orders \
-H "Authorization: Bearer csb_pub_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f" \
-d '{
"item_ids": ["itm_8841201", "itm_8841340"],
"max_price_usd": 30.00
}'
示例响应
{
"order_id": "cmg9x2k1p0007qz3h5v8w2r4n",
"status": "paid",
"currency": "USD",
"charged_total_usd": 26.47,
"item_count": 2,
"items": [
{
"market_hash_name": "AK-47 | Redline (Minimal Wear)",
"price_usd": 14.37,
"status": null
},
{
"market_hash_name": "AWP | Atheris (Field-Tested)",
"price_usd": 12.1,
"status": null
}
],
"delivery": "instant",
"expected_minutes": 1,
"created_at": "2026-06-29T17:12:04.000Z",
"updated_at": "2026-06-29T17:12:04.000Z"
}
错误代码
| HTTP 状态码 | 代码 | 含义 |
|---|---|---|
| 400 | invalid_request | 请求体格式错误——detail 为按字段列出的错误。 |
| 400 | unsupported_item | 该 ID 无法通过 API 购买。请使用 GET /v1/listings 返回的 ID。 |
| 400 | steam_account_required | 您的 CSBoard 账户未绑定 Steam 账户或没有有效的交易链接。 |
| 400 | cannot_mix_sources / one_external_per_order | 这些商品不能放在同一订单中。请拆分订单。 |
| 400 | unsupported_game | 您的密钥不能在此 appId 中购买。supported_app_ids 列出了可以购买的游戏。 |
| 401 | missing_api_key / invalid_api_key | API 密钥缺失或无效。 |
| 402 | insufficient_balance | 余额不足。响应体包含 required_usd 和 current_usd。 |
| 402 | kyc_required | 本次购买需要先完成身份验证。响应体包含 kyc_url。 |
| 403 | trading_not_enabled | 该 API 密钥未启用购买功能。请在您的个人资料中启用。 |
| 403 | account_restricted | 账户受限。请联系客服。 |
| 409 | price_moved | 实时总额超过了 max_price_usd。订单被拒绝,未扣款。响应体包含 quoted_max_usd、current_total_usd 以及每件商品的实时价格。 |
| 409 | item_unavailable | 商品在您的订单到达前已售出。响应体可能包含 unavailable_ids。 |
| 409 | idempotency_in_progress | 使用该 Idempotency-Key 的请求仍在处理中。请稍候并用同一个键重试。 |
| 409 | pending_trades_limit | 收货方有过多未接受的 Steam 交易报价。上限见响应体中的 limit。 |
| 409 | price_updating / concurrent_update | 价格正在刷新,或并发订单抢先完成。未扣款——请重试。 |
| 429 | rate_limit_exceeded | 超过每分钟 250 个订单,或超过密钥的通用每分钟限制。请等待 Retry-After 响应头中的秒数。 |
| 500 | order_failed | 意外失败。重试前请先查看 GET /v1/orders/info——订单可能已经存在。 |
| 503 | market_unavailable | 其中一件商品所在的市场暂时不可用。未扣款。 |
| 504 | upstream_timeout | 结果未知。请使用相同的 Idempotency-Key 重新发送或轮询订单——切勿使用新的键。 |
max_price_usd。实时市场上的价格可能在您查询 /v1/listings 到订单执行之间发生变化。若没有此上限,您的余额可能以高于预期的价格被扣除,且没有自动回滚机制。hold 交付的商品受 Steam 交易冻结约束。请查看原始挂单(来自 GET /v1/listings)上的 tradable_at 字段,了解被冻结的商品何时能在您的 Steam 库存中可交易。appId 为 570 或 252490 的订单会进入交付队列,并返回 delivery: "pending" 和 expected_minutes: null。请通过 GET /v1/orders/{id} 跟踪。价格上限、余额检查和幂等性与 CS2 完全相同。授权
Send your key as a Bearer token on every request: Authorization: Bearer csb_pub_.... Generate keys in your CSBoard profile.
请求头
Optional, 8–128 characters. A retried request with the same key replays the original order (200 with Idempotent-Replayed: true) instead of buying twice; while the first request is still running it answers 409 idempotency_in_progress.
请求体
1–10 unique ids from /v1/listings. Some items can't be combined in a single order — if so the order is rejected and you can split it.
1 - 10 elementsTotal ceiling in USD. Strongly recommended — your overcharge protection, enforced atomically inside the locked debit.
x <= 1000000Optional; or send the Idempotency-Key header. Replays the original order on retry.
8 - 128Sticky per-account setting (not per-order). Send true once to switch your key into auto-claim mode: every held order is then auto-released the moment its hold clears (your bot must auto-accept the Steam trade offer within ~15 minutes). Send false to switch back to manual claiming via POST /orders/{id}/claim. Omit to leave the setting unchanged.
Game the item_ids belong to: 730 = CS2 (the default), 570 = Dota 2, 252490 = Rust. Send the same appId you read the ids with from GET /listings. A game this key may not buy in answers 400 unsupported_game — tradable in GET /games tells you in advance.
730, 570, 252490 响应
Idempotent replay: a request with an Idempotency-Key (or idempotency_key) already used for a completed order returns that original response body, with the header Idempotent-Replayed: true. Nothing new is bought.
The order as it stands the moment it was created. status here is the internal state at that instant (for example paid or pending_delivery), not the normalised vocabulary of GET /orders — read the order there, or subscribe to webhooks, to follow it.
Order id. Use it with GET /orders/{id}.
Internal order state when the response was built, e.g. paid or pending_delivery. Poll GET /orders/{id} for the public status.
USD Total debited from your balance, in USD.
How the order is being delivered, when known: instant (bot delivery) or pending (a seller or supplier still has to send the trade). Dota 2 and Rust orders always answer pending.
instant, pending, null Rough delivery estimate in minutes, when we can state one. Always null for Dota 2 and Rust orders.
Number of items in the order.
One entry per item bought.
Show child attributes
Show child attributes
curl --request POST \
--url https://csboard.com/v1/orders \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"item_ids": [
"itm_8841201",
"itm_8841340"
],
"max_price_usd": 30,
"idempotency_key": "6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f"
}
'import requests
url = "https://csboard.com/v1/orders"
payload = {
"item_ids": ["itm_8841201", "itm_8841340"],
"max_price_usd": 30,
"idempotency_key": "6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
item_ids: ['itm_8841201', 'itm_8841340'],
max_price_usd: 30,
idempotency_key: '6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f'
})
};
fetch('https://csboard.com/v1/orders', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://csboard.com/v1/orders",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'item_ids' => [
'itm_8841201',
'itm_8841340'
],
'max_price_usd' => 30,
'idempotency_key' => '6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://csboard.com/v1/orders"
payload := strings.NewReader("{\n \"item_ids\": [\n \"itm_8841201\",\n \"itm_8841340\"\n ],\n \"max_price_usd\": 30,\n \"idempotency_key\": \"6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://csboard.com/v1/orders")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"item_ids\": [\n \"itm_8841201\",\n \"itm_8841340\"\n ],\n \"max_price_usd\": 30,\n \"idempotency_key\": \"6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://csboard.com/v1/orders")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"item_ids\": [\n \"itm_8841201\",\n \"itm_8841340\"\n ],\n \"max_price_usd\": 30,\n \"idempotency_key\": \"6f9c2b10-1a2b-4c3d-8e4f-5a6b7c8d9e0f\"\n}"
response = http.request(request)
puts response.read_body