DEVELOPER GUIDE / V1
把支付,接进你的产品。
产品负责订单与权益,Brclio Pay 负责与微信支付交互。通过服务端创建订单、核验通知,让网页和客户端共享同一条支付链路。
01 从下单到开通
- 为产品分配独立的
clientId、接口密钥和通知密钥,在支付服务端配置商品目录、允许的返回地址和通知地址。 - 用户点击购买,产品后端校验登录状态与商品,生成唯一的
merchantOrderId,向支付服务创建订单。 - 网页或客户端打开接口返回的
checkoutUrl。收银台凭证位于 URL 片段中,不会作为请求地址发给服务器。 - 微信确认付款后,支付服务验证通知与金额,向产品后端发送带签名的付款事件。产品核验并去重后开通权益。
- 用户返回产品时,产品后端查询订单复核,再展示自己的开通结果。
returnUrl 跳转,都不能单独作为到账凭据。产品权益只能依据服务端核验过的付款状态开通。02 按场景启用支付渠道
渠道必须同时满足商户权限、AppID 类型和支付参数要求。未开通的渠道应保持禁用。产品已有的支付宝及其他支付方式应继续保留,微信支付按新渠道接入。
| 场景 | 渠道 | 接入条件 |
|---|---|---|
| 电脑网页 / 桌面客户端 | Native 扫码 | 商户开通 Native,关联有效 AppID,用户用微信扫码。 |
| 微信小程序 | JSAPI | 关联的小程序 AppID 与对应用户 OpenID;在小程序内调用 wx.requestPayment。 |
| 微信内网页 | JSAPI | 需公众号 AppID、网页授权、对应 OpenID 和支付授权目录。小程序 AppID 不能直接代替公众号网页配置。 |
| 手机外部浏览器 | H5 | 需额外开通 H5 支付并配置支付域名;当前接入前先核实开通状态。 |
| 安卓原生应用 | APP | 需额外开通 APP 支付、绑定移动应用 AppID,并集成微信 SDK。 |
客户端统一通过自己的服务端下单。接口密钥与微信商户私钥均不得打包进网页、APK 或桌面应用。
03 创建与查询订单
POST /api/v1/orders
接口请求须带服务端签名。请求商品编码,金额以服务端商品目录为准;客户端不能自定付款金额。
{
"merchantOrderId": "your_unique_order_id",
"sku": "your_product_sku",
"quantity": 1,
"channel": "native",
"returnUrl": "https://your-product.brclio.com/billing/result"
}返回值包含订单 id、status 与 checkoutUrl。相同业务订单应复用同一个 merchantOrderId,避免网络重试生成重复订单。
查询:GET /api/v1/orders/:id;主动向微信核对:POST /api/v1/orders/:id/refresh。这两个接口同样需要签名,只能访问本产品自己的订单。
JSAPI 额外传入与该 AppID 对应的 payerOpenid;H5 额外传入由可信服务端获取的 clientIp。不要直接信任浏览器提交的代理请求头。
04 每次请求使用独立签名
签名只在产品后端生成。时间戳使用 Unix 秒,nonce 使用安全随机值。参与签名的请求路径和原始 JSON 字符串必须与发送的字节完全一致,末尾保留换行。
METHOD + "\n" +
pathnameAndQuery + "\n" +
timestamp + "\n" +
nonce + "\n" +
rawBody + "\n"
signature = HMAC_SHA256(apiKey, message).hex()发送以下请求头;GET 请求的 rawBody 为空字符串。
X-Brclio-Client: your_client_id
X-Brclio-Timestamp: unix_seconds
X-Brclio-Nonce: secure_random_hex
X-Brclio-Signature: lowercase_hex_hmacNode.js 服务端示例
import { createHmac, randomBytes } from 'node:crypto';
const path = '/api/v1/orders';
const timestamp = String(Math.floor(Date.now() / 1000));
const nonce = randomBytes(16).toString('hex');
const body = JSON.stringify({
merchantOrderId: 'your_unique_order_id',
sku: 'your_product_sku',
channel: 'native'
});
const message = `POST\n${path}\n${timestamp}\n${nonce}\n${body}\n`;
const signature = createHmac('sha256', process.env.PAY_API_KEY)
.update(message).digest('hex');
const response = await fetch(`${process.env.PAY_BASE_URL}${path}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Brclio-Client': process.env.PAY_CLIENT_ID,
'X-Brclio-Timestamp': timestamp,
'X-Brclio-Nonce': nonce,
'X-Brclio-Signature': signature
},
body
});
if (!response.ok) throw new Error('Payment order creation failed');
const order = await response.json();
// Return only the necessary checkout information to your client.05 验签、去重,再开通
支付事件发送到产品配置的 HTTPS 通知地址。先保留原始请求体字节并核验签名,通过后再解析 JSON。使用独立的通知密钥 webhookSecret,以常量时间比较函数核对签名,并检查时间戳有效期。
message = timestamp + "\n" + nonce + "\n" + rawBody + "\n"
signature = HMAC_SHA256(webhookSecret, message).hex()
X-Brclio-Event: payment.success.<orderId>
X-Brclio-Timestamp: unix_seconds
X-Brclio-Nonce: secure_random_hex
X-Brclio-Signature: lowercase_hex_hmac通知载荷包含 eventId、orderId、clientId、merchantOrderId、sku、quantity、total、currency、transactionId 和 paidAt。
- 核对
clientId、业务订单归属、SKU、数量、金额与币种,确保与产品自己的订单一致。 - 使用稳定的
eventId幂等处理。相同付款通知可能重复到达,不能重复发放权益。 - 建议再通过带签名的查询接口复核付款状态;把权益开通与事件去重放在同一个可靠事务中。
- 持久化处理结果后再返回 HTTP 2xx;处理失败返回非 2xx,让支付服务稍后重试。
06 正式收款前的准备
- 在 Cloudflare 为支付服务绑定 HTTPS 域名,例如
paywc.bornforthis.cn,将服务基址写入配置。 - 完成微信商户号、有效 AppID、商户 API 私钥、证书序列号、API v3 密钥与微信支付公钥配置。敏感配置仅通过 Cloudflare Secrets 管理。
- 核实 Native / JSAPI / H5 / APP 的实际开通状态,按场景完成关联、支付授权目录与域名配置。
- 为每个产品设置独立接口与通知密钥、商品目录、通知地址和允许的返回地址。
- 配置专用 GitHub 私有数据仓库的最小权限访问。高并发收款前,应评估 GitHub API 写入与限流边界。
- 完成真实小额付款、微信通知验签、主动查询、重复通知、权益去重和产品返回页验证。
支付中心的状态来自 GET /api/health。显示已配置,只代表服务端配置检查通过;正式上线仍应以真实支付验证结果为准。