USNpay API 文档
基于 RESTful 风格的加密货币收款接口。创建收款订单、查询状态、接收实时回调,资金直达您自己的钱包,固定 0.5% 透明手续费。
简介
USNpay 让您用自己的钱包收取加密货币付款。通过 API,您可以按法币定价创建订单,系统实时换算为加密金额并锁定汇率,客户付款后资金直接进入您绑定的链上钱包,平台不经手任何资金。
接入前,请先在会员中心注册商户账户并获取三项凭据:商户 ID(merchant_id)、API 公钥(api_key)、API 私钥(secret_key)。私钥仅在生成时显示一次,请妥善保管。
基础信息
请求地址
所有接口以您部署的站点域名为基础,统一前缀 /v1:
https://你的域名/v1数据格式
- 请求体为 JSON,请设置
Content-Type: application/json - 响应统一为 JSON,包含
code、message、data三个字段 - 金额字段均为字符串,加密金额最高 18 位小数,请用高精度库处理,切勿用浮点数
- 时间字段为 UTC 时间
统一响应结构
{
"code": 0, // 0 = 成功,非 0 = 失败
"message": "ok",
"data": { ... } // 业务数据,失败时为 null
}鉴权与签名
每个 API 请求都需通过 HMAC-SHA256 签名鉴权。请在请求头中携带以下四个字段:
| 请求头 | 说明 |
|---|---|
X-Merchant-Id | 商户 ID,如 M88021 |
X-Api-Key | API 公钥,如 pk_live_xxx |
X-Timestamp | 当前 Unix 时间戳(秒),有效窗口 ±300 秒,用于防重放 |
X-Signature | 签名值,计算方法见下 |
签名计算
将以下四部分用换行符 \n 拼接为待签名串,再用 API 私钥(secret_key)做 HMAC-SHA256,输出十六进制小写字符串:
HTTP方法(大写) + "\n" + 请求路径 + "\n" + 时间戳 + "\n" + 请求体
↓
signature = HMAC_SHA256(待签名串, secret_key)/v1/orders 这样的 path 部分,不含域名和查询参数。GET 请求的请求体为空字符串。时间戳必须与服务端时间相差在 5 分钟内。签名示例
MERCHANT="M88021"
APIKEY="pk_live_xxx"
SECRET="sk_live_xxx"
TS=$(date +%s)
PATH_="/v1/orders"
BODY='{"amount":"1288.00","fiat":"CNY","asset":"USDT","network":"TRC20"}'
# 拼接待签名串并计算 HMAC
PAYLOAD="POST\n${PATH_}\n${TS}\n${BODY}"
SIG=$(printf "%b" "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')
curl -X POST https://你的域名$PATH_ \
-H "X-Merchant-Id: $MERCHANT" \
-H "X-Api-Key: $APIKEY" \
-H "X-Timestamp: $TS" \
-H "X-Signature: $SIG" \
-H "Content-Type: application/json" \
-d "$BODY"function cpRequest($method, $path, $body, $cfg) {
$ts = time();
$json = $body ? json_encode($body, JSON_UNESCAPED_SLASHES) : '';
$payload = strtoupper($method) . "\n" . $path . "\n" . $ts . "\n" . $json;
$sig = hash_hmac('sha256', $payload, $cfg['secret']);
$ch = curl_init($cfg['base'] . $path);
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_POSTFIELDS => $json,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-Merchant-Id: " . $cfg['merchant'],
"X-Api-Key: " . $cfg['apikey'],
"X-Timestamp: " . $ts,
"X-Signature: " . $sig,
"Content-Type: application/json",
],
]);
return json_decode(curl_exec($ch), true);
}import time, json, hmac, hashlib, requests
def cp_request(method, path, body, cfg):
ts = str(int(time.time()))
raw = json.dumps(body, separators=(',', ':')) if body else ''
payload = f"{method.upper()}\n{path}\n{ts}\n{raw}"
sig = hmac.new(
cfg['secret'].encode(), payload.encode(), hashlib.sha256
).hexdigest()
headers = {
'X-Merchant-Id': cfg['merchant'],
'X-Api-Key': cfg['apikey'],
'X-Timestamp': ts,
'X-Signature': sig,
'Content-Type': 'application/json',
}
return requests.request(method, cfg['base'] + path, headers=headers, data=raw).json()const crypto = require('crypto');
async function cpRequest(method, path, body, cfg) {
const ts = String(Math.floor(Date.now() / 1000));
const raw = body ? JSON.stringify(body) : '';
const payload = `${method.toUpperCase()}\n${path}\n${ts}\n${raw}`;
const sig = crypto.createHmac('sha256', cfg.secret)
.update(payload).digest('hex');
const res = await fetch(cfg.base + path, {
method,
headers: {
'X-Merchant-Id': cfg.merchant,
'X-Api-Key': cfg.apikey,
'X-Timestamp': ts,
'X-Signature': sig,
'Content-Type': 'application/json',
},
body: raw || undefined,
});
return res.json();
}创建订单
按法币金额创建一笔收款订单。系统按当前汇率换算为加密金额并锁定,返回收款地址与支付链接。
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
amount | string | 必填 | 法币金额,如 "1288.00" |
fiat | string | 可选 | 计价法币,默认取站点配置,如 CNY/USD/EUR |
asset | string | 必填 | 收款币种,如 USDT/BTC/ETH |
network | string | 可选 | 网络,如 TRC20/ERC20。不填则取该币种默认网络 |
subject | string | 可选 | 商品名称或订单备注 |
out_trade_no | string | 可选 | 商户侧订单号,用于幂等。相同值重复请求返回同一订单 |
notify_url | string | 可选 | 回调通知地址。订单状态变化时推送至此 |
return_url | string | 可选 | 支付完成后跳转地址 |
请求示例
{
"amount": "1288.00",
"fiat": "CNY",
"asset": "USDT",
"network": "TRC20",
"subject": "会员年卡",
"out_trade_no": "SHOP-20260528-001",
"notify_url": "https://yourshop.com/callback"
}响应示例
{
"code": 0,
"message": "订单创建成功",
"data": {
"order_no": "CP-20260528-A1B2C3D4",
"out_trade_no": "SHOP-20260528-001",
"fiat": "CNY",
"fiat_amount": "1288.00",
"crypto_amount": "181.408450",
"rate": "7.100000000000",
"pay_address": "TJ8s...9kQz",
"pay_url": "https://你的域名/pay/CP-20260528-A1B2C3D4",
"status": "pending",
"subject": "会员年卡",
"expired_at": "2026-05-28 15:08:00",
"created_at": "2026-05-28 14:38:00"
}
}查询订单
根据平台订单号查询订单当前状态。建议优先依赖 Webhook 回调,仅在需要主动核对时调用此接口。
响应示例
{
"code": 0,
"message": "ok",
"data": {
"order_no": "CP-20260528-A1B2C3D4",
"status": "completed",
"crypto_amount": "181.408450",
"pay_address": "TJ8s...9kQz"
}
}订单列表
分页查询本商户的订单列表,支持按状态筛选。
查询参数
| 参数 | 说明 |
|---|---|
page | 页码,默认 1 |
size | 每页条数,默认 20,最大 100 |
status | 按状态筛选,可选,见订单状态表 |
GET /v1/orders?page=1&size=20&status=completed健康检查
检测服务可用性,无需鉴权。返回当前服务时间。
{ "code": 0, "data": { "time": "2026-05-28T14:38:00+00:00", "service": "USNpay" } }Webhook 通知
当订单状态发生变化(如到账、确认、完成)时,USNpay 会向您创建订单时提供的 notify_url 发送 POST 请求。请在收到通知后返回 HTTP 2xx 状态码表示接收成功;否则系统会按指数退避策略重试,最多重试若干次(由后台配置)。
推送请求头
| 请求头 | 说明 |
|---|---|
X-ChainPay-Signature | 推送体的 HMAC-SHA256 签名,用于验签 |
X-USNpay-Event | 事件类型,如 order.confirmed |
推送内容
{
"order_no": "CP-20260528-A1B2C3D4",
"out_trade_no": "SHOP-20260528-001",
"status": "confirmed",
"fiat": "CNY",
"fiat_amount": "1288.00",
"crypto_amount": "181.408450",
"paid_amount": "181.408450",
"tx_hash": "a7f3...d9e2",
"timestamp": 1716885480
}回调验签
收到回调后,请务必用您的 webhook_secret 对原始请求体重新计算 HMAC-SHA256,与请求头 X-ChainPay-Signature 比对,一致才视为合法通知。请使用恒定时间比较函数防止时序攻击。
$raw = file_get_contents('php://input');
$sig = $_SERVER['HTTP_X_CHAINPAY_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', $raw, $webhookSecret);
if (!hash_equals($expected, $sig)) {
http_response_code(401); exit('invalid signature');
}
$data = json_decode($raw, true);
// 验签通过 → 按 $data['status'] 更新本地订单
http_response_code(200); echo 'ok';@app.route('/callback', methods=['POST'])
def callback():
raw = request.get_data()
sig = request.headers.get('X-ChainPay-Signature', '')
expected = hmac.new(
webhook_secret.encode(), raw, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, sig):
return 'invalid', 401
data = request.get_json()
# 更新本地订单
return 'ok', 200app.post('/callback', express.raw({type:'*/*'}), (req, res) => {
const raw = req.body; // Buffer
const sig = req.headers['x-chainpay-signature'];
const expected = crypto.createHmac('sha256', webhookSecret)
.update(raw).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig)))
return res.status(401).send('invalid');
const data = JSON.parse(raw.toString());
// 更新本地订单
res.send('ok');
});order_no 做幂等,避免重复回调导致重复发货。订单状态
| 状态 | 含义 |
|---|---|
| pending | 待支付,订单已创建,等待客户付款 |
| paid | 已支付,检测到链上转账,确认数未达标 |
| confirmed | 已确认,达到所需确认数 |
| completed | 已完成,回调成功通知商户 |
| expired | 已超时,超过有效期仍未支付 |
| refunded | 已退款 |
| failed | 失败 |
错误码
失败响应的 code 非 0,HTTP 状态码标识错误类别,message 含可读描述。
| HTTP | 场景 | 说明 |
|---|---|---|
401 | 鉴权失败 | 缺少鉴权头、签名错误、时间戳过期、API Key 无效或已吊销 |
403 | 禁止访问 | 请求 IP 不在白名单内 |
404 | 资源不存在 | 订单不存在或接口路径错误 |
409 | 状态冲突 | 订单当前状态不允许该操作 |
422 | 参数错误 | 金额无效、缺少必填参数、币种不支持 |
400 | 请求错误 | 其他业务错误,如商户未配置收款钱包 |
500 | 服务异常 | 服务端内部错误 |