首页/接入第三方充值 / 发卡 API
开发文档

接入第三方充值 / 发卡 API

最近更新:2026-10-08

一句话总结

默认走内置 Mock 供应商。接真实上游:填环境变量,重启,不改代码。

1. 上游只需要提供五种能力

能力对应方法用途
拉目录pullCatalog()同步价格、库存、缺货状态
查库存fetchStock(ids)下单前校验
下单createOrder(req)带幂等键,同步返回或异步发货
查单queryOrder(id)Webhook 之外的兜底轮询
回调verifyWebhook()异步交付结果的主路径

2. 环境变量

UPSTREAM_ENABLED=true
UPSTREAM_ADAPTER=rest
UPSTREAM_BASE_URL=https://api.supplier.example
UPSTREAM_API_KEY=xxxxxxxx
UPSTREAM_API_SECRET=yyyyyyyy
UPSTREAM_SIGNATURE=hmac_sha256   # none|bearer|header_key|query_key|hmac_sha256|md5

UPSTREAM_PATH_CATALOG=/api/products
UPSTREAM_PATH_CREATE_ORDER=/api/order/create
UPSTREAM_PATH_QUERY_ORDER=/api/order/query

UPSTREAM_MAPPING_JSON='{"itemsPath":"data.list","fields":{"externalId":"id","title":"name","price":"price","stock":"stock","soldOutFlag":"sold_out"},"order":{"orderIdPath":"data.order_no","contentPath":"data.content"}}'

3. 签名做了什么

hmac_sha256 策略:把请求体按参数名排序拼成 k1=v1&k2=v2,尾部拼上 API Secret 再取摘要。这是国内绝大多数平台的通行做法,md5 是老平台的变体。

Webhook 验签采用 constant-time 比较,并校验时间戳容忍窗口,防止重放。

4. 字段映射怎么填

  • itemsPath:响应里数组所在的路径,例如 data.list。
  • fields.externalId:商品唯一标识,会与站内商品的 upstream_ref 对齐。
  • soldOutFlag / soldOutWhen:不同平台表达缺货的方式五花八门(布尔、字符串、库存为 0),用这两个字段统一。
  • order.contentPath:交付内容所在路径,字符串按行拆成多条凭证,数组按元素拆。

5. 换一家有多快

如果新平台的接口形态仍在这五个能力内:只改环境变量,代码零改动。

如果它比较另类(比如 SOAP、私有二进制协议、需要登录态会话):新增一个实现 UpstreamAdapter 的文件,在工厂里注册,其余层完全无感。

6. 自检

GET /api/upstream/health

返回当前生效的配置摘要、健康状态、目录条数。接新供应商后先看这个接口。

7. 稳定性策略

  • 超时 + 退避重试:默认 10s 超时,最多重试 2 次。
  • 下单不激进重试:避免重复发货,只重试 1 次。
  • 目录缓存:默认 60s。上游抖动时返回上一次结果并标记 stale,页面不白屏。
  • 幂等键:订单号-行号,同一笔重复提交只产生一个上游单。

8. 代码位置

lib/server/upstream/types.ts         # 接口契约(五种能力)
lib/server/upstream/mock-adapter.ts  # 本地供应商
lib/server/upstream/rest-adapter.ts  # 通用 REST 适配器
lib/server/upstream/index.ts         # 门面:缓存、降级、错误处理
lib/server/env.ts                    # 全部配置项
lib/server/http.ts                   # 超时/重试/幂等
lib/server/signature.ts              # 签名与 Webhook 验签
app/api/upstream/health/route.ts     # 自检接口
app/api/upstream/webhook/route.ts    # 异步回调入口