加密货币支付 API 接入:账单、签名与 Webhook 全解析
一份实用的开发者教程:一次签名请求创建账单,一个 Webhook 端点接收状态,再加上保证安全可信的关键细节。

加密货币支付 API 接入需要两部分:一个在服务器端为每笔订单创建账单并返回收银台链接的请求,以及一个在链上检测到并确认付款时接收签名状态更新的 Webhook 端点。在 mistKET,两者都是纯 HTTPS 和 JSON,用 HMAC-SHA256 签名,无需任何 SDK。
本指南先用代码走一遍完整流程,然后讲解区分演示版和生产环境的安全与可靠性细节。
一张图看懂架构
每一次加密货币支付 API 接入都遵循同样的五步循环:
- 创建订单 — 后端调用
POST /api/v1/invoices,传入金额、币种、订单号和回调地址。 - 跳转 — 把客户引导到返回的
checkout_url。 - 付款 — 客户在托管页面选择网络并付款;汇率在账单有效期内锁定。
- Webhook — mistKET 向你的回调地址 POST
invoice.paid、invoice.confirmed或异常事件。 - 履约 — 验证签名,把订单标记为已付款并发货。
账户审核通过后,你会在商户后台获得 API Key、API Secret 和 Webhook Secret。完整文档位于后台的 API 页面。
第 1 步:签名并发送账单请求
每个 API 请求携带三个请求头。签名是用你的 API Secret 对字符串 {timestamp}.{raw body} 计算的十六进制 HMAC-SHA256:
POST /api/v1/invoices
X-Api-Key: mp_live_…
X-Api-Timestamp: 1760000000
X-Api-Signature: hex(hmac_sha256("{ts}.{body}", secret))
{
"amount": "184.50",
"currency": "USD",
"order_id": "2041",
"callback_url": "https://yourstore.com/webhooks/mistket"
} 最简 PHP 实现如下:
$body = json_encode([
'amount' => '184.50', 'currency' => 'USD',
'order_id' => '2041',
'callback_url' => 'https://yourstore.com/webhooks/mistket',
]);
$ts = (string) time();
$sig = hash_hmac('sha256', $ts . '.' . $body, $apiSecret);
// send $body with X-Api-Key, X-Api-Timestamp, X-Api-Signature 对你实际发送的原始字节签名。签名后又重新编码 JSON(空格或键顺序不同)是签名错误的头号原因。
第 2 步:跳转到托管收银台
调用成功会返回 201 Created,包含账单 UUID、状态(new)和 checkout_url。把 UUID 与订单关联保存,然后跳转客户。托管页面显示准确金额、二维码、倒计时和实时状态,并适配移动端。客户在页面上选择网络:TRON、BNB Smart Chain、Ethereum 或 Arbitrum 上的 USDT,以及 TRX、BNB 和 ETH,除非你在 API 调用中固定了网络。
除了创建账单,API 还支持列出、查询和取消账单,在购物车变化或订单被放弃时很有用。
第 3 步:接收并验证 Webhook
状态变化时,mistKET 会向你的回调地址 POST JSON,并带上以下请求头:
| 请求头 | 用途 |
|---|---|
X-Mistket-Event | 事件名称,例如 invoice.confirmed |
X-Mistket-Timestamp | 参与签名的 Unix 时间戳 |
X-Mistket-Signature | sha256= + 用 Webhook Secret 对 {timestamp}.{raw body} 计算的 HMAC-SHA256 |
X-Mistket-Delivery | 投递 ID,便于记录日志 |
PHP 验签示例:
$raw = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_MISTKET_TIMESTAMP'] ?? '';
$got = $_SERVER['HTTP_X_MISTKET_SIGNATURE'] ?? '';
$exp = 'sha256=' . hash_hmac('sha256', $ts . '.' . $raw, $webhookSecret);
if (!hash_equals($exp, $got) || abs(time() - (int) $ts) > 300) {
http_response_code(401); exit;
}
$event = json_decode($raw, true); 使用常量时间比较(PHP 用 hash_equals,Python 用 hmac.compare_digest,Node.js 用 crypto.timingSafeEqual),并拒绝过期的时间戳以防止重放攻击。关于该算法的背景,请参阅 RFC 2104(HMAC)。
Webhook 载荷示例
一笔已确认的付款以简洁的 JSON 文档送达。最常用的字段是事件、订单号、状态以及应付和实付金额:
POST https://yourstore.com/webhooks/mistket
X-Mistket-Event: invoice.confirmed
X-Mistket-Signature: sha256=…
{ "event": "invoice.confirmed", "data": {
"order_id": "2041", "status": "confirmed",
"pay_amount": "184.5", "paid_amount": "184.5",
"pay_currency": "USDT", "network": "TRC20" } } 把 pay_currency 和 network 随订单一起保存,之后做账和处理客服问题时都用得上。
Node.js 与 Python 验签
另外两种常用语言的同样校验:
// Node.js (Express with express.raw for this route)
const exp = 'sha256=' + crypto.createHmac('sha256', secret)
.update(ts + '.' + rawBody).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(exp), Buffer.from(sig));
# Python
exp = 'sha256=' + hmac.new(secret.encode(), f'{ts}.{raw}'.encode(),
hashlib.sha256).hexdigest()
ok = hmac.compare_digest(exp, sig) 两种情况下都要确保读取的是原始请求体。很多框架会自动解析 JSON,一旦解析后再序列化,字节就与签名对不上了。
本地测试
Webhook 需要公网 HTTPS 地址,本地电脑无法直接接收。两个实用方案:尽早把处理程序部署到测试服务器,或用内网穿透工具临时暴露本地端口。创建指向测试回调地址的小额账单,然后在商户后台查看投递日志,准确了解发送了什么、你的服务器返回了什么。
测试期间尽量把每种事件都触发一次:已付款、已确认、少付和过期。当处理程序的每个分支都用真实 Webhook 跑过之后,生产环境中就很少会有意外;即便出了问题,你也清楚投递日志会是什么样子。
第 4 步:处理每一种状态
Webhook 载荷包含订单号、状态、应付金额(pay_amount)、实付金额(paid_amount)、币种和网络。把每个事件映射到一个动作:
| 事件 | 含义 | 典型处理 |
|---|---|---|
invoice.paid | 已检测到转账,等待确认 | 显示“已收到付款,确认中” |
invoice.confirmed | 已达到所需确认数 | 标记已付款并发货 |
invoice.underpaid | 低于你设置的容差 | 等待补款或联系客户 |
invoice.overpaid | 超出应付金额 | 发货,并决定如何处理差额 |
invoice.expired | 有效期内未收到有效付款 | 释放库存,订单保持未付款 |
少付容差、累计到总额的部分付款以及宽限期内的延迟付款都由 mistKET 处理,你的代码只需对最终结果做出响应。
可靠性:重试与幂等
如果你的端点宕机或返回错误,Webhook 会按退避策略重试数小时。这意味着你有时会收到同一事件两次。请按订单号让处理程序保持幂等:
- 尽快返回 2xx,把耗时任务放到队列中处理。
- 发货前先检查订单是否已标记为已付款。
- 记录投递 ID 和事件以便排查问题;后台也提供 Webhook 投递日志。
安全检查清单
加密货币支付 API 接入涉及资金,应像对待其他支付代码一样严格:
- API Secret 和 Webhook Secret 只保存在服务器端,绝不放进前端代码或移动 App。
- 在后台用 IP 白名单限制 API 访问。
- 拒绝超出短时间窗口的请求时间戳。
- 根据库存预留逻辑配置账单有效期。
- 金额一律用字符串或定点小数处理,绝不使用浮点数。
下一步
以上就是完整的加密货币支付 API 接入:一次签名请求、一个经过验证的 Webhook 和一张状态映射表。同一流程的非开发者视角,请阅读网站如何接入加密货币收款。要做机器人而不是网站?请看Telegram 机器人加密货币收款。通过 Telegram @mistnetwork 申请 API 密钥,在开发者专区查看示例,并在商户登录页面管理密钥。


