商户 API 文档

USDT-TRC20 支付网关对外开放的服务器端接入 API(/api/v1/)。 所有接口要求商户使用 HMAC-SHA256 进行签名认证, 请求与响应均为 JSON 格式。

适用对象:集成 USDT 收款能力的商户系统服务端(不适用浏览器端直接调用 —— 出于密钥安全考虑,api_secret 不应出现在任何前端代码或 CDN 资源中)。

接入地址

生产环境
https://api2.iqingchuan.com/api/v1
测试环境
https://api2.iqingchuan.com/api/v1(测试/生产共用同一 API 入口)
所有请求
走 HTTPS,Content-Type 为 application/json; charset=utf-8

签名认证

所有 /api/v1/ 接口都需要 4 个签名头 + 1 个身份头。 商户在管理端「设置」页生成 api_key(公钥,用于识别身份) 与 api_secret(私钥,用于签名)。api_secret 一旦丢失只能重置,平台不存储明文。

必填请求头

说明
X-Api-Key商户 api_key(注册时由平台生成)
X-TimestampUnix 秒级时间戳,误差须在 ±300 秒内
X-Nonce随机字符串(建议 16+ 字节),10 分钟内不可重用
X-SignatureHMAC-SHA256 签名(hex 小写),见下方算法

签名算法

msg = timestamp + "\n" + nonce + "\n" + METHOD + "\n" + path + "\n" + body
signature = HMAC_SHA256(api_secret, msg).hexdigest()

说明:

常见踩坑:
  • GET 请求的 body 必须是空字符串 "",不能传 null{}
  • path 必须包含 query string,且顺序与编码后实际发送的一致(服务端按 request.url.path + ? + request.url.query 验签)
  • 服务器时间偏差若 > 5 分钟会返回 TIMESTAMP_EXPIRED,建议使用 NTP
  • 同一 nonce 10 分钟内不可重用,否则返回 NONCE_REPLAY(这是重试机制的关键)

返回结构

成功时统一返回:

{
  "code": 0,
  "message": "ok",
  "data": { ... }
}

失败时 code 为业务错误码字符串,message 为人可读描述, HTTP 状态码同步返回(401/403/404/400/500)。

错误码一览

codeHTTP含义
MISSING_AUTH_HEADERS401签名头缺失
INVALID_TIMESTAMP401时间戳格式错误
TIMESTAMP_EXPIRED401时间戳误差超过 5 分钟
NONCE_REPLAY401nonce 10 分钟内已被使用
INVALID_API_KEY401api_key 不存在
INVALID_SIGNATURE401签名校验失败
MERCHANT_UNAVAILABLE403商户账号被禁用
BLACKLISTED403商户或 IP 在黑名单
IP_NOT_ALLOWED403客户端 IP 不在白名单
PARAM_REQUIRED400必填参数缺失
INVALID_MERCHANT_ORDER_NO400订单号非法
INVALID_CLIENT_USER_ID400客户 ID 非法
NOTIFY_URL_REQUIRED400未提供 notify_url 且商户未设置默认地址
INVALID_MODE400confirmation_mode 取值非法
INVALID_EXPIRE400expire_minutes 应在 5–1440 之间
AMOUNT_POOL_EXHAUSTED400该地址与金额组合已满负载(可重试或换地址)
MERCHANT_ORDER_DUPLICATE409订单号已存在(同 merchant_order_no)
ORDER_NOT_FOUND404订单不存在
ORDER_STATUS_INVALID400只有 CREATED 状态可取消
INTERNAL_ERROR500服务端内部错误

POST /order/create 下单

POST /order/create

创建一笔 USDT 收款订单。返回订单号、收款地址、应付金额、二维码内容。 同一 merchant_order_no 重复请求会幂等返回原订单。

请求参数(body)

字段类型必填说明
merchant_order_nostring(1-128)*商户侧订单号,商户系统内唯一
amountstring(精度 ≤ 6)*收款金额,字符串以保留精度(如 "10.00")
client_user_idstring(1-128)*商户侧用户标识,用于风控
notify_urlstring(≤500)入账回调地址;留空使用商户默认回调
client_ipstring(≤45)下单客户 IP,留空由服务端从头部识别
client_fingerprintstring(≤64)设备指纹,风控辅助
confirmation_mode"fast"|"standard"|"smart"确认数模式;smart 时 ≤50 USDT 自动 0 确认
expire_minutesint(5-1440)订单过期时间,默认 30 分钟
extraobject透传字段,会在回调中原样返回

响应

{
  "code": 0,
  "message": "ok",
  "data": {
    "platform_order_no": "PAY202608110001",
    "merchant_order_no": "MYORDER_001",
    "base_amount": "10.00",
    "pay_amount": "10.001234",
    "pay_address": "TAbc...",
    "status": "CREATED",
    "confirmation_mode": "smart",
    "required_confirmations": 0,
    "expire_at": 1723353600,
    "created_at": 1723351980,
    "qr_code_content": "tron:TAbc...?amount=10.001234&token=TR7..."
  }
}
<?php
$apiKey    = 'YOUR_API_KEY';
$apiSecret = 'YOUR_API_SECRET';
$baseUrl   = 'https://api2.iqingchuan.com';
$path      = '/api/v1/order/create';
$body      = json_encode([
    'merchant_order_no' => 'MYORDER_'.time(),
    'amount'            => '10.00',
    'client_user_id'    => 'user_123',
    'notify_url'        => 'https://yoursite.com/cb',
]);

$ts    = (string) time();
$nonce = bin2hex(random_bytes(16));
$msg   = $ts."\n".$nonce."\nPOST\n".$path."\n".$body;
$sig   = hash_hmac('sha256', $msg, $apiSecret);

$ch = curl_init($baseUrl.$path);
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => $body,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        'Content-Type: application/json',
        "X-Api-Key: $apiKey",
        "X-Timestamp: $ts",
        "X-Nonce: $nonce",
        "X-Signature: $sig",
    ],
]);
echo curl_exec($ch);
// Java(后端,使用 OkHttp + Jackson)
String apiKey    = "YOUR_API_KEY";
String apiSecret = "YOUR_API_SECRET";
String baseUrl   = "https://api2.iqingchuan.com";
String path      = "/api/v1/order/create";

Map<String,Object> params = new HashMap<>();
params.put("merchant_order_no", "MYORDER_" + System.currentTimeMillis());
params.put("amount", "10.00");
params.put("client_user_id", "user_123");
params.put("notify_url", "https://yoursite.com/cb");

ObjectMapper mapper = new ObjectMapper();
String body = mapper.writeValueAsString(params);

String ts    = String.valueOf(System.currentTimeMillis() / 1000);
String nonce = UUID.randomUUID().toString().replace("-", "");
String msg   = ts + "\n" + nonce + "\nPOST\n" + path + "\n" + body;
String sig   = HmacUtils.hmacSha256Hex(apiSecret, msg);

Request req = new Request.Builder()
    .url(baseUrl + path)
    .post(RequestBody.create(body, MediaType.parse("application/json")))
    .addHeader("X-Api-Key",    apiKey)
    .addHeader("X-Timestamp",  ts)
    .addHeader("X-Nonce",      nonce)
    .addHeader("X-Signature",  sig)
    .build();

OkHttpClient client = new OkHttpClient();
try (Response resp = client.newCall(req).execute()) {
    System.out.println(resp.body().string());
}
import time, uuid, json, hmac, hashlib, requests

API_KEY    = "YOUR_API_KEY"
API_SECRET = "YOUR_API_SECRET"
BASE_URL   = "https://api2.iqingchuan.com"
PATH       = "/api/v1/order/create"

body = json.dumps({
    "merchant_order_no": "MYORDER_" + str(int(time.time())),
    "amount": "10.00",
    "client_user_id": "user_123",
    "notify_url": "https://yoursite.com/cb",
}, separators=(",", ":"))

ts    = str(int(time.time()))
nonce = uuid.uuid4().hex
msg   = f"{ts}\n{nonce}\nPOST\n{PATH}\n{body}"
sig   = hmac.new(API_SECRET.encode(), msg.encode(), hashlib.sha256).hexdigest()

resp = requests.post(
    BASE_URL + PATH,
    data=body,
    headers={
        "Content-Type": "application/json",
        "X-Api-Key":    API_KEY,
        "X-Timestamp":  ts,
        "X-Nonce":      nonce,
        "X-Signature":  sig,
    },
    timeout=15,
)
print(resp.json())
// Node.js(使用原生 https + crypto,无需第三方依赖)
const crypto = require("crypto");
const https  = require("https");

const API_KEY    = "YOUR_API_KEY";
const API_SECRET = "YOUR_API_SECRET";
const PATH       = "/api/v1/order/create";

const bodyObj = {
    merchant_order_no: "MYORDER_" + Date.now(),
    amount: "10.00",
    client_user_id: "user_123",
    notify_url: "https://yoursite.com/cb",
};
const body = JSON.stringify(bodyObj);

const ts    = Math.floor(Date.now() / 1000).toString();
const nonce = crypto.randomBytes(16).toString("hex");
const msg   = `${ts}\n${nonce}\nPOST\n${PATH}\n${body}`;
const sig   = crypto.createHmac("sha256", API_SECRET).update(msg).digest("hex");

const req = https.request({
    host: "api2.iqingchuan.com",
    path: PATH,
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "X-Api-Key":    API_KEY,
        "X-Timestamp":  ts,
        "X-Nonce":      nonce,
        "X-Signature":  sig,
    },
}, (res) => {
    let chunks = "";
    res.on("data", c => chunks += c);
    res.on("end", () => console.log(JSON.parse(chunks)));
});
req.write(body); req.end();

GET /order/query 查单

GET /order/query

根据 platform_order_nomerchant_order_no 查询订单。

查询参数

字段类型必填说明
platform_order_nostring平台订单号(以 PAY 开头)
merchant_order_nostring商户订单号

两个参数至少传一个。

响应

/order/create 响应格式。

<?php
$apiKey    = 'YOUR_API_KEY';
$apiSecret = 'YOUR_API_SECRET';
$baseUrl   = 'https://api2.iqingchuan.com';

$query = http_build_query(['platform_order_no' => 'PAY202608110001']);
$path  = '/api/v1/order/query?'.$query;
$body  = '';   // GET 请求 body 必须为空字符串

$ts    = (string) time();
$nonce = bin2hex(random_bytes(16));
$msg   = $ts."\n".$nonce."\nGET\n".$path."\n".$body;
$sig   = hash_hmac('sha256', $msg, $apiSecret);

$ch = curl_init($baseUrl.$path);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        "X-Api-Key: $apiKey",
        "X-Timestamp: $ts",
        "X-Nonce: $nonce",
        "X-Signature: $sig",
    ],
]);
echo curl_exec($ch);
String path = "/api/v1/order/query?platform_order_no=PAY202608110001";
String body = "";

String ts    = String.valueOf(System.currentTimeMillis() / 1000);
String nonce = UUID.randomUUID().toString().replace("-", "");
String msg   = ts + "\n" + nonce + "\nGET\n" + path + "\n" + body;
String sig   = HmacUtils.hmacSha256Hex(apiSecret, msg);

Request req = new Request.Builder()
    .url("https://api2.iqingchuan.com" + path)
    .get()
    .addHeader("X-Api-Key",   apiKey)
    .addHeader("X-Timestamp", ts)
    .addHeader("X-Nonce",     nonce)
    .addHeader("X-Signature", sig)
    .build();

OkHttpClient client = new OkHttpClient();
try (Response resp = client.newCall(req).execute()) {
    System.out.println(resp.body().string());
}
import time, uuid, hmac, hashlib, requests

API_KEY    = "YOUR_API_KEY"
API_SECRET = "YOUR_API_SECRET"
PATH       = "/api/v1/order/query"
QUERY      = "platform_order_no=PAY202608110001"
FULL_PATH  = f"{PATH}?{QUERY}"
body       = ""   # GET 签名 body 必须是空字符串

ts    = str(int(time.time()))
nonce = uuid.uuid4().hex
msg   = f"{ts}\n{nonce}\nGET\n{FULL_PATH}\n{body}"
sig   = hmac.new(API_SECRET.encode(), msg.encode(), hashlib.sha256).hexdigest()

resp = requests.get(
    "https://api2.iqingchuan.com" + FULL_PATH,
    headers={
        "X-Api-Key":   API_KEY,
        "X-Timestamp": ts,
        "X-Nonce":     nonce,
        "X-Signature": sig,
    },
    timeout=15,
)
print(resp.json())
const crypto = require("crypto");
const https  = require("https");

const API_KEY    = "YOUR_API_KEY";
const API_SECRET = "YOUR_API_SECRET";
const QUERY      = "platform_order_no=PAY202608110001";
const FULL_PATH  = "/api/v1/order/query?" + QUERY;
const body       = "";

const ts    = Math.floor(Date.now() / 1000).toString();
const nonce = crypto.randomBytes(16).toString("hex");
const msg   = `${ts}\n${nonce}\nGET\n${FULL_PATH}\n${body}`;
const sig   = crypto.createHmac("sha256", API_SECRET).update(msg).digest("hex");

https.get({
    host: "api2.iqingchuan.com",
    path: FULL_PATH,
    headers: {
        "X-Api-Key":   API_KEY,
        "X-Timestamp": ts,
        "X-Nonce":     nonce,
        "X-Signature": sig,
    },
}, (res) => {
    let chunks = "";
    res.on("data", c => chunks += c);
    res.on("end", () => console.log(JSON.parse(chunks)));
});

POST /order/cancel 取消

POST /order/cancel

取消一笔尚未入账的订单(只能取消 CREATED 状态的订单)。 取消后金额配额会回滚,同款金额可被新订单重新占用。

请求参数(body)

字段类型必填说明
platform_order_nostring*平台订单号

响应

{ "code": 0, "message": "已取消", "data": { "platform_order_no": "PAY...", "status": "CANCELLED" } }
<?php
$path = '/api/v1/order/cancel';
$body = json_encode(['platform_order_no' => 'PAY202608110001']);

$ts = (string) time();
$nonce = bin2hex(random_bytes(16));
$msg = $ts."\n".$nonce."\nPOST\n".$path."\n".$body;
$sig = hash_hmac('sha256', $msg, $apiSecret);
// 头部同 /order/create 示例,curl 用 POST 发送 $body
// body 仅含 platform_order_no,其它头部同 /order/create
body = json.dumps({"platform_order_no": "PAY202608110001"})
# 头部构造与 /order/create 一致,仅 path 与 body 不同
// body 仅含 platform_order_no,头部构造与 /order/create 一致

GET /order/list 列表

GET /order/list

分页拉取当前商户的订单列表。可选按状态筛选。

查询参数

字段类型必填说明
statusstring订单状态:CREATED / PAID / CONFIRMED / SETTLED / EXPIRED / CANCELLED
pageint ≥ 1页码,默认 1
page_sizeint 1-100每页数量,默认 20,最大 100

响应

{
  "code": 0, "message": "ok",
  "data": {
    "total": 42, "page": 1, "page_size": 20,
    "items": [
      { "platform_order_no": "PAY...", "status": "PAID", "pay_amount": "10.001234", ... }
    ]
  }
}

签名方式同 /order/query(GET,body 为空字符串)。

GET /ping 调试

GET /ping

连通性测试。验证签名正确后,返回当前商户号、套餐状态与服务端时间戳。 可用于 SDK 接入自检。

{ "code": 0, "message": "pong", "data": { "merchant_no": "M001", "email": "merchant@x.com", "package_status": "active", "server_time": 1723351980 } }

POST /echo 调试

POST /echo

回显测试。服务端原样回传你发的 JSON body,用于校验序列化是否一致。

// 请求 body:任意 JSON
{ "hello": "world", "n": 1 }
// 响应
{ "code": 0, "message": "ok", "data": { "received": { "hello": "world", "n": 1 }, "from": "M001" } }