独立站 / 外贸电商接入
这套接入适合谁
用 Shopify、WooCommerce 或自建商城做外贸生意的商家,想在结账页加一个"USDT 付款"选项, 买家选它之后看到收款信息,付款成功后订单自动标记为已支付。
前置准备
- 已拿到 API KEY(见立即接入),并配置好收款地址。
- 你的服务端能接收 webhook(平台的支付回调),并且能调用平台的开放接口(带 KEY)。
- 想清楚"谁触发发货":建议由平台的支付回调驱动订单状态变更,而不是靠买家点击。
服务端下单,绝不放到结账页
结账页是浏览器。所有下单请求都从你的商城后端发出(KEY 在后端), 结账页只负责展示收款信息或跳转。
接入形态:自定义支付方式 + webhook
三个平台的接法本质相同,都是这一套:
买家在结账页选 "Pay with USDT"
│
▼
你的商城后端 ──(带 API KEY)──▶ 平台 createOrder
│
▼
展示收款信息(收款地址 + 应付金额 + 链)或跳平台收银台
│
▼
买家付款 ──▶ 链上确认 ──▶ 平台回调你的 webhook
│
▼
你的商城后端把订单标记为已支付 / 触发发货WooCommerce:自定义支付网关
WooCommerce 通过支付网关插件接入。核心是 process_payment 里下单、以及一个接收回调的 REST 端点:
php
<?php
// 精简示意:WooCommerce 自定义支付网关
class WC_Gateway_Web3SDK extends WC_Payment_Gateway {
public function __construct() {
$this->id = 'web3sdk';
$this->method_title = 'USDT (Web3SDK)';
$this->has_fields = false;
parent::__construct();
}
public function process_payment($order_id) {
$order = wc_get_order($order_id);
// 1) 在商城后端下单:带 API KEY 调平台开放接口
$resp = wp_remote_post(getenv('API_BASE') . '/api/pay/open/createOrder', [
'headers' => [
'X-Pay-Api-Key' => getenv('PAY_API_KEY'), // 只在服务端
'Content-Type' => 'application/json',
],
'body' => wp_json_encode([
'merchantOrderNo' => (string) $order_id, // 幂等键
'chainId' => 2,
'tokenId' => 1,
'amount' => (string) $order->get_total(), // 代币单位小数字符串
'subject' => 'Order #' . $order_id,
'notifyUrl' => home_url('/?wc-api=web3sdk_notify'),
'returnUrl' => $this->get_return_url($order),
]),
'timeout' => 15,
]);
$data = json_decode(wp_remote_retrieve_body($resp), true);
if (empty($data['code']) && !isset($data['data']['order'])) {
wc_add_notice('USDT 下单失败,请重试', 'error');
return ['result' => 'failure'];
}
$o = $data['data']['order'];
// 2) 把收款信息存到订单上,结账后页面展示
$order->update_meta_data('_web3_order_no', $o['orderNo']);
$order->update_meta_data('_web3_pay_address', $o['payAddress']);
$order->update_meta_data('_web3_pay_amount', $o['payAmountDisplay']);
$order->update_meta_data('_web3_chain', $o['chainKey']);
$order->save();
return ['result' => 'success', 'redirect' => $this->get_return_url($order)];
}
}接收回调(验签 + 幂等 + 改订单状态):
php
add_action('woocommerce_api_web3sdk_notify', function () {
$raw = file_get_contents('php://input'); // 原始正文
$ts = $_SERVER['HTTP_X_PAY_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_PAY_SIGNATURE'] ?? '';
$key = getenv('PAY_API_KEY');
$want = hash_hmac('sha256', $ts . $raw, $key); // 时间戳 + 原始正文
if (!hash_equals($want, $sig)) { // 常数时间比较
status_header(401); exit;
}
$p = json_decode($raw, true);
$order_id = intval($p['merchantOrderNo'] ?? 0);
$order = $order_id ? wc_get_order($order_id) : null;
if (!$order) { status_header(200); exit; } // 不是我们的单,仍回 2xx
// 幂等:已处理过就直接应答
if ($order->get_meta('_web3_tx_hash') === ($p['txHash'] ?? '')) {
status_header(200); exit;
}
// 只认已确认,且不要只信回调 —— 可选:再查一次平台查询接口核对
if (($p['status'] ?? 0) >= 3) {
$order->update_meta_data('_web3_tx_hash', $p['txHash'] ?? '');
$order->payment_complete($p['txHash'] ?? ''); // 触发 WooCommerce 的已支付流程
}
status_header(200); exit; // 2xx 让平台停止重试
});Shopify:自定义支付方式
Shopify 的自定义支付方式(Custom payment method)在结账时把买家跳到一个你控制的 URL, 你在那里展示收款信息,付款成功后通过 Order API 把订单标记为已支付:
js
// 1) 你的服务端:跳转落地页里下单
app.get('/shopify/pay', async (req, res) => {
const { orderId, total } = req.query
const r = await fetch(`${process.env.API_BASE}/api/pay/open/createOrder`, {
method: 'POST',
headers: { 'X-Pay-Api-Key': process.env.PAY_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
merchantOrderNo: String(orderId),
chainId: 2, tokenId: 1, amount: String(total),
subject: `Shopify Order ${orderId}`,
notifyUrl: 'https://your-shop.com/shopify/notify',
}),
}).then((x) => x.json())
res.render('pay', { order: r.data.order })
})
// 2) 收到平台回调后,把 Shopify 订单标记为已支付
app.post('/shopify/notify', express.raw({ type: '*/*' }), async (req, res) => {
const raw = req.body.toString('utf8')
if (!verify(raw, req.get('X-Pay-Timestamp'), req.get('X-Pay-Signature'))) {
return res.sendStatus(401)
}
const p = JSON.parse(raw)
if (isProcessed(p.merchantOrderNo)) return res.sendStatus(200) // 幂等
await fetch(`https://${process.env.SHOP}/admin/api/2024-07/orders/${p.merchantOrderNo}/transactions.json`, {
method: 'POST',
headers: {
'X-Shopify-Access-Token': process.env.SHOPIFY_TOKEN,
'Content-Type': 'application/json',
},
body: JSON.stringify({
transaction: { kind: 'capture', status: 'success', amount: p.amountDisplay },
}),
})
markPaid(p.merchantOrderNo, p.txHash)
res.sendStatus(200)
})Shopify 的 API 版本与字段会变,请以官方文档为准;这里给的是接入形状。
回调处理
无论哪个平台,回调都遵循同一套规则:
- 验签:
HMAC-SHA256(apiKey, timestamp + 原始正文),常数时间比较。 - 幂等:用
merchantOrderNo(在你的商城里通常就是订单号)去重,别重复发货。 - 快返回:约 10 秒超时;改订单状态这类动作如果慢,先落库再异步做。
- 2xx 才停重试:返回 2xx 表示你收到了;其它状态码平台会按退避序列重试。
- 以查询为准:发货前用查询订单复核真实状态。
常见问题
| 问题 | 说明 |
|---|---|
| 能不能直接放一段 JS 在结账页下单 | 不能,KEY 会暴露。必须服务端下单 |
| 支付回调与商城 webhook 冲突吗 | 不冲突。平台的回调驱动"订单已支付",商城自己的 webhook 照常 |
用 amount 还是商城总额 | 开放接口要代币单位小数字符串,与商城总额同单位即可 |
| 币价波动怎么办 | 稳定币计价,金额按订单金额直接给;不涉及换汇 |
| 回调丢了怎么办 | 平台会重试;此外你的商城可以定时用查询接口对账补状态 |
| 库存锁定多久 | 由订单有效期(expiresAt)决定,过期即作废,不必再等 |
相关
- 创建订单 · 查询订单 · 回调通知与验签
- Next.js 接入(自建独立站常用)