1. 快速接入
- 登录平台,打开 /merchant,填写商户名称,自助开通。每个已注册账户可开通一个商户,无需管理员审批。
- 在商户中心创建 API 密钥。完整密钥仅显示一次,保存到你的服务端环境变量;不要放进网页、App 包、Git 或 URL。最多保留 5 个有效密钥,支持撤销与轮换。
- 服务端创建订单,将响应中的
checkoutUrl提供给付款用户。 - 用户在平台登录并核对商户、标题和金额后确认支付积分。API 密钥不能代替用户确认、不能指定付款用户或自动扣款。
- 你的服务端查询订单,确认
status === "paid"后按商户订单号幂等交付。收款进入开通者的积分账户,可站内转账或经现有审核流程提取为 USDC。
支持签名 Webhook 推送,服务端查询用于交付前核实和漏单补偿;不提供浏览器支付结果回调、部分退款或 API 链上提现。订单支付与退款均为平台内积分变动,无链上 Gas;USDC 提现使用平台已有的审核流程。
2. 基础地址、鉴权和通用约定
生产 Base URL:https://你的平台域名/api/merchant/v1。本地:http://localhost:8787/api/merchant/v1。文档中的 $BASE 包含 /api/merchant/v1,$KEY 为完整密钥。
Authorization: Bearer um_live_<64 位随机十六进制字符串> Content-Type: application/json Idempotency-Key: <UUID,仅创建订单必填>
- 所有接口均需 Bearer 密钥,Cookie 登录会话不能替代商户 API 密钥。只允许访问该密钥所属商户的数据。
- POST 必须使用 JSON;取消订单发送
{}。服务端接入不要求 Origin,不开放跨域浏览器 API 接入。 - 每商户每分钟最多 120 次 API 请求,含查询、鉴权后的错误请求和重试。超限返回 429,请等待约一分钟再重试;本版本不返回 Retry-After。
- 金额请求必须是十进制字符串,单位为平台积分,最多 6 位小数。例如
"1.250001"。不接受 JSON 数值、负数、0、科学计数法或 USDC 链上最小单位作为 amount。 - 最大单笔为
9007199254.740991积分,实际付款还受用户可用余额和收款账户容量约束。冻结积分不可支付。 - 响应的 amount 固定 6 位小数;amountMicros 为整数的十进制字符串,1 积分 = 1,000,000 最小单位。currency 固定为 POINTS,与管理员设置的积分显示名称无关。
- 时间均为 UTC Unix 秒。响应头 X-Request-ID 和错误体 requestId 用于排查请求,不是幂等键。
3. 完整接口列表
| 方法 | 路径 | 用途 |
|---|---|---|
| GET | /account | 查询商户与收款账户可用/冻结余额 |
| POST | /orders | 创建订单,必填 Idempotency-Key |
| GET | /orders | 倒序列出本商户订单,支持 before 分页 |
| GET | /orders/{id} | 按平台订单 UUID 查询 |
| GET | /orders/by-number/{outTradeNo} | 按商户订单号查询 |
| POST | /orders/{id}/cancel | 取消待付款订单 |
GET /account
{"merchantId":"商户UUID","name":"示例商店","status":"active",
"balanceMicros":"10000000","reservedMicros":"0","currency":"POINTS","decimals":6}余额与开通商户的用户账户共用;不是单独的商户钱包。密钥不会返回助记词、私钥、其他用户余额或提现权限。
POST /orders
curl "$BASE/orders" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $REQUEST_UUID" \
-d '{"outTradeNo":"SHOP-20261104-001","title":"示例商品",
"amount":"1.250001","expiresInSeconds":1800}'| 请求字段 | 类型 | 必填 | 规则 |
|---|---|---|---|
| outTradeNo | string | 是 | 1–64 个字母、数字、下划线、点或短横线;本商户内永久唯一 |
| title | string | 是 | 去除首尾空格后 1–120 字,向付款用户展示 |
| amount | string | 是 | 大于 0,最多 10 位整数和 6 位小数,不超过上述上限 |
| expiresInSeconds | integer | 否 | 60–86400,默认 1800。有效期自首次成功创建开始,不因重试延长 |
成功统一返回 HTTP 200 和下方订单对象。创建订单不扣任何用户积分。创建请求超时后,用同一 Idempotency-Key、同一商户订单号及完全相同的业务参数重试;也可通过商户单号查询是否已创建。
GET /orders?before={cursor}
不传 before 查询最新订单,每页最多 50 条。before 为正整数游标,使用上一页响应的 nextBefore;为 null 表示已无下一页。列表按创建顺序倒序,查询会更新已过期的未付订单状态。
{"data":[{"id":"订单UUID","cursor":"51","status":"pending","...":"完整订单字段"}],
"nextBefore":"51"}
订单管理与筛选
订单管理页面为 /merchant/orders,支持关键词、状态、创建日期、详情、全额退款确认和 CSV 导出。创建入口保留在商户中心,可选 5 分钟、30 分钟、1 小时或 24 小时有效期。停用商户可使用登录账户查看和导出历史记录,但 Bearer API 仍整体禁止访问。
| 列表、统计与导出通用查询参数 | 规则 |
|---|---|
| q | 可选,去除首尾空格后最多 120 字。平台订单号、支付/退款流水精确匹配;商户订单号与标题包含匹配(ASCII 不区分大小写);%、_ 和引号均按普通文字处理 |
| source | 可选:shop(商城订单)/ api(API 订单)。按商城购买记录关联判断,列表、统计、导出共用此筛选。 |
| status | 可选:pending / paid / refunded / cancelled / expired |
| from / to | 可选的非负 Unix 秒整数,按 createdAt 筛选,范围为 from ≤ createdAt < to。两者同时提供时 from 必须小于 to;上限 253402300799。网页使用浏览器本地时区,将结束日期换算为次日零点 |
| before | 仅列表分页参数;翻页时必须保留相同筛选。统计和导出忽略 before,覆盖所有筛选结果 |
GET /orders/summary
{"totalOrders":3,"counts":{"pending":1,"paid":1,"cancelled":0,"expired":0,"refunded":1},
"paidAmountMicros":"5623456","refundedAmountMicros":"2500000","netAmountMicros":"3123456"}paidAmountMicros 为筛选结果中已付款及已退款订单的原始收款总额;refundedAmountMicros 为已退款订单总额;netAmountMicros 为两者之差。金额为精确整数的字符串,累计总额可以大于单账户安全整数上限。统计按订单创建时间分组,后续支付或退款会使结果变化,不等同于支付日期结算报表。净收款不扣除账户转账、提现或其他余额变动,不能当作可用余额;列表与统计是各自查询时的状态,持续交易时可能短暂变化。
GET /orders/{id}/detail
返回完整订单对象,额外包含 payerAccountId: string | null 和 webhookEvents: []。付款账户 ID 仅用于核对原付款方,不能指定为退款参数;不返回邮箱或钱包私钥。每个回调摘要包含 id、type、status、totalAttempts、lastHttpStatus、lastError、createdAt、deliveredAt;可用回调详情接口查询投递日志,失败事件可通过既有 retry 接口补发。无回调配置时可能为空,不会追溯生成历史事件。
GET /orders/export
返回 UTF-8 BOM 的 text/csv,Content-Disposition 为附件 merchant-orders.csv;列为 id、outTradeNo、title、status、amount、amountMicros、currency、createdAt、expiresAt、paidAt、refundedAt、paymentReference、refundReference、source。所有时间为 Unix 秒,空字段用空单元格;引号和换行按 CSV 规则转义。可能被表格软件当作公式的内容会添加单引号前缀。最多 5000 条,超限返回 400 / export_limit,需缩小筛选,绝不静默截断。每商户每分钟最多导出 5 次,并计入 API 的 120 次总限额。表格软件导入时将编号和金额列设为文本以保留精度。Node.js 客户端支持 listOrders(before, filters)、orderSummary(filters)、getOrderDetail(id)、exportOrders(filters)(返回 CSV 文本)。
GET /orders/{id} 与 GET /orders/by-number/{outTradeNo}
响应为同一订单对象;不属于本商户或不存在返回 404,不泄露其他商户订单。平台 id 必须为 UUID,商户单号是创建时提交的 outTradeNo。请对商户单号进行 URL 路径编码。
POST /orders/{id}/cancel
发送 {}。仅 pending 可取消;同一已取消订单重复取消返回原订单(200)。已付款、过期或已退款返回 409。取消不涉及积分变动。
网页后台全额退款
商户公开 API 不提供退款操作,API 密钥不能发起退款。商户须登录 订单管理,打开已付款订单,点击全额退款,核对原付款账户和金额并确认。仅 paid 可全额退款,金额与收款人由原订单固定。商户可用积分不足或原付款人账户容量不足时退款失败,订单仍为 paid;补足余额后可在网页重试。成功后状态为 refunded,并生成 refundReference;重复或并发确认只退款一次。退款回到原付款人的平台积分账户,不是链上 USDC 退款。服务端可继续查询退款状态,或接收 order.refunded Webhook。
4. 订单响应字段
{
"id":"0e4c7267-fcea-4b73-9f5f-e7be0e8597df",
"cursor":"51",
"merchantId":"7a08d8c2-a91c-44bb-8f4a-d1514906ca04",
"outTradeNo":"SHOP-20261104-001",
"title":"示例商品",
"amount":"1.250001",
"amountMicros":"1250001",
"currency":"POINTS",
"status":"paid",
"checkoutUrl":"https://你的平台域名/checkout/0e4c7267-fcea-4b73-9f5f-e7be0e8597df",
"paymentReference":"0d004a7d-09c3-45c2-8c39-c6130de8fcd0",
"refundReference":null,
"createdAt":1793750400,
"expiresAt":1793752200,
"paidAt":1793750420,
"refundedAt":null
}| 字段 | 说明 |
|---|---|
| id / merchantId | 平台订单 UUID / 商户 UUID |
| cursor | 创建顺序游标,分页使用 |
| outTradeNo / title | 原商户单号 / 展示标题,创建后不能修改 |
| amount / amountMicros | 积分十进制字符串 / 最小单位整数的字符串 |
| source | 订单来源:shop 为商城订单,api 为 API / 商户收款订单;不能通过修改订单号前缀伪造来源。 |
| currency | 固定 POINTS,不能传入其他币种 |
| status | 见状态表 |
| checkoutUrl | 平台托管收银台地址;必须使用部署后的真实域名配置 |
| paymentReference | 付款转账流水 UUID,付款前为 null,退款后仍保留 |
| refundReference | 退款转账流水 UUID,退款前为 null |
| createdAt / expiresAt | 创建及截止时间,Unix 秒 |
| paidAt / refundedAt | 支付及退款完成时间,未发生时为 null |
5. 状态、幂等和一致性
| 状态 | 含义 | 可操作 |
|---|---|---|
| pending | 待用户确认 | 用户付款、商户取消、到期转 expired |
| paid | 已完成积分扣款及商户入账 | 登录网页后台全额退款 |
| cancelled | 已取消,未扣款 | 终态 |
| expired | 已过期,未扣款 | 终态;重新创建须使用新单号与新幂等键 |
| refunded | 已全额退回原付款人 | 终态 |
- 同一商户 Idempotency-Key 和 outTradeNo 均唯一。相同键重试要求 title、amount、outTradeNo、expiresInSeconds 相同(金额按数值比较)。不同键重用已有 outTradeNo 返回 409;相同键改参数也返回 409。
- 创建重试不会重置有效期。创建重试返回的状态可能由后续查询或付款更新,应以查询结果判断当前状态。
- API 取消、网页退款按平台订单 id 天然幂等;公开 API 不提供退款操作。对一笔 paid 订单只有一次完整退款。
- 订单状态、双方余额、转账流水、审计在同一数据库语句及触发器中完成;任一环节失败整笔回滚。多人同时支付只允许一个付款账户成功,不会重复扣款。
- 商户可被管理员停用。停用期间密钥接口、收银台支付和网页退款不可用,原有流水保留,恢复后密钥可继续使用(已撤销密钥除外)。
6. HTTP 状态和错误处理
{"error":{"code":"idempotency_conflict","message":"请求编号或商户订单号已用于其他订单",
"requestId":"本次请求诊断UUID"}}| HTTP | code | 处理方式 |
|---|---|---|
| 400 | invalid_request | 修正参数、UUID、金额字符串或有效期 |
| 401 | invalid_api_key | 检查密钥是否完整、属于正确环境及未撤销 |
| 403 | merchant_disabled / merchant_required | 检查商户状态或联系管理员 |
| 404 | order_not_found / not_found | 检查单号及所属商户,不要切换其他用户密钥查询 |
| 409 | idempotency_conflict | 用原单号查询;不要为同一订单盲目改幂等键 |
| 409 | invalid_order_state | 重新查询订单,按状态表处理 |
| 429 | rate_limited | 停止高频调用,稍后指数退避重试 |
| 500 | internal_error | 保留原参数与幂等键,查询原订单后重试,记录 requestId |
全局请求限制:JSON 请求体最多 8 KiB,超出返回 413;非 JSON POST 返回 415。这类请求在鉴权前被拒绝,可能返回简单 {"error":"说明"},接入方须同时检查 HTTP 状态,不要假设所有错误响应都是成功订单结构。超时或断网不等于订单创建失败、支付失败或退款失败,必须查询原订单确认。
7. 确认到账、轮询和业务交付
付款用户若在账户安全中启用了两步验证,邮箱或 Google 首次验证后还须完成动态码登录;已设置的支付密码及两步验证也用于收银台付款和网页退款确认。商户 API 不接收用户支付密码或动态码,不能代扣用户余额或发起退款。
- 将 outTradeNo、平台 id、预期 amountMicros、merchantId 和创建时的 Idempotency-Key 持久化到你的业务数据库。
- 用户在独立窗口或当前窗口打开 checkoutUrl;该地址支持未登录时登录后返回原订单。不要将 API 密钥拼到链接中。
- 你的后端按平台 id 查询,建议单订单 5–10 秒一次、逐步退避,并在所有订单之间共享 120 次/分钟预算。大量订单时使用集中队列;列表接口用于对账,不要让每个浏览器独立高频轮询。
- 只有后端使用 Bearer 查询得到 paid,且 merchantId、outTradeNo、amountMicros、currency 均与业务记录一致时才交付。用你的数据库唯一键/事务确保同一商户订单号只交付一次。
- pending 继续等待;expired / cancelled 停止等待;refunded 按你的售后规则处理。用户关闭收银台或浏览器显示“成功”均不能替代服务端查询。
- 需要退款时,商户登录网页订单后台确认全额退款;服务端通过订单查询或 order.refunded Webhook 确认结果并记录 refundReference,不能使用 API 密钥发起退款。
可通过签名 Webhook 触发后端查询,并用低频轮询补齐遗漏。请按下方 Webhook 协议验签与去重,不能直接信任浏览器或未验签的通知。网络失败时不要先发货,也不要新建多笔同额订单作为补偿。商户 API 的积分收款与链上充值、USDC 提现是不同流程。
8. Node.js 服务端示例
需要 Node.js 22+。下载上方客户端,环境变量 MERCHANT_API_BASE 包含 /api/merchant/v1,MERCHANT_API_KEY 为服务端密钥。
import { MerchantClient } from './merchant-client.mjs';
import { randomUUID } from 'node:crypto';
const client = new MerchantClient(process.env.MERCHANT_API_BASE,
process.env.MERCHANT_API_KEY);
// 将请求编号与商户单号一起持久化;重试时从数据库读取同一个值。
const requestId = randomUUID();
const order = await client.createOrder({
outTradeNo: 'SHOP-20261104-001', title: '示例商品',
amount: '1.250001', expiresInSeconds: 1800
}, requestId);
console.log(order.checkoutUrl); // 提供给用户,不包含密钥
const current = await client.getOrder(order.id);
if (current.status === 'paid' && current.amountMicros === '1250001') {
// 校验 merchantId 和商户单号,再在你的业务数据库中幂等交付。
}
// 退款请登录网页商户订单后台操作;API 仅查询退款结果。curl 查询与取消
curl "$BASE/account" -H "Authorization: Bearer $KEY"
curl "$BASE/orders/$ORDER_ID" -H "Authorization: Bearer $KEY"
curl "$BASE/orders/by-number/SHOP-20261104-001" -H "Authorization: Bearer $KEY"
curl "$BASE/orders?before=51" -H "Authorization: Bearer $KEY"
curl "$BASE/orders/$ORDER_ID/cancel" -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" -d '{}'9. 密钥轮换、上线与验收
先创建新密钥、更新你的后端环境变量并确认查询正常,再撤销旧密钥。撤销后新的 API 请求立即拒绝,已经进入处理的请求可能完成。密钥不支持找回明文,泄露时立即撤销。
平台运营方为新数据库执行统一初始化文件 migrations/0001_initial.sql(本地 npm run db:local,线上 npm run db:remote;已有数据库按项目 README 的旧库接续说明处理),将 APP_ORIGIN 设置为真实 HTTPS 域名并部署代码及静态资源。商户端必须使用 HTTPS,localhost 仅用于本地测试。文档没有独立沙箱域名;本地测试请使用隔离数据库和虚拟积分。上线验收覆盖创建重试、登录返回收银台、确认付款、服务端查询交付、取消、过期、全额退款、余额不足、越权查询及密钥撤销。
本接口版本为 v1,新增可选响应字段应被客户端忽略。公开退款接口已按权限策略移除,退款统一在网页登录后操作;退款结果字段、查询和回调继续保留。
10. Webhook 配置、签名、重试与补偿
平台运营配置
- 新数据库执行
npm run db:local(线上npm run db:remote),统一初始化已包含 Webhook 表和触发器。已有旧库先按 README 补齐原有迁移,保留业务数据和迁移记录。 - 用
node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"生成 32 字节随机十六进制加密密钥,本地填入 .dev.vars 的WEBHOOK_ENCRYPTION_KEY;线上执行npx wrangler secret put WEBHOOK_ENCRYPTION_KEY。该密钥用于 AES-GCM 加密商户签名密钥,必须备份、长期保留,不能直接替换。更换需先做密文重加密迁移。 - 在 wrangler.jsonc 的
WEBHOOK_ALLOWED_HOSTS填入运营方审核的精确域名,用英文逗号分隔,例如pay.your-shop.com,notify.another-shop.com。不支持通配符;请确认这些域名及其 DNS 指向由可信商户控制且始终为公网服务,不能加入内网转发域名。空值拒绝所有目标;设置启用或新地址时和每次投递前均检查。HTTPS 默认 443,拒绝 IP、账号密码、片段、localhost,且不跟随 3xx。不得加入泛域名代理、公共回显服务或会转发到内网的站点。 - 部署并启用每分钟 Cron。每轮最多 20 个事件,4 路并发,单次请求 10 秒超时;有积压时首投和重试会延迟,需监控投递记录。
商户设置接口
商户中心可直接配置,也可用 Bearer API:GET /webhook 返回当前配置;首次未配置返回 {"url":"","enabled":false,"version":null,"updatedAt":null}。POST /webhook 请求:
{"url":"https://pay.your-shop.com/webhooks/upoints","enabled":true,
"version":null,"rotateSecret":false}url、enabled、version 必填;首次 version 为 null,以后必须使用 GET 返回的 version,配置并发变化返回 409。rotateSecret 可选,默认 false。成功返回 url、enabled、version、updatedAt,首次配置、换地址或 rotateSecret=true 时额外返回 secret: "whsec_...",仅本次显示。此签名密钥与 API Bearer 密钥不同;完整 whsec_ 字符串作为 HMAC 密钥,不能去前缀或按十六进制解码。不保存于浏览器存储。
配置实际变更(包括启停、换地址和轮换)会取消之前未成功的事件;重复保存相同配置不会变更版本或取消事件,不能补发已取消事件;已经发出的网络请求无法撤回。停用商户会暂停后续投递。设置启用后仅收集新发生的支付与退款;不会追溯生成历史事件。变更时先暂停业务流量并通过订单查询补偿;生成新签名密钥后立即配置商户接收器,未配置期间请求可能验签失败,自动重试会恢复。配置响应超时导致密钥未收到时,GET 不返回明文,需刷新版本并主动轮换。
事件与 HTTP 协议
回调是 HTTPS POST、Content-Type: application/json,事件类型为 order.paid 和 order.refunded。无取消/过期事件。支付或退款的账本更新与事件写入在同一 D1 原子语句中,失败全部回滚;投递失败不会回退已成功付款或退款。
X-UPoints-Event-ID: evt_0123456789abcdef0123456789abcdef X-UPoints-Timestamp: 1793750400 X-UPoints-Signature: v1=<64 位小写十六进制 HMAC-SHA256>
{
"id":"evt_0123456789abcdef0123456789abcdef",
"type":"order.paid","createdAt":1793750400,"merchantId":"商户UUID",
"apiVersion":"2026-11-04",
"data":{
"id":"订单UUID","merchantId":"商户UUID","outTradeNo":"SHOP-001",
"title":"示例商品","amount":"1.250001","amountMicros":"1250001",
"currency":"POINTS","status":"paid","paymentReference":"转账UUID",
"refundReference":null,"createdAt":1793750300,"expiresAt":1793752100,
"paidAt":1793750400,"refundedAt":null
}
}data 是订单在该次事件发生时的固定快照(不包含列表 cursor、checkoutUrl);退款事件 type=order.refunded、data.status=refunded,refundReference/refundedAt 有值并保留原 paymentReference/paidAt。事件不含邮箱、钱包私钥或 API 密钥;所有时间均为 Unix 秒。
验签与安全交付
- 读取未经改写的原始 HTTP 请求体字节,保留中文、空格、字段顺序。用 HMAC-SHA256 对
timestamp + "." + rawBody签名,密钥为完整 secret 的 UTF-8 字节,结果小写十六进制加 v1= 前缀。禁止将解析后的 JSON 重新序列化后验签。 - 严格解析 timestamp 和签名格式,将 timestamp 与当前 Unix 秒比较,时间差不得超过 300 秒,保持服务器校时;使用恒定时间比较。重试使用新的发送 timestamp 和签名,event.createdAt 仍是原时间。
- 验签后解析 JSON,核对头部事件 ID 与 body.id、merchantId 与 data.merchantId。以 body.id 唯一键持久化入队后返回任意 2xx,建议 204;重复事件返回 2xx。非 2xx、超时、网络异常均视为失败,响应体不作判断。
- 业务处理器按本地商户订单号核对订单、merchantId、currency、amountMicros,再通过 Bearer 查询当前订单。只有当前仍为 paid 才交付;refunded 按售后规则处理。同一订单的业务操作需唯一键/事务幂等,将业务更新与处理标记原子提交。未验证签名或金额不符绝不交付。
下载 merchant-webhook.mjs,用 Node.js 22.13+(推荐 24)运行:设置环境变量 WEBHOOK_SECRET、MERCHANT_ID,可选 WEBHOOK_DB、PORT,然后 node merchant-webhook.mjs。示例在 127.0.0.1:3001 的 /webhooks/upoints 接收并持久化至 SQLite inbox,需由你的 HTTPS 反向代理公开该路径。它不自动发货;请在你的业务处理器中消费 inbox 并完成上述校验和幂等事务。多实例接收器应使用共享持久数据库。
重试、顺序与人工补偿
系统提供至少一次投递,同一事件的 ID 和请求体保持不变,可能重复或乱序,尤其支付与紧随其后的退款可同时到达;不能依赖到达顺序或旧快照判定当前状态。持久化 inbox 后尽快返回成功,耗时业务异步处理。接收器异常前可能已经提交业务,所以即使上次超时仍必须去重。
每轮自动最多 8 次尝试(首次加 7 次重试),失败间隔依次为 60、300、900、3600、10800、21600、43200 秒。Cron 每分钟检查,实际执行不会早于 nextAttemptAt,有积压可更晚。第 8 次失败后 status=failed;投递进程崩溃的租约 120 秒后恢复,已消耗的尝试次数不回退。
| 接口(均需本商户 Bearer) | 说明 |
|---|---|
| GET /webhook/events?before={cursor} | 倒序列表,每页最多 50 条;data、nextBefore 分页 |
| GET /webhook/events/{eventId} | 包含 event 原始快照及最近 50 次 deliveryAttempts |
| POST /webhook/events/{eventId}/retry,JSON {} | 仅失败且仍为当前启用配置的事件可重新入队;pending 重复调用幂等;已成功、取消、处理中返回 409。每商户 10 次/分钟 |
列表字段:id、cursor、orderId、type、url、status(pending/processing/delivered/failed/cancelled)、attempts(本轮次数)、totalAttempts(终身次数)、nextAttemptAt(仅待发送/处理中,否则 null)、lastHttpStatus、lastError、createdAt、deliveredAt。详情额外 event、deliveryAttempts;每次记录 attempt、startedAt、finishedAt、httpStatus、error。手动补发重置本轮 attempts,保留总次数和旧日志;不会改变订单或重复扣款。平台不保存响应体、签名或明文签名密钥。processing 的 nextAttemptAt 是本轮原定时间,lease 到期恢复不代表接收器未处理。
错误码:400 invalid_webhook_url / webhook_host_not_allowed / invalid_request;409 webhook_config_conflict / webhook_retry_conflict;404 webhook_event_not_found;503 webhook_not_configured;429 rate_limited。投递日志常见原因 timeout、http_XXX、network_or_signing_error、lease_expired、configuration_changed。配置变更、服务中断、未启用回调或队列积压时,用订单接口低频查询对账补齐;不要将通知作为唯一账本。
商户名称与商城库存
在平台网页的商户中心可修改显示名称,商城链接、商户 ID 和 API 密钥不变,收银台将显示新名称。商城购买支持每单 1–100 件;同一买家重复点击完全相同且未过期的未付款订单时复用原单,整单扣款并按数量自动发货。商城订单查询额外返回 quantity(件数)和 unitAmountMicros(下单时单价的最小单位字符串),amountMicros 为整单总额。商品与库存页面提供状态筛选、数量统计、编号搜索、未售卡密核对及批量停用/恢复;停用库存不再参与发货,已售库存和退款后的原交付记录保持锁定。敏感操作沿用已开启的安全验证并记录审计。
以上功能仅在登录后的网页后台操作,不属于本 Bearer API。公开订单、Webhook 和商品列表均不返回卡密内容。