快速开始
快速开始
约 15 分钟完成第一笔沙箱收款。
本教程使用 Node.js 18+,其他语言步骤完全相同 —— Python、Go、PHP、Java 示例见请求签名。
获取沙箱凭证
在开发者控制台中:
- 创建 App 并申请开通支付(App 未发布也可使用沙箱)。
- 支付状态变为已开通后,进入支付 → API Key,创建沙箱 Key。复制
key_id(ok_test_…)和 Secret —— Secret 只展示一次。 - 设置回调地址,复制回调签名密钥(同样只展示一次)。
保存为环境变量:
bash
export HTP_API_BASE=
export HTP_KEY_ID=ok_test_xxxxxxxx
export HTP_API_SECRET=xxxxxxxxxxxxxxxx
export HTP_CALLBACK_SECRET=xxxxxxxxxxxxxxxx添加签名函数
每个请求都使用 HMAC-SHA256 签名。保存为 htp.js:
htp.js
import crypto from 'node:crypto';
const { HTP_API_BASE, HTP_KEY_ID, HTP_API_SECRET } = process.env;
export async function htp(method, path, body, idempotencyKey = '') {
const raw = body === undefined ? '' : JSON.stringify(body);
const timestamp = Math.floor(Date.now() / 1000).toString();
const nonce = crypto.randomBytes(18).toString('base64url'); // 24 位 URL 安全字符
const bodyHash = crypto.createHash('sha256').update(raw).digest('hex');
const stringToSign = [method, path, timestamp, nonce, idempotencyKey, bodyHash].join('\n');
const signature = crypto.createHmac('sha256', HTP_API_SECRET).update(stringToSign).digest('base64');
const headers = {
'Content-Type': 'application/json',
'X-Key-Id': HTP_KEY_ID,
'X-Timestamp': timestamp,
'X-Nonce': nonce,
'X-Signature': signature,
};
if (idempotencyKey) headers['Idempotency-Key'] = idempotencyKey;
const res = await fetch(HTP_API_BASE + path, { method, headers, body: raw || undefined });
const json = await res.json();
if (!res.ok) {
throw Object.assign(new Error(json.message), { code: json.error_code, status: res.status, traceId: json.trace_id });
}
return json.data;
}创建收款单
create-payment.js
import crypto from 'node:crypto';
import { htp } from './htp.js';
const orderNo = 'A' + Date.now();
const payment = await htp(
'POST',
'/open/v1/payments',
{ out_order_no: orderNo, amount: '1.00', currency: 'USDT', description: '测试订单' },
crypto.randomUUID().replaceAll('-', ''), // Idempotency-Key —— 重试时复用
);
console.log(payment.id, payment.status); // … CREATED
console.log(payment.checkout_url);用测试用户付款
用 App 的测试用户(在控制台测试用户中添加)登录 HTP App,打开 checkout_url,输入支付 PIN 确认。
请使用测试用户,而不是你自己的账号
开发者永远不能向自己的 App 付款(SELF_PAYMENT_FORBIDDEN),沙箱和生产都一样。沙箱订单只能由 App 的测试用户支付(其他人返回 SANDBOX_USER_ONLY)。
接收回调
HTP 向你的回调地址 POST payment.paid。信任之前先校验签名 —— 代码见回调。
json
{
"event_id": "9e8d7c6b-5a4f-4e3d-2c1b-0a9f8e7d6c5b",
"event": "payment.paid",
"created_at": "2026-11-07T09:05:12Z",
"data": { "id": "0b7a9c62-…", "out_order_no": "A1730970000000", "status": "PAID", "amount": "1.00", "net_amount": "0.99", "user_sub": "2f6c0d1e8a9b4c7d", "…": "…" }
}还没有公网地址?可以改为查询订单:
js
const order = await htp('GET', `/open/v1/orders/${payment.id}`);
console.log(order.status); // PAID