邦斧开放平台 · 对外接口文档 v1
版本:v1.5.1 · 2026-10-12
适用:接入方(乙方)对接邦斧开放平台「会员资产与激励体系」开放能力
文档状态:契约已冻结。签名规则、错误码语义一经发布不再变更,只允许新增。
维护方:邦斧开放平台 · 技术支持:见附录 F
文档导航(先看这里,按角色选读)
| 你的角色 | 建议阅读顺序 | 预计耗时 |
|---|---|---|
| 技术负责人 / 架构 | §0.3 业务资产模型 → §一 接口总览 → §五 鉴权 → §四 签名 → §八 幂等重试 → 附录 B 数据字典 | 40 分钟 |
| 后端开发(要写代码) | §三 5 分钟跑通 → §2.2 沙箱测试账号 → §四 签名算法(含多语言示例)→ §六~§八 接口与错误码 → 附录 A 参数速查 → 附录 E curl 集合 | 1.5 小时 |
| 测试 / 联调 | §2.2 沙箱测试账号 → §十四 沙箱环境 → §十三 排查 → 附录 D 问题排查手册 → 附录 E curl 集合 | 40 分钟 |
| 产品 / 业务 | §0.3 业务资产模型 → §一 接口总览(只看"用途"列)→ 附录 C 端到端时序 | 20 分钟 |
| 合规 / 法务 | §十七 合规要求 → §6.12 个人信息通道 → 附录 F 服务条款 | 20 分钟 |
三条最省时间的提示(很多对接方在这里绕远路):
- 先用沙箱账号把链路打通(§2.2 直接给了可用凭证),不要拿生产凭证等开通流程。
- 先用 §4.4 的自检数据验签名,再写业务代码 —— 签名错会导致"所有接口都报 40002",很难定位。
- 本平台不做回调(§0.2.4),不用写回调验签/状态机;上报结果用
order/query主动查。
〇、接口总览
共 20 个接口(其中 10 个是「只读查询类」:#2 #5 #6 #9 #10 #13 #14 #18 #19 #20 —— 只读不写、不需要幂等键、 随便调不会改任何数据)。建议按「先连通 → 再绑会员 → 再报业务 → 用查询类对账」的顺序接入。
0.1 一张表看懂所有接口
| # | 方法 | 路径 | 用途 | 优先级 | 改资产 | 幂等键 |
|---|---|---|---|---|---|---|
| 1 | POST | /open/v1/auth/token | 签发令牌(2 小时) | 必接 | — | — |
| 2 | POST/GET | /open/v1/ping | 连通性自检 | 必接 | — | — |
| 3 | POST | /open/v1/member/bind | 绑定外部会员 | 必接 | — | out_uid |
| 4 | POST | /open/v1/member/unbind | 解绑 | 可选 | — | out_uid |
| 5 | GET | /open/v1/member/profile | 会员资料(已脱敏) | 建议 | — | — |
| 6 | GET | /open/v1/member/balance | 积分与券余额 | 必接 | — | — |
| 7 | POST | /open/v1/order/consume | 上报消费(让利入池 + 发积分) | 必接 | ✔ | out_order_id + seq |
| 8 | POST | /open/v1/order/refund | 退款回冲(含扣回积分) | 建议 | ✔ | out_order_id + seq |
| 9 | GET | /open/v1/pool/summary | 奖励池概览(只读) | 可选 | — | — |
| 10 | GET | /open/v1/integral/logs | 积分流水 | 可选 | — | — |
| 11 | POST | /open/v1/integral/adjust | 积分人工调整(默认关) | 可选 | ✔ | out_order_id + seq |
| 12 | POST | /open/v1/member/data-request | 个人信息合规通道 | 可选 | ✔ | out_order_id + seq |
| 13 | GET | /open/v1/coupon/balance | 券余额 | 可选 | — | — |
| 14 | GET | /open/v1/coupon/logs | 券流水 | 可选 | — | — |
| 15 | POST | /open/v1/coupon/verify | 券核销(扣减) | 必接 | ✔ | out_order_id + seq |
| 16 | POST | /open/v1/coupon/unverify | 券回退(订单取消/退款) | 建议 | ✔ | out_order_id + seq |
| 17 | POST | /open/v1/coupon/transfer | 券转赠(默认关) | 可选 | ✔ | out_order_id + seq |
| 18 | GET | /open/v1/order/query | 按业务单号查处理结果(超时确认,只读) | 建议 | — | — |
| 19 | GET | /open/v1/member/list | 会员列表 + 各自资产(批量对账,只读) | 可选 | — | — |
| 20 | GET | /open/v1/billing/usage | 本期用量与账单(自己看成本,只读) | 可选 | — | — |
优先级说明:必接 6 个(不接则功能不完整)· 建议 4 个(退款、券回退、超时确认、会员资料)· 其余 可选。
最小可用接入 = 必接的 6 个,约 1 天可打通。
「改资产」= 会改变会员积分或券的接口。这类接口必须实现幂等(用上表的幂等键),
只有它们需要传
out_order_id;查询类接口不需要。
0.2 「改资产」接口的统一要求(三条,务必先看)
out_order_id必须是稳定的业务单号(不是随机串、不是时间戳)——
重复上报靠它去重;用随机串会导致同一笔钱被记两次。
- 金额一律整数分(
1000= 10 元)。全站不出现浮点金额。 - 重复调用是安全的:同幂等键再次提交会返回首次的结果并带
idempotent:true,不会重复记账。
所以超时后请放心重试(重试要换新 nonce,见 §4)。
0.3 ★★ 业务资产模型速览(先看懂这个,接口就顺了)
很多对接方卡住不是卡在技术,而是卡在这个资产模型没理解透。所以先讲它。
0.3.1 一张图看懂资产怎么流转
① 用户在你方商城下单,付款成功
│
▼
② 你方把「让利额」报给邦斧 ← 注意:报的是【让利额】,不是订单金额
│ 例:订单 200 元,让利 10% ⇒ 报 profit=2000(单位:分)
▼
③ 邦斧在同一瞬间做两件事
├── 让利额 进【商家奖励池】 ← 等平台按周期释放
└── 给该会员发【等额积分】 ← 1 元让利 = 1 积分
│
▼
④ 平台按周期自动释放(商家可配:每几天一批、每批释放池子的百分之几)
│
▼
⑤ ★ 释放的那一刻:【扣积分 + 发券】
│ 例:释放 20 元券 ⇒ 扣 20 ÷ 5 = 4 积分
│ ⇒ 积分 20 → 16 ;可用券 0 → 20 元
▼
⑥ 用户下笔消费时用券抵扣 ← ★ 只有券能抵扣,积分不能
0.3.2 三个必须记住的数字
| 关系 | 数值 | 说明 |
|---|---|---|
| 让利额 ↔ 积分 | 1 元 = 1 积分 | 让利 20 元 ⇒ 立即得 20 积分 |
| 积分 ↔ 券 | 1 积分 = 5 元券(反过来说:发 1 元券要扣 0.2 积分) | 所以 20 积分理论上最多释放出 100 元券(上限 = 积分 × 5) |
| 券 ↔ 抵扣 | 1 元券 = 1 元抵扣 | 券是可直接抵扣的余额;积分只是"待释放的额度" |
0.3.3 一个完整的数字实例(让利 20 元,每天一批、每批释放 50%)
| 时点 | 本批释放券 | 会员积分 | 会员可用券 | 说明 |
|---|---|---|---|---|
| 下单当时 | — | 20 | 0 | 让利入池 + 发等额积分 |
| 第 1 批 | 10 元 | 20 − 2 = 18 | 10 元 | 扣 10÷5 = 2 积分 |
| 第 2 批 | 5 元 | 18 − 1 = 17 | 15 元 | 扣 5÷5 = 1 积分 |
| 第 3 批 | 2.5 元 | 16.5 | 17.5 元 | 持续释放… |
关键现象:会员的「积分在减少、券在增加」。 积分是"还没兑现的额度",券才是"到手能花的钱"。
0.3.4 为什么这么设计(业务视角)
如果让利一进来就全额变券,商家当月现金压力大、用户也可能拿完就走。所以设计成先入池、再分期释放: 用户为了拿到后续的券会持续回来消费 —— 这就是这套体系的锁客作用。
0.3.5 三个最常见的误解(提前澄清)
| 误解 | 实际 |
|---|---|
| ❌ "我报订单金额" | ✅ 报的是 profit 让利额,即你愿意拿出多少钱做锁客 |
| ❌ "积分能当钱花" | ✅ 积分不能抵扣任何消费,只有券能抵扣 |
| ❌ "报了要等平台回调通知" | ✅ 平台不做回调,接口同步返回,返回成功即已记账;要确认用 order/query |
0.3.6 技术层面为什么不难
| 项 | 情况 | 对贵司的好处 |
|---|---|---|
| 接口形态 | 标准 HTTP + JSON(RESTful) | 任何语言都能调,不需要 SDK |
| 鉴权 | HMAC-SHA256 签名 + 访问令牌 | 业界通用,后端 20 行代码可完成 |
| 回调 / 消息队列 | 完全没有 | 不写回调验签、不处理乱序重复、不做状态机 |
| 异步处理 | 完全没有 | 每个接口同步返回,返回即结果 |
| 定时任务 | 平台侧自动跑(释放券) | 贵司无需实现任何定时逻辑 |
| 实际要接的 | 6 个必接 + 4 个建议(共 20 个接口) | 见 §一 接口总览的分级 |
〇之二、术语与公共字段
先看这一节,后面所有接口都只列"业务字段",不再重复公共字段。
0.2.1 术语表(对接必读,避免理解偏差)
| 术语 | 含义 | 说明 |
|---|---|---|
appid | 接入方标识 | 平台发给贵司的公开标识,可出现在 URL 里 |
appsecret | 接入方密钥 | 只用于取令牌,绝不放进 URL、绝不进日志 |
access_token | 访问令牌 | 有效期 2 小时,业务接口鉴权用;过期重新取 |
out_uid | 贵司的会员标识 | 贵司会员体系里的用户 ID。我方只认它,全站必填 |
mid | 我方的会员 ID | 邦斧侧内部 ID。只在返回里出现,贵司不需要存(除对账倒查) |
out_order_id | 贵司的订单/业务单号 | 幂等键。一笔业务一个,必须稳定唯一 |
seq | 同单序号 | 同一 out_order_id 多次业务(如部分退款)时递增,从 1 开始 |
request_id | 单次请求标识 | 防"同一请求被网络重发"。重试时必须换新的 |
profit | 让利额 | 本单愿意让出的金额(分)。入池的就是这个数 |
member_profit | 消费者侧份额 | 会员分到的部分(分)。不传 = 等于 profit |
| 让利 | — | 订单里拿出来做激励的那部分钱。入池=记进奖励池;出批/派发=按周期变成券发给会员 |
| 奖励池 | — | 按商家隔离的让利池。贵司一个商家对应一个池 |
| 消费券 | — | 会员可抵扣的券,来自奖励池派发。不支持提现,支持转赠 |
| 积分 | — | 与让利额 1:1 记录,是释放券的依据;会员体系在贵司侧 |
★ 常见误解纠正:
· 「入池」不等于「发券」—— 入池只是记账,券要等出批才发到会员手上(有周期)。
· 积分与券是两笔不同的资产,不要混为一谈。
· 券是商家专属的:只能在贵司商城抵扣,与邦斧其他商家无关。
0.2.2 公共请求参数(所有接口都要带)
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
appid | URL query | string | 是 | 接入方标识 |
timestamp | URL query | int | 是 | 当前 Unix 秒级时间戳。与服务器相差超过 ±300 秒会被拒(40003) |
nonce | URL query | string | 是 | 随机串(建议 16 位随机 hex)。同一 nonce 5 分钟内不可重复,否则报 40004 |
X-Open-Sign | Header | string | 是 | 签名,算法见 §4 |
X-Open-Token | Header | string | 业务接口是 / auth/token 否 | 访问令牌。取令牌时用 appsecret 自身验签 |
request_id | Body 或 query | string | 否(强烈建议) | 幂等辅助;填了就按它去重,超时重试请换新值 |
Content-Type | Header | — | POST 是 | application/json |
0.2.3 公共响应字段(所有接口统一)
{ "code": 0, "msg": "成功", "data": { }, "request_id": "本次请求的 request_id(回显)" }
| 字段 | 类型 | 说明 |
|---|---|---|
code | int | 0 表示成功;非 0 见 §七 错误码表。请只判 code,不要判 msg 文本 |
msg | string | 给人看的中文提示,不要用于程序判断(措辞可能优化) |
data | object/null | 业务数据;失败时为 null |
request_id | string | 回显贵司传的 request_id,便于双方对账定位 |
msg会写进用户界面吗?不会 —— 它是给贵司技术人员排障看的。面向消费者的文案请贵司自己组织。
0.2.4 ★★ 交互模式:本平台不做回调,全部同步返回
这一点请务必先知道,可以省掉大量对接工作:
- 没有异步回调,也没有「事件推送」「等待通知」「回调地址配置」这些东西。
- 每个接口都是同步的:调用返回时,结果就已经确定了(成功即已记账)。
- 因此贵司不需要:配回调 URL、写回调签名验签、处理回调乱序/重复、做"上报后等通知"的状态机。
- 唯一需要异步处理的是券的发放:上报消费后,券要等平台的释放周期才发到会员手上
(这是业务规则,不是接口延迟)。贵司只需定时查 coupon/balance 即可,不要轮询上报接口。
★ 那"上报超时了,到底记上没有"怎么确认? 用 GET /open/v1/order/query(#19)—— 按业务单号主动查、只读无副作用地看到这笔的处理结果(是否入池、发了多少积分、券动作、是否已退款作废)。 它和"重复提交同一单号"是两条并行的确认路径,任选其一或都用:
| 想确认的事 | 用哪个 | 特点 |
|---|---|---|
| 这笔处理成功了吗? | order/query | 纯查询,不会产生任何副作用;查不到也不代表失败(可能还在路上) |
| 重发会不会记两笔? | 直接重发同 out_order_id+seq | 有幂等保护,返回首次结果并带 idempotent:true,不会重复记账 |
如果贵司业务上确实需要"券发到手"的即时通知,属于新增回调能力,需另行评审与排期
(涉及重试、乱序、幂等一整套机制),请先与平台对接人确认。
0.2.5 超时与重试建议
| 项 | 建议值 |
|---|---|
| 连接/读取超时 | 连接 3 秒、读取 10 秒 |
| 重试次数 | 最多 3 次,间隔 1s / 2s / 4s(指数退避,或按响应头 Retry-After) |
| 重试必做 | 换新 nonce(否则报 40004);request_id 也建议换新;out_order_id/seq 保持不变 |
收到 42901 | 按 Retry-After 退避,不要固定 sleep |
收到 50001 | 可重试;连续失败请联系平台并提供 request_id |
| 超时后不确定结果 | 先调 GET /open/v1/order/query 查这笔的处理结果(只读);要重发就用同一 out_order_id+seq |
0.2.6 精度与金额口径(★ 最容易出 100 倍错误的地方)
- 接口层全部用整数分:
profit: 1000= 10.00 元。不要传小数。 - 积分是
decimal(15,4)(带 4 位小数),返回时以字符串给出,请勿当浮点数运算后取整(会丢资产)。 - 券余额同时给分与元两个字段(如
coupon_usable_cents/coupon_usable),请用分那个做计算。
一、5 分钟跑通(先做这一步)
对接第一件事不是写业务,是先确认网络、凭证、签名算法三者都对。按下面四步走。
第 1 步:拿到凭证
向平台方索取:
| 名称 | 说明 |
|---|---|
appid | 应用 ID(对外可见) |
appsecret | 应用密钥(只在发放时显示一次,请妥善保存) |
⚠️ 凭证可用有三个前提,缺一个都调不通:
| 前提 | 缺了会怎样 |
|---|---|
| ① 接入方已被平台开通(不是建好就行) | 40102 服务已停止 |
| ② 已签署《客户合规承诺书》(开通的前提就是已签约) | 未签约则平台无法开通 ⇒ 仍是 40102 |
| ③ 用的是对应环境的凭证(测试/沙箱/生产不通用) | 40101 appid 不存在 |
想「先验通链路再走签约」?请向平台方要【沙箱凭证】。 沙箱接入方免签约、免开通,拿到即可联调(详见第十一节)。正式凭证必须走完「签约 → 平台开通」才能使用。
第 2 步:算签名
// PHP 示例
$ts = time(); // 10 位秒级时间戳
$nonce = bin2hex(random_bytes(8)); // 16 位随机串,5 分钟内不可重复
$rid = ''; // 取令牌时不传 request_id
$body = json_encode(['appsecret' => $appsecret]);
$payload = implode("\n", [$appid, $ts, $nonce, $rid, hash('sha256', $body)]);
$sign = hash_hmac('sha256', $payload, $appsecret);
第 3 步:取令牌
auth/token 用 appsecret 自身鉴权(请求体里要带 appsecret),签名也用 appsecret 算。
curl -s -X POST "http://<平台地址>/open/v1/auth/token?appid=<appid>×tamp=<ts>&nonce=<nonce>" \
-H "Content-Type: application/json" \
-H "X-Open-Sign: <用 appsecret 算出的 sign>" \
-d '{"appsecret":"<appsecret>"}'
# 期望返回:
# {"code":0,"msg":"签发成功","data":{"access_token":"...","expires_in":7200,"token_type":"Bearer","appid":"..."},"request_id":""}
拿到 access_token 就是第 3 步成功。 若返回 40001,多半是请求体里的 appsecret 没被发出去(检查 Content-Type: application/json)。
第 4 步:打 ping 验证链路
ping 是业务端点:令牌放 X-Open-Token 头,签名改用 access_token 作密钥(不是 appsecret,这里最容易搞反)。
curl -s -X POST "http://<平台地址>/open/v1/ping?appid=<appid>×tamp=<ts2>&nonce=<nonce2>" \
-H "X-Open-Sign: <用 access_token 算出的 sign>" \
-H "X-Open-Token: <access_token>"
# 期望返回:
# {"code":0,"msg":"pong","data":{"appid":"...","rate_limit":600,"rate_used":1,...},"request_id":""}
看到 {"code":0,"msg":"pong",...} 就通了 —— 一次性确认了四件事:① 网络与路由可达 ② 凭证正确 ③ 签名算法一致 ④ 令牌有效。若不通,按 code 查第七节错误码表,常见问题见第十四节。
二、环境地址与沙箱测试账号
2.1 环境地址
| 环境 | 地址 | 说明 |
|---|---|---|
| 生产环境 | https://a.jetu.cc | 正式对接使用(用正式 appid) |
| 沙箱环境 | 同一地址 https://a.jetu.cc | 联调与演示使用(用沙箱 appid)。沙箱数据挂在沙箱专用商家名下,不会进入任何真实商家的积分与抵用券账本 |
所有接口均在
<地址>/open/v1/之下。生产环境启用 HTTPS。
2.2 ★★ 沙箱测试账号(可直接用,无需申请)
为了让贵司拿到文档当天就能动手,我们直接提供一个可用的沙箱账号:
| 项 | 值 |
|---|---|
| 环境地址 | https://a.jetu.cc |
appid | bfop261012c8ab974b60 |
appsecret | bab2b513dee1dd7e65ad75804f1bb84f7ef50a1e96fd956b |
| 数据范围 | 仅沙箱专用商家的数据(碰不到任何真实客户商家的数据) |
这个账号的限额(刻意压到最低,防止误用):
| 项 | 沙箱值 | 生产默认值 |
|---|---|---|
| 限流 | 30 次/分钟(单接口 10 次/分钟) | 600 次/分钟 |
| 单笔发券上限 | 10 元 | 1000 元 |
| 单日累计发券上限 | 50 元 | 10000 元 |
| 积分人工调整 | 关闭 | 默认关闭,需平台开启 |
| 个人信息匿名化 | 关闭 | 默认关闭,需平台开启 |
| 券转赠 | 开启(便于体验) | 默认关闭,商户后台可开 |
| 计费 | 不计费 | 按合同 |
拿到账号后 60 秒自测(复制即可跑):
# 1) 取令牌(把 <ts> 换成当前秒级时间戳、<nonce> 换成任意随机串)
curl -s "https://a.jetu.cc/open/v1/auth/token?appid=bfop261012c8ab974b60×tamp=<ts>&nonce=<nonce>" \
-X POST -H "X-Open-Sign: <按 §4 算出的签名>" -H "Content-Type: application/json" \
-d '{"appsecret":"bab2b513dee1dd7e65ad75804f1bb84f7ef50a1e96fd956b"}'
# 2) 连通性自检(把 <token> 换成上一步的 access_token)
curl -s "https://a.jetu.cc/open/v1/ping?appid=bfop261012c8ab974b60×tamp=<ts>&nonce=<nonce>" \
-H "X-Open-Token: <token>" -H "X-Open-Sign: <按 §4 算出的签名>"
期望:第 2 步返回 {"code":0,"msg":"pong",...} —— 看到它就说明签名、网络、链路全部正确。
★ 凭证维护:此账号的
appid/appsecret长期有效、不会随意变动;如平台因安全原因轮换,会提前通知并同步更新本文档。请以本文档显示的最新值为准。
★ 安全说明(请知悉):此账号仅限沙箱联调与体验,只能操作沙箱商家的数据、不计费、限额极低,
且平台可随时一键重置(重置后其中的测试数据清空,凭证不变)。
生产环境凭证由平台在签约后单独签发,不会使用、也不应复用此沙箱凭证。
若贵司希望使用独立沙箱账号(不与他人共用),可联系我们单独开通。
沙箱可用测试数据:沙箱不预置会员,请用 member/bind 自行绑定(建议用 out_uid 如 DEMO-001)。 沙箱的释放周期可由我们临时调整为 1 天,便于快速看到"积分减少、券增加"的效果,需要时告知即可。
三、鉴权流程
① 用 appid + appsecret 调 POST /open/v1/auth/token → 拿到 access_token(有效期 2 小时)
② 之后所有业务接口带 HTTP 头 X-Open-Token: <access_token>
③ 令牌过期(40104)→ 重新调 ① 换取
④ 每个 appid 可同时持有多个有效令牌(无单点登录限制)
两个端点两类密钥(最容易搞错的地方):
| 端点 | 鉴权方式 | 签名密钥 |
|---|---|---|
auth/token | 请求体里传 appsecret,平台校验 | appsecret |
| 其他业务端点 | 请求头 X-Open-Token 传令牌 | access_token |
安全提醒:
appsecret只在调用auth/token时出现在请求体里,不要放到 URL 查询串(会被访问日志记录)- 平台侧
appsecret只存哈希,即使我们自己也查不出明文;丢失只能重置/轮换
3.1 密钥轮换 vs 密钥重置(★ 请分清,用错会中断服务)
平台提供两个操作,后果完全不同:
| 轮换(计划性,推荐) | 重置(应急) | |
|---|---|---|
| 用途 | 按安全规范定期更换密钥 | 密钥泄露、必须立即作废 |
| 旧密钥 | 保留重叠期(默认 24 小时)内仍可用 | 立即失效 |
已签发的 access_token | 全部继续有效(不断服) | 立即全部失效 |
| 客户侧体验 | 无中断:先上新密钥跑通、再下旧密钥 | 服务中断,直到换上 新密钥 |
⇒ 定期轮换请要求平台用「轮换」(说清是轮换,避免被误当作重置而中断你的服务)。
推荐的轮换操作顺序(全程零失败):
① 请平台执行「轮换」→ 你方拿到新密钥(明文只显示一次)
② 你方把新密钥配置上线(此时新、旧密钥同时有效,重叠期内随便切)
③ 观察确认新密钥调用正常
④ 重叠期自然结束,旧密钥自动失效 —— 你方无需做任何操作
- 重叠期时长由平台按接入方配置(0~720 小时,默认 24 小时);
0表示不留重叠期,效果等同重置 - 重叠期内新旧密钥各自有效、互不影响;重叠期结束后旧密钥返回
40103
你方应在自己系统里记录密钥的启用/停用时间,避免把两把密钥的用途搞混(例如误把旧密钥留在配置里)。
四、签名算法(契约,不可变)
4.1 规则
payload = appid + "\n" + timestamp + "\n" + nonce + "\n" + request_id + "\n" + sha256hex(rawBody)
sign = HMAC-SHA256(payload, secret) 输出小写十六进制
rawBody= HTTP 请求体的原始字符串(原样,不做任何重排/序列化)- 无请求体时用空字符串
"",其sha256为e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 request_id未传时按空字符串参与拼接- 每次请求都要用新的
nonce(含重试);request_id才是在重试时要保持不变的 - 字段之间用
\n(换行符) 分隔,不是&或|
4.2 参数位置(硬规定)
| 参数 | 位置 |
|---|---|
appid、timestamp、nonce、request_id | URL 查询串(query string) |
签名 sign | HTTP 请求头 X-Open-Sign |
| 令牌 | HTTP 请求头 X-Open-Token |
| 业务参数 | 请求体(JSON) |
为什么
sign走请求头:签名覆盖了请求体,若把sign也放进请求体,就成了「签的内容里包含签名自身」,无法计算。
4.3 多语言实现(可直接抄)
PHP
function bopSign($appid, $timestamp, $nonce, $requestId, $rawBody, $secret) {
$payload = implode("\n", [
(string)$appid, (string)$timestamp, (string)$nonce,
(string)$requestId, hash('sha256', (string)$rawBody),
]);
return hash_hmac('sha256', $payload, $secret);
}
Java
public static String bopSign(String appid, String ts, String nonce, String rid, String rawBody, String secret) throws Exception {
String bodyHash = toHex(MessageDigest.getInstance("SHA-256").digest(rawBody.getBytes("UTF-8")));
String payload = appid + "\n" + ts + "\n" + nonce + "\n" + rid + "\n" + bodyHash;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
return toHex(mac.doFinal(payload.getBytes("UTF-8"))); // toHex 输出小写十六进制
}
Node.js
const crypto = require('crypto');
function bopSign(appid, ts, nonce, rid, rawBody, secret) {
const bodyHash = crypto.createHash('sha256').update(rawBody, 'utf8').digest('hex');
const payload = [appid, String(ts), nonce, rid, bodyHash].join('\n');
return crypto.createHmac('sha256', secret).update(payload, 'utf8').digest('hex');
}
Python
import hmac, hashlib
def bop_sign(appid, ts, nonce, rid, raw_body, secret):
body_hash = hashlib.sha256((raw_body or '').encode('utf-8')).hexdigest()
payload = '\n'.join([str(appid), str(ts), nonce, rid or '', body_hash])
return hmac.new(secret.encode('utf-8'), payload.encode('utf-8'), hashlib.sha256).hexdigest()
4.4 签名自检(★ 请务必先用这组数据验通,再写业务代码)
用下面这组固定输入跑你方实现,结果必须逐字节一致:
| 输入 | 值 |
|---|---|
appid | bfoptest0001 |
timestamp | 1800000000 |
nonce | abcdef1234567890 |
request_id | demo-0001 |
rawBody | {"note":"hello"} |
secret | 000000000000000000000000000000000000000000000000(48 个 0) |
第 1 步 · 验 sha256
sha256({"note":"hello"}) = 498207608015e1c6ea99b40748b3ecefd7d9035d5c0a70817902058823362be6
第 2 步 · 验拼接(注意是字面换行符 \n,不是 \n 两个字符)
bfoptest0001
1800000000
abcdef1234567890
demo-0001
498207608015e1c6ea99b40748b3ecefd7d9035d5c0a70817902058823362be6
即 payload = bfoptest0001\n1800000000\nabcdef1234567890\ndemo-0001\n498207608015e1c6ea99b40748b3ecefd7d9035d5c0a70817902058823362be6
第 3 步 · 验 HMAC
sign = 4601ac48c04aa780348549ac2df50fff6f7bd4318eafbbf04e701b183848a77b
你能算出这个值 ⇒ 签名算法已经对,可以进入业务对接。算不出 ⇒ 先别写业务,先按第十四节排查。
附:无请求体时的 sha256("")
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
(GET 类请求或 body 为空时用这个值参与拼接。)
五、请求与响应约定
5.1 统一响应信封
{
"code": 0,
"msg": "ok",
"data": { },
"request_id": "你在查询串里传的值原样回传"
}
| 字段 | 说明 |
|---|---|
code | 0 = 成功;非 0 = 错误(见第七节)。请用 code 判断成功,不要用 msg(msg 是人看的文案,可能微调) |
msg | 人话说明,可直接展示给运营 |
data | 业务数据;无数据时为 null |
request_id | 原样回传,便于对账与排查 |
幂等命中额外带 "idempotent": true(见第八节)。
5.2 HTTP 状态码
| code 区间 | HTTP 状态 |
|---|---|
| 0 | 200 |
| 40001–40099 | 400 |
| 40101–40199 | 401 |
| 40301–40399 | 403 |
| 404xx(接口不存在 40006) | 404 |
| 40901 | 409 |
| 42901 | 429 |
| 500xx | 500 |
请同时判断 HTTP 状态与
code:即使 HTTP 是 4xx/5xx,响应体始终是 JSON(不会是 HTML),可直接解析。
★ 响应体永远是 JSON —— 包括出错和平台内部异常时。
平台对 /open/v1/* 的所有响应都保证是上面这个统一信封的 JSON,不会返回 HTML 错误页。 即使平台内部出错(HTTP 500),响应体也是:
{"code":50001,"msg":"服务内部错误","data":null,"request_id":""}
所以贵司的代码可以无条件 json_decode,不用为"解析失败/拿到 HTML"写分支。 请同时判断 HTTP 状态与 code:HTTP 200 不等于业务成功,以 code == 0 为准。
5.3 传输与编码
- 请求体统一 JSON(UTF-8),
Content-Type: application/json - 金额一律 整数分(例:
12.34元传1234),不要传浮点 - 时间统一 10 位秒级 Unix 时间戳(不是毫秒)
六、接口清单
6.1 POST /open/v1/auth/token —— 签发令牌
| 项 | 内容 |
|---|---|
| 查询串 | appid、timestamp、nonce、request_id(可选) |
| 请求头 | X-Open-Sign |
| 请求体 | {"appsecret":"<你的密钥>"} |
| 签名密钥 | appsecret |
| 幂等 | 否(每次调用签发新令牌) |
| 豁免 | 本接口豁免合规门禁(不校验 agreement_status);但同样不豁免「开通状态」(未开通 → 40102) |
响应 data | access_token(48 位十六进制)、expires_in(秒,固定 7200)、token_type(Bearer)、appid |
6.2 POST|GET /open/v1/ping —— 连通性自检
| 项 | 内容 |
|---|---|
| 查询串 | appid、timestamp、nonce |
| 请求头 | X-Open-Sign、X-Open-Token |
| 签名密钥 | access_token |
| 幂等 | 传 request_id 时启用 |
| 豁免 | 本接口豁免合规门禁(即不校验 agreement_status,为的是合规状态变化时你仍能自检连通性)⚠️ 但不豁免「开通状态」:接入方未被平台开通,本接口同样返回 40102 |
响应 data | appid、name、bid、sandbox、agreement_status、server_time、server_time_text、rate_limit、rate_used、cost_ms |
用途:验证 ① 网络与路由可达 ② 凭证正确 ③ 签名算法一致 ④ 令牌有效 ⑤ 查剩余配额。建议你方在监控里定时调用。
6.3 POST /open/v1/member/bind —— 绑定外部会员
把你的会员 ID 与邦斧会员建立一一对应关系。这是对接的第一件事:没有映射,你的会员在邦斧侧就无处挂账。
| 项 | 内容 |
|---|---|
| 查询串 | appid、timestamp、nonce、request_id(可选) |
| 请求头 | X-Open-Sign、X-Open-Token |
| 签名密钥 | access_token |
| 请求体 | {"out_uid":"你的会员ID","phone":"13800138000"}或 {"out_uid":"...","mid":123,"bind_type":3} |
| 幂等 | 是。同一 out_uid + 同一会员重复调用,返回首次结果并带 idempotent:true(不报错) |
响应 data | out_uid、mid(邦斧会员 ID)、idempotent |
规则(请务必按此实现):
| 情形 | 结果 |
|---|---|
out_uid 首次绑定 | code=0,返回 mid |
同 out_uid + 同会员再次绑定 | code=0,idempotent=true(不要当成失败) |
该 phone 在邦斧侧不存在会员 | 40201 —— 本平台不代为创建会员,请先引导用户完成注册 |
| 该外部会员已绑定另一个邦斧会员 | 40202 —— 按约定不做账号合并、也不允许直接改绑,须先 unbind 或人工核实 |
该邦斧会员已被另一个 out_uid 占用 | 40202 —— 见下注 |
★ 为什么「一个邦斧会员只能被一个
out_uid绑定」:若允许两个外部身份绑同一会员,这些积分与券的归属将无法界定,对账必然产生纠纷。按约定的一一匹配原则,此类请求一律拒绝。
★ 为什么不做账号合并:合并要处理两个主键体系的历史流水、券余额、上下级关系,
第一版明确不做(见《商用解决方案》§4.1)。请在你方侧保证
out_uid的稳定与唯一。
6.4 POST /open/v1/member/unbind —— 解绑
| 项 | 内容 |
|---|---|
| 请求体 | {"out_uid":"你的会员ID"} |
| 幂等 | 是。当前未绑定时返回 code=0 且 unbound=false(不报错,避免重试风暴) |
响应 data | out_uid、mid、unbound(本次是否真的解绑了) |
★ 解绑不影响用户已有积分与券:权益保留在邦斧侧,只是外部身份不再关联。
解绑后该
out_uid再查余额会得到40203;若之后重新绑定同一个会员,会复用原有映射(历史流水不断)。
6.5 GET /open/v1/member/profile —— 会员资料(已脱敏)
| 项 | 内容 |
|---|---|
| 查询串 | appid、timestamp、nonce、out_uid、request_id(可选) |
响应 data | mid、out_uid、tel_masked、nickname、sex、levelid、level_name、has_headimg、registered_at |
★ 脱敏口径(与本平台客户服务一致,不是本接口自创):
| 字段 | 返回形式 |
|---|---|
手机号 tel_masked | 前 3 后 4(如 138****8000),完整号码永不下发 |
昵称 nickname | 只留首字,其余以 * 代替 |
| 地址 | 不下发(本接口不含任何地址字段) |
| 头像 | 只给 has_headimg 布尔值,不给 URL |
若你方业务确需完整手机号,属另行评估事项,须单独书面约定(涉及个人信息合规),本接口不做。
6.6 GET /open/v1/member/balance —— 积分与券余额
这是你方最常用的接口(下单确认页、我的页面、客服查询都靠它)。
| 项 | 内容 |
|---|---|
| 查询串 | appid、timestamp、nonce、out_uid、request_id(可选) |
响应 data | 见下表 |
| 字段 | 含义 |
|---|---|
integral | 积分余额(整数) |
coupon_usable_cents | ★ 可用券余额(分)= 本商家专属券(不含平台通用券,见下注) |
coupon_merchant_cents | 本商家专属券(分),与 coupon_usable_cents 同值 |
coupon_platform_cents | 平台通用券(分)。仅当存在时返回,不计入可用额度 |
coupon_scope_note | 口径说明(随响应下发,避免按"两层相加"理解额度) |
coupon_frozen | 布尔:该会员的券当前是否被冻结(冻结时一律不可抵扣) |
coupon_frozen_note | 冻结原因的人话说明(正常时为「正常」) |
amount_unit | 恒为 分(提醒:所有金额均为整数分) |
★ 关于「冻结」:它是整体禁用开关,不是「冻结了多少钱」。
平台不提供冻结金额这个数,请勿在你方界面展示「冻结 ¥X」。你方只需按
coupon_frozen决定券能否使用。注意:冻结不改变余额,
coupon_usable_cents照常返回。
★★ 关于券的范围(重要):邦斧系统里券分「平台通用券」与「商家专属券」两层,
但本次对接你方只使用「商家专属券」 —— 平台通用券是邦斧平台自有的券,
由你方之外的体系发放与承担,你方既不发放也不核销。
因此
coupon_usable_cents只等于商家专属券。若某会员在邦斧侧另有平台通用券,会以
coupon_platform_cents单列并注明"未计入可用" ——请勿把它算进可用额度,否则会拿一个自己用不了的额度去抵扣、在用户侧穿帮。
口径权威性:积分与券的完整口径(换算比例、抵扣上限、有效期、活跃度闸门等)
以《邦斧开放平台 · 会员资产口径权威文档 v1.0》为准,请一并索取。
6.7 POST /open/v1/order/consume —— 上报消费(让利入池)
把你方订单的让利额报给邦斧,进入你方对应商家的奖励池。之后由既有释放机制自动按周期与比例 释放成券给会员 —— 你方不需要也不应该做释放,平台不提供"手动释放"接口。
| 项 | 内容 |
|---|---|
| 请求体 | {"out_uid":"...","out_order_id":"你方订单号","seq":1,"profit":1000,"order_amount":10000} |
| 金额单位 | 整数分(profit:1000 = 10 元) |
profit | 必填,本单让利额(分)。入池的就是这个数 |
out_order_id + seq | ★ 业务幂等键(见第六节)。同订单多次上报(如部分退款)用 seq 递增 |
member_profit | 可选,消费者侧份额(分)。不传则等于 profit(让利全额给消费者侧,与平台口径一致) |
| 幂等 | 是。同 out_order_id+seq 重复上报返回首次结果 + idempotent:true,不会重复入池 |
响应 data | record_id(入池记录)、mid、profit_cents、amount_unit |
★ 业务幂等键与
request_id是两件事:request_id只防"同一请求重发";你方换一个
request_id再报同一订单,靠的是out_order_id + seq挡住重复入池。所以
out_order_id必须是稳定的业务单号,不能是随机串。
★ 入池 ≠ 发券:入池只是把让利记进池子,券要等出批时才释放。
上报后立刻查券余额看不到变化是正常的,不要重试上报。
6.8 POST /open/v1/order/refund —— 退款回冲
订单退款后调用,把该订单从后续每一批的释放基数里剔除 —— 否则释放池会为一张已退款的订单持续释放消费券(白送)。
| 项 | 内容 |
|---|---|
| 请求体 | {"out_order_id":"你方订单号","seq":1,"out_uid":"可选"} |
| 幂等键 | 同 out_order_id + seq(与 order/consume 同一套键,所以必须传上报时用的那个订单号) |
| 幂等 | 是。重复调用不会重复回冲 |
响应 data | found(该订单是否入过池)、stopped_records(剔除的记录数)、pool_balance_cents、has_verified_coupon、hint |
★ 两类券的处理不同,别搞混:
| 券的类型 | 退款时怎么办 | 谁做 |
|---|---|---|
| 释放池发给会员的激励券 | 不回退已发的,只剔除后续释放 | 平台(本接口自动完成) |
| 你方自己商城核销掉的券 | 需要退(订单都退了,抵的券当然要还) | 你方另调 coupon/unverify |
本接口不会替你回退你方核销的券(核销是你方的交易流程),
但会在响应里用
has_verified_coupon告诉你"这单有核销记录",避免你漏掉。
found=false不是错误:表示该订单没有入池记录(可能没上报过,或已回冲过)。接口返回成功、
stopped_records=0,请不要重试。
6.9 GET /open/v1/pool/summary —— 奖励池概览(只读)
| 字段 | 含义 |
|---|---|
pool_balance | 池余额(元)= 待入池 + 上批未释放剩余 —— 这才是当前可释放的部分 |
pending_intake | 待入池(出批后新增、尚未进入任何批次) |
surplus | 上批已出批但尚未释放完的剩余 |
history_intake | 历史入池总额(只增不减的累计量,不是可用余额) |
history_reward | 累计已释放 |
batch_count | 已出批次数 |
release_pool_day / release_pool_rate | 你方商家的释放周期(天)与释放比例(%) |
exchange_rate | 兑换比例(1 积分最多释放多少元券,默认 5) |
★ 别把
history_intake当余额:它是历史累计入池额,只增不减。看"现在能释放多少"请看
pool_balance。
6.9.1 ★ POST /open/v1/order/refund 到底做了几件事
| 动作 | 是否做 | 说明 |
|---|---|---|
| 扣回该订单发放的积分 | ✅ 做 | 扣回额 = 发出积分 − 已被释放消耗的积分(精确,不会多扣)。写既有积分流水(remark=订单退款扣除积分) |
| 作废入池 | ✅ 做 | back_status='stop' ⇒ 该订单不再参与任何后续出批释放 |
| 收回已释放到商家专属层的券 | ❌ 不做 | 既有退款函数只回收平台层券余额;本平台券在商家专属层 ⇒ 不命中。这是既有函数的实际行为,非本平台的设计选择 |
| 退回订单抵扣的券 | ❌ 不做 | BOP 侧无邦斧订单抵扣(抵扣在你方商城发生) |
| 你方自己核销的券 | 你方处理 | 返回 has_verified_coupon=true 时,如需退券请另调 coupon/unverify |
返回新增 integral_reclaimed = 本次扣回的积分数。
★ 你方的会员积分账要与之对齐:退款后你方商城的会员积分也应回到「消费前」的状态
—— 即「发出的积分 − 已换券用掉的积分」。
6.10 GET /open/v1/integral/logs —— 积分流水
| 字段 | 含义 |
|---|---|
count / list | 总数 / 流水列表(每条含时间、方向 in/out、变动量、变动后余量快照、说明、source) |
integral_total | 该会员的积分总余额(字符串,4 位小数) |
★★ 积分不是整数! 邦斧积分是 4 位小数的数值(生产实测 26,418 / 26,967 个会员带小数,
如
2.7238、9671.3113)。接口以字符串返回,请勿取整 —— 取整会直接丢掉用户资产。
★ 积分是平台级字段,不按商家隔离(这点与券不同:券分会员级/商家专属两层)。
本接口只返回该会员在本商家产生的流水,但
integral_total是他的全部积分。
6.11 POST /open/v1/integral/adjust —— 积分人工调整(补分 / 扣分)
★ 默认关闭。 该操作等于直接变动用户资产(1 积分最多可释放 5 元券), 需平台在参数配置中开启,并受单笔上限(默认 1000 积分)约束。
| 项 | 内容 |
|---|---|
| 请求体 | {"out_uid":"...","amount":"0.5","reason":"客服补分","out_order_id":"ADJ-1","seq":1,"operator":"kf001"} |
amount | 字符串数值,正数=补分 负数=扣分,支持 4 位小数(不要取整) |
reason | 必填(用于留痕与审计) |
operator | 建议填写操作人(会写进流水,便于事后追责) |
| 幂等 | 是。同 out_order_id+seq 重复调用不重复调整 |
| 失败即不动 | 积分不足返回 40208 且不扣款(不会扣成负数) |
关于「双人复核」:这是你方客服系统的流程。本平台提供完整的可追溯留痕
(既有积分流水 + 本模块业务流水,含
operator、reason、request_id),供你方审计。
6.12 POST /open/v1/member/data-request —— 个人信息合规通道
type | 作用 | 开关 |
|---|---|---|
query | 消费者查阅其个人信息:返回收集了哪些字段、用途、当前值(已脱敏),以及"未收集"清单 | 默认可用 |
delete | 删除权:匿名化(清手机号/昵称/头像/性别) | 默认关闭(不可逆) |
★ 「删除」= 匿名化,不是物理删除:消费者的积分/券与全部流水必须保留
(账务留存、对账、反欺诈需要 —— 这是个保法删除权的法定例外)。物理删会员行会直接抹掉用户的资产。
★ 匿名化后
out_uid ↔ mid映射保留,所以你方按out_uid查资产仍能查到(资产不丢)。但若之后用同一手机号绑一个新的
out_uid,会形成新账户、资产不合并 ——这是去标识化的必然结果,你方应始终使用稳定的
out_uid,不要靠手机号重绑。
6.12.1 ★ POST /open/v1/coupon/transfer —— 券转赠
口径(已与贵司确认):消费券不支持提现;支持转赠;是否开启由商户后台配置(默认关闭)。
| 项 | 内容 |
|---|---|
| 请求体 | {"out_uid":"转出方","to_out_uid":"接收方","amount":300,"out_order_id":"TF-1","seq":1} |
| 生效前提 | 平台侧已为该接入方开启转赠(商户后台配置);未开启返回 40211 |
| 范围 | 同一商家内的会员之间(券是商家专属层,跨商家无意义) |
| 约束 | 不能转给自己(40212);接收方必须已 member/bind(40213);余额不足拒绝(40205,不截断) |
| 幂等 | 是(out_order_id + seq),重复调用不重复转 |
| 返回 | 双方余额 from_left_cents / to_left_cents |
★ 双方各产生一条券流水:转出方
action=0(减少)、接收方action=1(增加),
remark互指对方标识与单号 ⇒ 双方各自对账时都能看到这笔,不需要额外解释。两条流水的
ordernum都是本次转赠单号,可倒查。
并发安全:转赠按会员 ID 升序加行锁,
A→B与B→A同时发起不会死锁(已实测)。
6.13 券:余额与流水
| 接口 | 说明 |
|---|---|
GET /open/v1/coupon/balance | 券余额(= 商家专属券)。返回 coupon_usable_cents、coupon_frozen(布尔) |
GET /open/v1/coupon/logs | 券流水(分页)。每条含方向(in/out)、金额(分)、余额快照、说明、source |
source的含义:bop= 由你方通过本平台产生;other= 该会员在这个商家下的其它来源流水。平台一并返回,不做隐藏 —— 只给你方自己的流水会看起来像隐瞒。
★ 关于「可用券列表」(方案原列的
coupon/list):本平台的券是余额制(一个金额),不是卡券制 —— 系统里没有"一张张券",所以没有面额、有效期、适用范围这些字段,
也就不存在"可用券列表"这个接口。要明细请看
coupon/logs(流水)。这与《口径权威文档》里"券不做过期回收"是同一条事实。
6.14 关于「发券」——券只能由奖励池释放产生
★ 平台不提供「直接发券」接口。 券的唯一来源是奖励池按配置释放:
```
订单让利额 profit
↓ 入池 (order/consume 上报)
奖励池 platform_profit_stage ← 池子里就是这笔钱
↓ 发等额积分(1 元让利 = 1 积分)
会员积分
↓ 按池子配置分批释放:本批 = back_amount × member_profit ÷ back_integral
↓ 同时【扣积分】= 券额 ÷ 5
券(本商家专属券,会员可用于抵扣)
```
为什么必须这样:券的量天生被让利额顶死 —— 上限 =
让利额 × 5(Member.php的
bcmul($record['member_profit'], 5, 2))。池子里有多少钱,就只能释放出多少券。若允许绕过池子直接给会员加券,券就会与积分、利润脱钩,
会员拿到的抵扣将没有对应的资金支撑 —— 这既破坏账目闭合,也不是任何一方想要的结果。
因此:贵司要让会员拿到券,正确且唯一的做法是
order/consume上报让利额,之后平台会按奖励池配置(周期、每批比例)自动释放,贵司无需实现任何释放逻辑。
释放进度可随时用
GET /open/v1/pool/summary查看。
6.15 POST /open/v1/coupon/verify —— 券核销(扣减)
在你方自己的交易流程里决定抵多少,然后调本接口扣减。 平台不判断你方订单该不该抵、抵多少。
| 项 | 内容 |
|---|---|
| 请求体 | {"out_uid":"...","amount":1500,"out_order_id":"V-1","seq":1} |
| 金额单位 | 整数分 |
| 失败即不扣 | 余额不足返回 40205 且不扣款 —— 平台不会自动按余额"有多少抵多少"(那是你方的业务决策) |
| 并发 | 平台用行锁保证并发核销不会超扣(已实测:两笔并发恰好一成功一余额不足) |
| 幂等 | 是。同 out_order_id+seq 重复核销不会重复扣减 |
响应 data | used_cents、left_cents、idempotent |
★ 一次消费要核销多次怎么办(如分单核销):用不同的
seq。
6.16 POST /open/v1/coupon/unverify —— 券回退(订单取消 / 退款)
| 项 | 内容 |
|---|---|
| 请求体 | {"out_uid":"...","out_order_id":"V-1","seq":1} |
| 金额来源 | 取自原核销记录,不需要也不允许你方指定金额 —— 杜绝"退得比扣得多" |
| 一次一退 | 一次核销只能回退一次;重复回退返回成功且 idempotent:true,不会重复加券 |
| 找不到对应核销 | 40206 |
响应 data | refunded_cents、left_cents、idempotent |
6.19 GET /open/v1/order/query —— 按业务单号查询处理结果(★ 超时确认用)
为什么有这个接口:本平台不做回调(见 §0.2.4),上报后如果遇到网络超时,贵司需要一种 不产生任何副作用的方式确认"这笔到底处理成功了吗"。这个接口就是干这个的。
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_order_id | string | 是 | 业务单号(贵司自己的单号,与上报时一致) |
seq | int | 否 | 事件序号。不传 = 查该单号下的全部事件(最多 50 条) |
响应 data 字段
| 字段 | 类型 | 说明 |
|---|---|---|
found | bool | 本平台是否查到该单号的处理记录 |
event_count | int | 查到的事件条数 |
events[] | array | 每条事件:action(consume/refund/grant/verify/unverify/transfer/adjust/privacy)、seq、amount_cents、integral、biz_id、processed_at |
coupon_logs | int | 该单号在券流水里的条数 |
integral_logs | int | 该单号在积分流水里的条数 |
pool[] | array | 入池记录:in_pool_cents(入池金额,分)、back_status、back_status_text("有效(会参与后续释放)" / "已因退款作废(不再参与释放)")、record_id |
hint | string | 给贵司的处置建议(查不到时会明确告诉你下一步怎么做) |
★ found: false 不等于失败。 可能是:还没到达本平台、仍在重试中、或者单号写错了。 此时正确做法是重发——用同一 out_order_id + seq(有幂等保护,不会重复记账), 不要换新单号(换新单号会变成一笔新的业务)。
示例
GET /open/v1/order/query?appid=bfop260101xxxxxxxx&out_order_id=SO20261012001×tamp=1750000000&nonce=abc123
{
"code": 0, "msg": "ok",
"data": {
"out_order_id": "SO20261012001", "found": true, "event_count": 1,
"events": [{"action":"consume","seq":1,"amount_cents":3000,"integral":"30","biz_id":1302,"processed_at":"2026-10-12 17:39:21"}],
"coupon_logs": 0, "integral_logs": 1,
"pool": [{"in_pool_cents":3000,"back_status":"normal","back_status_text":"有效(会参与后续释放)","record_id":90755}],
"hint": "已查到处理记录。重复提交同一单号会返回这份同样的结果,不会重复记账。",
"amount_unit": "分"
},
"request_id": ""
}
数据范围:只能查到本接入方自己的单号,别家的同名单号查不到(按
appid严格隔离)。
6.20 GET /open/v1/member/list —— 会员列表(批量对账)
为什么有这个接口:贵司做批量对账时,需要"我这边绑了哪些会员、各自多少积分多少券"。 一个个调 member/balance 在会员上千时不可行。
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
page | int | 否 | 页码,默认 1 |
limit | int | 否 | 每页条数,默认 50,上限 200(超了自动压到 200) |
响应 data 字段
| 字段 | 类型 | 说明 |
|---|---|---|
page / limit / total / count / has_more | — | 分页信息(total = 本接入方名下的会员总数) |
list[] | array | 每项:out_uid、mid、integral(字符串,4 位小数)、coupon_usable_cents、coupon_usable_yuan、bound_at |
只回本接入方名下的会员(已解绑的不在内);不回姓名、手机号(个人信息最小化)——
需要某个会员的详细信息请调
member/profile(已脱敏)。券额度为本商家专属券口径。
6.21 GET /open/v1/billing/usage —— 本期用量与账单
为什么有这个接口:贵司需要在自己系统里看"这个月调了多少次、要交多少钱",不用每次问平台。
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
period | string | 否 | 账期,格式 YYYY-MM,默认当月 |
响应 data 字段
| 字段 | 类型 | 说明 |
|---|---|---|
usage.http_calls | int | 本期实际收到的请求数 = 日志行数 + 幂等重放次数(用它能和贵司自己的请求日志对上) |
usage.success / usage.failed | int | 成功 / 失败次数 |
usage.idempotent_replay | int | 幂等命中次数 —— 不计费 |
usage.billable_calls | int | 计费调用数(只算成功且非沙箱) |
usage.is_sandbox | int | 沙箱接入方为 1(沙箱整月调用不计费) |
bill | object\ | null |
计费口径与平台账单完全一致(同一个实现);账号信息(是否签约、费率)请见平台提供的接入方信息页。
6.17 其他接口
退款回冲(消费入池的回冲)、积分流水、积分人工调整、释放池明细等将随对接方案确认后逐个开放。
当前已开放的接口:auth/token、ping、member/bind、member/unbind、member/profile、 member/balance、member/data-request、order/consume、order/refund、pool/summary、 integral/logs、integral/adjust、coupon/balance、coupon/logs、 coupon/verify、coupon/unverify、coupon/transfer。其余路径一律返回 40006。
★ 不提供
coupon/grant(直接发券) —— 原因见 §6.14。
6.18 未定义路径(兜底)
请求 open/v1/ 下未定义的路径,在鉴权通过的前提下返回:
{"code":40006,"msg":"接口不存在","data":null,"request_id":""}
(HTTP 404,仍是 JSON,不会返回 HTML。)
⚠️ 前提是「鉴权通过」:平台先鉴权、后路由,所以若签名或令牌无效,会优先返回鉴权类错误码(
40001/40002/40102/40104),而不会返回40006。也就是说:连
40006都拿不到,先怀疑签名/令牌,而不是路径。
七、错误码表(完整,已冻结)
| code | 含义 | 常见原因 | 你方处置 |
|---|---|---|---|
| 0 | 成功 | — | — |
| 40001 | 缺少必填参数 | 少传 appid/timestamp/nonce;调 auth/token 没传 appsecret | 补齐参数 |
| 40002 | 签名校验失败 | 拼串顺序/分隔符错、用了错误的密钥(业务端点误用 appsecret)、rawBody 不是你实际发出的字节 | 核对第四节,用同语言示例比对 |
| 40003 | 时间戳超出容差 | 服务器时间不同步(容差 ±300 秒) | 校准 NTP |
| 40004 | nonce 重复 | 同一 nonce 在 5 分钟内二次使用(含网络重试原样重发) | 每次请求生成新 nonce |
| 40005 | 请求体不是合法 JSON | Content-Type 声明 JSON 但内容非 JSON | 修正序列化 |
| 40006 | 接口不存在 | 路径拼错 | 核对路径 |
| 40101 | appid 不存在 | appid 写错 / 环境不对(测试凭证打了生产) | 核对凭证与环境 |
| 40102 | 接入方服务已停止 | ① 被平台停用(一键断服,旧令牌同时失效;可恢复)② 该接入方尚未被平台开通(常见:刚拿到凭证就调) | 先确认是否已「签约 + 开通」;否则联系平台 |
| 40103 | appsecret 校验失败 | 密钥错误 / 已被重置 | 使用最新密钥 |
| 40104 | access_token 无效或已过期 | 未带 X-Open-Token、令牌过期(>2h)、已重置密钥后旧令牌失效 | 重新取令牌 |
| 40105 | 沙箱凭证只能访问沙箱域 | 沙箱 appid 打了正式接口(保留码,暂未启用) | 用对应环境凭证 |
| 40106 | 接入服务已到期 | 年费到期未续期,平台已停止服务 | 联系平台续期(续期后立即恢复,无需改代码) |
| 40107 | 调用来源 IP 不在白名单内 | 你方调用出口 IP 未被加入白名单(或 IP 变了) | 把你方出口 IP 报给平台添加(见 §9.2) |
| 40108 | 合作已终止 | 该接入方与平台的合作已结束(数据已交割)。与 40102 的区别:40102 是临时停用、可恢复;40108 是合作终结、不可恢复 | 无法"申请恢复"。如需继续合作,请联系平台重新签约接入(会重新走签约与开通流程) |
| 40201 | 邦斧侧不存在该会员 | phone 未在邦斧侧注册(本平台不代为创建会员);或 mid 不存在 | 引导用户先完成注册后再绑定 |
| 40202 | 会员绑定冲突 | 一个外部会员对应一个邦斧会员(一一匹配):① 该 out_uid 已绑别的会员 ② 该会员已被别的 out_uid 占用 | 先 unbind 或人工核实;按约定不做账号合并 |
| 40203 | 该外部会员尚未绑定 | 未调 member/bind 就来查余额/资料(含解绑后再查) | 先调 member/bind |
| 40204 | 券已被冻结 | 该会员的券被整体冻结(平台风控或平台级开关) | 联系平台核实;冻结是整体开关,不是金额 |
| 40205 | 券余额不足 | 你方申请的抵扣额超过该会员在本商家的券余额 | 下调抵扣额后重试(平台不会替你按余额截断) |
| 40206 | 找不到核销记录 | 回退时 out_order_id/seq 对不上任何已发生的核销 | 核对你方记录的 out_order_id 与 seq |
| 40207 | 积分人工调整未开启 | 该接入方未开启(默认关,属敏感操作) | 联系平台在参数配置中开启 |
| 40208 | 积分不足 | 扣减会让积分变负 | 下调扣减量后重试 |
| 40209 | 超出单笔调整上限 | 单笔超过配置上限(默认 1000 积分) | 拆分或申请提高上限 |
| 40210 | 个人信息删除未开启 | 匿名化是不可逆操作,默认关 | 联系平台开启 |
| 40211 | 券转赠未开启 | 该接入方未开启(商户后台配置,默认关) | 联系平台开启,或引导用户改用其他方式 |
| 40212 | 不能转赠给自己 | 转出方与接收方是同一会员 | 校验 to_out_uid ≠ out_uid |
| 40214 | (已废弃)超出单笔发券上限 | 随「直接发券」一并下线,不会再返回 | — |
| 40215 | (已废弃)超出单日累计发券上限 | 随「直接发券」一并下线,不会再返回 | — |
| 40213 | 接收方未绑定 | to_out_uid 未在本接入方绑定会员 | 先调 member/bind |
| 40301 | 未签署合规承诺书 | 该接入方尚未完成签约(仅对非豁免的业务接口生效,见下注) | 到商户后台「合规中心」签署 |
| 40901 | 同一 request_id 正在处理中 | 并发重试 | 不要并发,稍后查询结果 |
| 42901 | 超出频率限制 | 超过该 appid 的每分钟配额 | 退避重试(见第九节) |
| 50001 | 服务内部错误 | 平台侧异常 | 带 request_id 联系平台 |
关于
40301与「豁免端点」:ping与auth/token这两个端点是合规门禁的豁免端点(为的是合规状态变化时你仍能自检连通性),所以它们永远不会返回
40301。
40301只会出现在业务接口上(member/*即业务接口)。所以联调member/*时若收到40301,说明该接入方尚未完成签约,请到商户后台「合规中心」完成签署。
关于
40106(服务到期):接入服务按年计费,到期后所有接口(含ping/auth/token)都会返回
40106。请在生产环境监控里对40106单独告警 —— 它和40102的处置方式不同:
40102是「被平台停用」(要问原因),40106是「该续费了」。
八、幂等与重试(重要,请务必实现)
8.1 语义
带 request_id 的写接口,平台按「appid + request_id」去重:
| 情况 | 平台行为 |
|---|---|
| 首次 | 正常处理 |
| 处理中 | 返回 40901 |
| 已成功 | 直接回放首次结果,响应带 "idempotent": true,不重复入账 |
| 已失败 | 允许用同一 request_id 重试 |
8.2 你方必须做的
- 写接口必带
request_id,取值建议:你方业务单号 + 操作类型(如ORDER123456:consume) - 超时不要换 request_id:超时后用同一个
request_id重发,平台会告诉你真实结果 - 非幂等接口(如
auth/token)不要复用request_id request_id长度 ≤ 64
8.3 重试建议
网络超时/5xx → 同 request_id 重试,间隔 1s / 3s / 10s(最多 3 次)
收到 40901 → 说明前一次还在处理,等待 ≥2s 后同 request_id 重试
收到 42901 → 按响应中的限流信息退避(建议 ×2 递增)
收到 4xx 参数/鉴权类 → 重试无意义,先修问题
⚠️ 重试时必须重新生成
nonce(请求体与request_id保持不变)。「防重放」与「幂等」是两道独立的闸门,且防重放在前:
| 重试方式 | 平台返回 | 含义 |
|---|---|---|
| 同
request_id+ 新 nonce ✅ |idempotent: true+ 首次结果 | 正确姿势,直接拿到真实结果 || 同
request_id+ 同 nonce(原样重发) ❌ |40004| 被防重放拦下,不会回放结果 |
40004只说明「这个 nonce 用过了」,不代表业务失败 —— 别据此判定失败并另开新单,否则可能重复入账。换成新 nonce 用同一个request_id再发一次即可。
九、限流与访问控制
| 项 | 值 |
|---|---|
| 维度 | 两个维度同时生效:① 按 appid(整包总额度)② 按单个接口(防单点打爆) |
| 算法 | 固定窗口(每分钟) |
| 默认配额 | appid 维度 600 次/分钟;单接口维度默认不限(0) |
| 可调整 | 是(平台可在「参数配置」中为该接入方单独设定:appid 维度 1~100000、单接口维度 0~100000) |
| 超限响应 | code=42901,HTTP 429 |
| 查询余量 | 调 ping,看 data.rate_limit 与 data.rate_used |
为什么有两个维度:总额度是"总闸"。若你方某个循环写错、只打一个接口,总余量还很充足,
但那个接口已经把平台侧写库(发券/入池都带锁)打满。单接口闸门会在总闸仍放行的情况下,
单独把异常高频的那一个接口拦住 —— 保护的是双方:平台不被单点打爆,你方也不会因此
把整包额度耗尽。建议按该接口正常峰值的 3~5 倍设置。
⚠️ 单接口维度只拦被超限的那个接口,不影响你方其他接口的调用(不连坐)。
📌 计费口径也是按分钟调用量统计,与本限流窗口自洽:限流口径 = 计费口径。
如需更高配额,提前告知平台方并说明峰值 QPS 与调用模型(批量/实时)。
超限时响应头会带
Retry-After(秒),请按它退避,不要固定 sleep。
9.2 IP 调用白名单(★ 生产环境建议必配)
为什么要有它:appsecret 一旦泄露,签名就是「合法」的。IP 白名单是凭证之外的第二道门 —— 即使密钥被盗,攻击者不在白名单里也进不来。
| 项 | 说明 |
|---|---|
| 配置位置 | 平台「接入方管理 → 参数配置 → IP 调用白名单」(改动自动留痕) |
| 格式 | 英文逗号分隔;支持单个 IP 与网段,例:203.0.113.10,203.0.113.0/24,2001:db8::/32 |
| 留空 | 不限制(联调期默认如此;生产接入方建议必配) |
| 支持协议 | IPv4 与 IPv6,网段按位精确匹配 |
| 生效范围 | 全部端点,含 auth/token 与 ping —— 白名单外的来源连令牌都取不到 |
| 被拒返回 | code=40107,HTTP 401;该请求不计入你的调用配额(不占 600 次/分钟) |
| 变更方式 | 双方书面确认后由平台添加/删除;请勿口头临时加 IP |
上线前请把这三件事确认掉:
- 报准出口 IP:不是「服务器内网 IP」,而是访问外网时对端看到的公网 IP。
可用 curl https://ifconfig.me 在你方服务器上查。若你方走 NAT/网关/云函数,要报网关的出口 IP。
- 覆盖变化范围:若你方出口 IP 是浮动池或会扩容,请把整个网段报过来(如
203.0.113.0/24),
否则某台机器扩容后就会突然收到 40107。
- 双向对等:平台回调你方(如事件通知,后续开放)时,也需要你方把我方出口 IP 加入你方白名单 ——
届时平台会书面提供固定出口 IP 清单。
运维提醒:
40107通常不是故障,而是你方出口 IP 变了。如果业务突然中断且返回 40107,先自查出口 IP,再带
request_id联系平台。
十、调用可见性(排查「我上报了但没到账」)
10.1 平台侧记录
平台对每一次调用都留痕(不论成功失败、不论有没有 request_id),记录:时间、接口、request_id、业务单号、结果码、失败原因、耗时、来源 IP、脱敏后的请求体。
10.2 你方遇到「上报了但没到账」的排查顺序
- 你方是否拿到响应? 没拿到 → 网络/超时问题
- 响应是
code=0吗? 不是 → 按第七节处理 - 把
request_id提供给平台方,平台可立刻定位: - 查不到记录 ⇒ 请求根本没到平台(你方没发出、地址写错、被中间层拦掉)
- 有记录且是失败 ⇒ 记录里有明确原因(如会员不存在)
- 有记录且成功 ⇒ 问题在后续业务环节,带上记录一起排查
10.3 你方应自留
- 每次调用的
request_id、请求体、响应体、耗时 - 建议落库并保留 ≥ 90 天,便于双方对账
十一、沙箱环境
11.1 用途
客户不要拿生产联调 —— 否则脏数据污染真实账本,后续对账永久对不上。
11.2 使用方式
★ 文档 §2.2 直接给了一个可用的沙箱测试账号(appid + appsecret + 限额),无需申请即可开始联调。
若贵司需要独立沙箱(不与他人共用),可联系我们单独开通。
平台方也可为贵司额外开通一个沙箱接入方(独立的 appid)。
沙箱最大的好处:免签约、免开通,拿到凭证立刻能调。 所以「先验通链路」这件事请用沙箱做,不要占着正式凭证等签约流程。
| 项 | 正式 | 沙箱 |
|---|---|---|
| appid | 独立 | 独立 |
| 数据 | 正式数据域 | 沙箱数据域,可一键重置 |
| 计费 | 按合同 | 不计费 |
| 用途 | 生产运营 | 联调、回归、演示 |
11.3 重要边界(必须知晓)
沙箱是逻辑沙箱:按 appid 隔离平台侧数据(调用日志/令牌/规则快照),可一键重置。
但涉及会员积分、消费券等实际业务数据的写入,会落在沙箱接入方所绑定的那个商家名下。因此:
沙箱接入方必须绑定一个【专用的沙箱商家】,不得绑定真实客户商家,否则沙箱联调会污染真实客户的会员数据。
平台方在开通时会做这个绑定,请勿要求把沙箱绑到生产商家上。
11.4 沙箱合格标准
贵司应在拿到沙箱凭证后 24 小时内,自行跑通「绑定会员 → 上报消费 → 查询积分 → 券到账 → 核销券」全链路,不需要向平台求助。 遇到问题请先按第十节自查,再带 request_id 联系平台。
十二、合规要求(接入前置条件)
邦斧开放平台在合规上是有门禁的,请知悉。
正确顺序(顺序错了会一直报 40102):
① 平台方建好接入方并发给你 appid / appsecret
② 贵司在商户后台「合规中心」在线签署《客户合规承诺书》
③ 平台方在「接入方管理」点【开通】 ← 签约 ≠ 开通,这步必须做
④ 此时业务接口才可用(此前一律 40102)
⑤ 急等联调?直接用【沙箱凭证】,跳过后三步
| 要求 | 说明 |
|---|---|
| 必须签署《客户合规承诺书》 | 在商户后台「合规中心」在线签署(27 项逐条确认)。未签署前,业务接口一律返回 40301 |
| 超默认档配置需另签 | 如需开启多层计酬、区域代理等超默认配置,另签《超默认档配置确认书》 |
| 按人数奖励平台不提供 | 以发展人员数量为计酬依据属传销入罪界线,平台不开放该配置(签任何确认书也不放开) |
| 区域服务商须平台独立授权 | 不得由上级服务商发展下级产生;按区域内整体销售业绩计酬;同一笔业绩只归属一个区域 |
| 宣传口径红线 | 不得使用「稳赚/保本/躺赚/月入过万」等收益承诺表述;不得虚构平台背景与官方认证关系 |
| 平台可一键断服 | 发现合规风险时平台可立即停服(旧令牌同时失效) |
| 服务按年计费、到期停服 | 到期后所有接口返回 40106;续期后立即恢复。请在监控里单独对 40106 告警 |
签署完成后,平台为该接入方开通,业务接口即可正常调用。签署过程会留痕(协议全文快照 + SHA256 内容哈希 + 逐项勾选 + 签署人声明 + 身份确认 + IP/设备/时间),双方均可下载《签署证明》。
十三、接入自检清单(提交联调前请逐项确认)
- 已拿到
appid/appsecret,并确认对应环境(测试 / 沙箱 / 生产) - 已确认该接入方【已签约且已被平台开通】(否则一切接口都是
40102;只想验链路请改用沙箱凭证) - 签名算得对:用第四节 4.4 的自检数据比对通过
- 时间戳取自 NTP 同步的服务器时间,误差 < 5 分钟
- 每次请求生成新的 nonce
- 已实现
auth/token取令牌 + 令牌过期(40104)自动重新获取 - 已与平台约定密钥轮换周期,并知悉【轮换】不会断服而【重置】会立即失效(见 §3.1)
- 业务端点用
access_token签名,auth/token用appsecret签名(别搞反) -
X-Open-Sign在请求头,公共参数在查询串 - 金额按整数分传递
- 写接口都带
request_id,且重试用同一个request_id - 实现了超时(建议 5~10 秒)+ 有限次重试 + 指数退避
- 处理了
40102(被停服)、40106(服务到期,需续期)与40301(未签约)三个状态 - 对
40106与40102分别告警(40102要问平台原因,40106是提示续费) - 已把出口 IP(或网段)报给平台加入白名单,且已覆盖扩容后的地址范围(见 §9.2)
- 已处理
40107:能区分「IP 变了」与「真故障」,并对40107单独告警 - 已实现
ping定时自检(建议 1~5 分钟一次)并接入你方告警 - 每次调用落库留痕(
request_id+ 请求 + 响应 + 耗时),保留 ≥ 90 天 - 已按第十一节在沙箱完成全链路联调
- 已签署《客户合规承诺书》并通过平台开通
十四、常见问题
Q:40001 但参数我都传了? 调 auth/token 时请求体里必须有 appsecret(该端点用密钥自身鉴权)。业务端点不需要传 appsecret。
Q:突然全是 40107「调用来源 IP 不在白名单内」? 不是你方代码问题,是出口 IP 变了(换机、扩容、改 NAT、上了云函数/代理都会变)。 先在你方服务器执行 curl https://ifconfig.me 看当前出口 IP,报给平台添加即可。 若你方出口是浮动池,建议改报整个网段。
Q:40002 签名失败,我按示例写的? 三个高频原因:① rawBody 用的不是你实际发出的字节(例如先 json_encode 算签名、发送时又被重新序列化);② 字段间分隔符不是 \n;③ 业务端点误用了 appsecret 作密钥(应该用 access_token)。
Q:40104 但我刚取的令牌? 检查 X-Open-Token 请求头名是否正确、值里是否混入空格或换行;令牌有效期 2 小时。
Q:40301 是什么? 该接入方还没完成合规签约。请到商户后台「合规中心」签署,签完平台开通即可。
Q:40901 要不要换 request_id 重试? 不要换。 用同一个 request_id 稍后重试,平台会返回真实结果。
Q:重试时收到 40004,是不是说明前面那次失败了? 不是。 40004 只表示 nonce 重复(你原样重发了)。请换一个新 nonce、保持同一个 request_id 再发一次 —— 平台会告诉你前一次的真实结果。
Q:我上报了但查不到记录? 把 request_id 给平台,若平台查不到记录,说明请求没到平台 —— 请先检查你方是否真的发出、地址是否写对、是否被代理/防火墙拦掉。
Q:我换了密钥,为什么突然全断? 大概率是平台执行了「重置」而不是「轮换」 —— 重置会同时作废旧密钥与全部令牌。 下次定期换密钥请明确要求轮换(旧密钥有重叠期、令牌不断)。详见 §3.1。
Q:我刚拿到凭证,第一次调就 40102「服务已停止」? 大概率不是被停服,而是这个接入方还没被开通。正常顺序是:签约 → 平台点开通 → 才可用。急等联调请改用沙箱凭证(沙箱免签约、免开通)。
Q:沙箱能不能绑我的正式商家? 不能。 沙箱接入方必须绑定专用沙箱商家,否则沙箱联调会污染真实客户的会员数据。
附录 A、各接口请求参数速查表
只为省你翻页:每个接口的字段、类型、必填一次列全。公共参数(
appid/timestamp/nonce/签名头)见 §0.2.2,此处不重复。「二选一」表示该组字段至少填一个;「否(默认 X)」表示可不填,不填按 X 处理。
A.0 POST|GET /open/v1/ping
用途:连通性自检(豁免合规门禁,但不豁免开通状态) 详见:§6.2
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
— | — | — | 除公共参数外无其他参数 |
A.1 POST /open/v1/auth/token
用途:—(除公共参数外无) 详见:§6.1
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
appsecret | string | 是 | 在请求体内(JSON 字段)。仅本接口用它验签,不放进 URL |
A.2 POST /open/v1/member/bind
用途:绑定贵司会员与我方账本账户(一对一) 详见:§6.3
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_uid | string | 是 | 贵司会员唯一标识。全站主键,一经绑定不可改 |
phone | string | 二选一 | 会员手机号(11 位)。用于匹配我方已有会员 |
mid | int | 二选一 | 已知我方 mid 时可直接指定(与 phone 二选一) |
bind_type | int | 否(默认 1) | 绑定方式,默认 1 |
A.3 POST /open/v1/member/unbind
用途:解绑(资产保留,重新绑可恢复) 详见:§6.4
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_uid | string | 是 | 要解绑的会员标识 |
A.4 GET /open/v1/member/profile
用途:会员资料(已脱敏:姓名首字/手机前3后4/地址到省市) 详见:§6.5
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_uid | string | 是 | 会员标识 |
A.5 GET /open/v1/member/balance
用途:积分与券余额 详见:§6.6
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_uid | string | 是 | 会员标识 |
A.6 POST /open/v1/order/consume
用途:上报消费:让利入池 + 同步发等额积分 详见:§6.7
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_uid | string | 是 | 会员标识 |
out_order_id | string | 是 | ★ 贵司订单号(幂等键,必须稳定唯一) |
seq | int | 否(默认 1) | 同单序号,部分退款时递增 |
profit | int(分) | 二选一 | 本单让利额。与 member_profit 至少一个 |
member_profit | int(分) | 二选一 | 消费者侧份额。不传 = 等于 profit |
order_amount | int(分) | 是 | 订单实付金额(按实际支付金额核算) |
A.7 POST /open/v1/order/refund
用途:退款回冲:剔出释放基数 + 扣回积分(发券同步扣) 详见:§6.8
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_uid | string | 是 | 会员标识 |
out_order_id | string | 是 | 原上报的订单号(幂等键) |
seq | int | 否(默认 1) | 要与上报时一致 |
A.8 GET /open/v1/pool/summary
用途:奖励池概览(只读,不需 out_uid) 详见:§6.9
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
— | — | — | 除公共参数外无其他参数 |
A.9 GET /open/v1/integral/logs
用途:积分流水(分页) 详见:§6.10
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_uid | string | 是 | 会员标识 |
page | int | 否(默认 1) | 页码 |
limit | int | 否(默认 20) | 每页条数 |
A.10 POST /open/v1/integral/adjust
用途:积分人工调整(默认关闭,需平台开启) 详见:§6.11
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_uid | string | 是 | 会员标识 |
amount | string | 是 | 调整量,可带符号或小数(扣分传负值)。受单笔上限约束(默认 1000) |
reason | string | 是 | 调整原因(会留痕,请写清楚,事后对账要用) |
operator | string | 是 | 操作人标识(贵司侧经办人,会留痕) |
out_order_id | string | 是 | ★ 幂等键(内部单号) |
seq | int | 否(默认 1) | 同单序号 |
A.11 POST /open/v1/member/data-request
用途:个人信息合规通道(查询/删除权,删除=匿名化) 详见:§6.12
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_uid | string | 是 | 会员标识 |
type | string | 否(默认 query) | query 查询 / delete 删除(匿名化) |
reason | string | 否 | 事由(默认「消费者行使删除权」),会留痕 |
out_order_id | string | 是 | ★ 幂等键(合规动作也要可追溯) |
seq | int | 否(默认 1) | 同单序号 |
A.12 位号保留(原「
POST /open/v1/coupon/grant」已随直接发券下线,见 §6.14)。
A.13 GET /open/v1/coupon/balance
用途:券余额(商家专属层) 详见:§6.13
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_uid | string | 是 | 会员标识 |
A.14 GET /open/v1/coupon/logs
用途:券流水(每笔带单号可倒查) 详见:§6.13
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_uid | string | 是 | 会员标识 |
page | int | 否(默认 1) | 页码 |
limit | int | 否(默认 20) | 每页条数 |
A.15 POST /open/v1/coupon/verify
用途:券核销(扣减) 详见:§6.15
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_uid | string | 是 | 会员标识 |
amount | int(分) | 是 | 核销金额。余额不足拒绝(40205),不自动截断 |
out_order_id | string | 是 | ★ 幂等键 |
seq | int | 否(默认 1) | 同单序号 |
A.16 POST /open/v1/coupon/unverify
用途:券回退(订单取消/退款) 详见:§6.16
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_uid | string | 是 | 会员标识 |
out_order_id | string | 是 | 原核销时的单号(幂等键) |
seq | int | 否(默认 1) | 要与核销时一致 |
A.17 POST /open/v1/coupon/transfer
用途:券转赠(默认关闭,商户后台可开) 详见:§6.12.1
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
out_uid | string | 是 | 转出方会员标识 |
to_out_uid | string | 是 | 接收方会员标识(须已绑定;不能等于 out_uid) |
amount | int(分) | 是 | 转赠金额,必须 > 0 |
out_order_id | string | 是 | ★ 幂等键 |
seq | int | 否(默认 1) | 同单序号 |
A.18 GET /open/v1/order/query
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
appid | query | string | 是 | 接入方 ID |
timestamp | query | int | 是 | 秒级时间戳 |
nonce | query | string | 是 | 随机串(每次不同) |
out_order_id | query | string | 是 | 业务单号 |
seq | query | int | 否 | 事件序号;不传 = 查全部事件 |
请求头:X-Open-Sign(必需)、X-Open-Token(必需)。
A.19 GET /open/v1/member/list
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
appid | query | string | 是 | 接入方 ID |
timestamp | query | int | 是 | 秒级时间戳 |
nonce | query | string | 是 | 随机串(每次不同) |
page | query | int | 否 | 页码,默认 1 |
limit | query | int | 否 | 每页条数,默认 50,上限 200 |
请求头:X-Open-Sign(必需)、X-Open-Token(必需)。
A.20 GET /open/v1/billing/usage
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
appid | query | string | 是 | 接入方 ID |
timestamp | query | int | 是 | 秒级时间戳 |
nonce | query | string | 是 | 随机串(每次不同) |
period | query | string | 否 | 账期 YYYY-MM,默认当月 |
请求头:X-Open-Sign(必需)、X-Open-Token(必需)。
附录 B、数据字典与枚举
B.1 业务流水事件类型(order/query 返回的 action)
| 值 | 名称 | 含义 | 对应接口 |
|---|---|---|---|
| 1 | consume | 上报消费(发积分 + 入池) | POST order/consume |
| 2 | refund | 退款回冲(扣回积分 + 作废入池) | POST order/refund |
| 3 | grant | (已废弃)发券 | 直接发券已下线,见 §6.14;编号保留不复用 |
| 4 | verify | 券核销(扣减) | POST coupon/verify |
| 5 | unverify | 券回退 | POST coupon/unverify |
| 6 | transfer | 券转赠(转出视角) | POST coupon/transfer |
| 7 | privacy | 个人信息请求(查询 / 匿名化) | POST member/data-request |
| 8 | adjust | 积分人工调整 | POST integral/adjust |
B.2 金额与积分方向(流水表)
| 表 | 字段 | 取值 |
|---|---|---|
| 券流水 | direction(接口输出) | in = 增加 / out = 减少 |
| 积分流水 | direction(接口输出) | in = 增加 / out = 减少 |
| 两者底层 | action(库内) | 1 = 增加 / 0 = 减少 |
⚠️ 注意区分:业务流水(
biz_record)的action是事件类型(上表 B.1,值 1~8);积分/券流水的
action是方向(1=增 0=减)。两者取值空间不同,不要混用。
B.3 order/query 返回的入池状态
| 字段 | 取值 | 含义 |
|---|---|---|
pool[].back_status | normal | 有效,会参与后续释放 |
stop | 已因退款作废,不再参与释放 | |
pool[].back_status_text | 中文说明 | 直接可展示给运营 |
B.4 券的口径字段(member/balance)
| 字段 | 含义 |
|---|---|
coupon_usable_cents | 本次可用额度(= 商家专属券层),单位:分。这是贵司做抵扣判断要用的字段 |
coupon_usable_yuan | 同上,元字符串(便于展示) |
coupon_platform_cents | 平台通用券层(不在本次对接范围,单列,不计入可用额度) |
coupon_scope_note | 口径说明文案 |
★ 券是余额制,不是卡券制(没有一张张独立的券码)。所以只有"余额"与"流水",没有"券列表"。
B.5 会员资料字段(member/profile)
| 字段 | 脱敏规则 | 说明 |
|---|---|---|
phone | 前 3 后 4(如 138****1234) | 合规要求,勿把完整明文透传前端 |
nickname | 仅首字 | |
| 地址 | 只到省/市 |
B.6 账期格式
| 项 | 格式 | 示例 |
|---|---|---|
billing/usage 的 period | YYYY-MM | 2026-10(不传 = 当月) |
附录 C、端到端集成时序
C.1 场景一:用户下单并支付成功(核心)
你方商城 邦斧开放平台
│ │
│ ① 订单支付成功 │
├──── POST /open/v1/order/consume ───────▶│
│ {out_uid, out_order_id, │ ② 让利额入池
│ seq, profit, order_amount} │ ③ 发等额积分(1 元=1 积分)
│◀─── {code:0, data:{record_id}} ────────┤ ④ 同步返回(已记账)
│ │
│ (后续平台按周期自动释放成券,贵司无需实现任何定时逻辑)
│ │
│ ⑤ 想确认结果? │
├──── GET /open/v1/order/query ──────────▶│ 只读,无副作用
│ ?out_order_id=... │
│◀─── {found, events[], pool[]} ─────────┤
注意事项
out_order_id必须是稳定的业务单号(用你方真实订单号,不要用随机串/时间戳)。- 同一单号多笔事件用
seq区分(seq从 1 开始)。 - 网络超时不要慌:用同一单号 + 同一
seq重发(有幂等保护,不会重复记账)。
C.2 场景二:用户用券抵扣
│ ① 结算页先查可用券 │
├──── GET /open/v1/member/balance ─────────▶│
│◀─── {coupon_usable_cents} ───────────────┤
│ │
│ ② 用户勾选「用券抵扣 5 元」 │
├──── POST /open/v1/coupon/verify ─────────▶│ 扣券
│ {out_uid, amount:500, out_order_id} │
│◀─── {code:0} ─────────────────────────────┤
│ │
│ ③ 若该订单后来取消/退款 │
├──── POST /open/v1/coupon/unverify ───────▶│ 把券退回
│ {out_uid, out_order_id, seq} │
│◀─── {code:0} ─────────────────────────────┤
注意事项
- 余额不足会直接拒绝(
40205),不会自动截断 ⇒ 必须先查余额再决定能抵多少。 - 回退必须带原核销的同一
out_order_id(幂等键沿用原核销键)。
C.3 场景三:订单退款
│ ① 你方订单退款 │
├──── POST /open/v1/order/refund ──────────▶│
│ {out_uid, out_order_id, seq} │ ② 扣回当时发的积分
│ │ (扣回额 = 发出积分 − 已释放消耗)
│ │ ③ 这笔让利从释放基数中剔除
│◀─── {code:0} ─────────────────────────────┤ ⇒ 不再参与后续发券
注意事项
- 不接这个接口 = 白送积分。退款场景务必实现。
- 退款后可再用
order/query看到该笔的back_status = stop(已作废)。
C.4 场景四:券自动释放到账(平台侧行为,贵司无需实现)
平台定时任务(按商家配置的周期自动跑)
┌────────────────────────────────────────────────┐
│ ① 出批:计算本批可释放额度 │
│ ② 结算:生成派发明细 │
│ ③ 发券:扣积分 + 发券(券额÷5 = 扣的积分;即 1 积分 = 5 元券) │
│ ⇒ 会员侧现象:积分减少、券增加 │
└────────────────────────────────────────────────┘
贵司唯一要做的事:在展示"我的券"时调 member/balance 拿最新余额; 不要轮询上报接口去等券到账。
附录 D、集成问题排查手册(按现象查)
| 现象 | 最可能原因 | 排查动作 | 解决 |
|---|---|---|---|
所有接口都返回 40002 签名错误 | 签名串拼接不对(最常见) | 用 §4.4 的自检数据先验通;核对 ` | |
| ` 分隔与拼接顺序 | 严格按 §4.1 拼串;注意 sha256hex(rawBody) 是对原始 body 求哈希 | ||
返回 40003 时间戳超期 | 服务器时间不准 | 与 NTP 校时 | 时间偏斜需在 300 秒内 |
返回 40004 nonce 重放 | 重试时复用了同一个 nonce | 检查重试逻辑 | 重试必须换新 nonce,但 out_order_id/seq 保持不变 |
返回 40101 appid 不存在 | appid 传错 / 用了生产 appid 打测试环境 | 核对 appid 与环境 | 沙箱用 §2.2 的账号 |
返回 40104 令牌无效或过期 | 令牌 2 小时到期 / 传错位置 | 检查是否放在头 X-Open-Token | 提前刷新并复用令牌 |
返回 40107 来源 IP 不在白名单 | 出网 IP 变了 | 用 ping 看是否也有此码 | 把新出网 IP 报给平台加入白名单 |
返回 40201 邦斧侧不存在该会员 | 没先调 member/bind | 确认绑定顺序 | 先绑定再上报 |
返回 40205 余额不足 | 券不够扣 | member/balance 查实际余额 | 不要靠截断,先查再扣 |
返回 40207 积分调整未开启 | 开关默认关 | — | 联系平台在参数配置里开启 |
返回 40211 券转赠未开启 | 开关默认关 | — | 在商户后台开启(默认关闭) |
返回 40214 / 40215 | (接口已下线)若真的收到,说明你方对接的是旧版本 → 联系平台 | — | 改走 order/consume 上报让利额 |
返回 42901 限流 | 调用过快 | 看响应头 Retry-After | 按 Retry-After 退避,不要固定 sleep |
返回 50001 服务内部错误 | 平台侧异常 | 记录 request_id | 可重试;连续失败带 request_id 联系平台 |
| 上报成功但"没到账" | 看错字段 / 上报的是别家 / 幂等命中 | 用 order/query 按单号查 | 见 §十 调用可见性 |
| 拿到的响应是 HTML 不是 JSON | ← 平台已修:现在任何异常都返回 JSON 信封 | — | 若仍遇到请立即反馈(这属于平台缺陷) |
附录 E、curl / Postman 快速验证集合
把
APPID/SECRET换成 §2.2 的沙箱账号即可直接跑。签名算法见 §4.3。
# ===== 公共变量 =====
BASE="https://a.jetu.cc"
APPID="bfop261012c8ab974b60"
SECRET="bab2b513dee1dd7e65ad75804f1bb84f7ef50a1e96fd956b"
# ===== 签名函数(bash + openssl)=====
# sign <appid> <timestamp> <nonce> <rawBody> <secret>
sign() {
local s1="${1}\n${2}\n${3}\n"
local bodyHash=$(printf '%s' "${4}" | openssl dgst -sha256 -hex | awk '{print $2}')
printf "${s1}${bodyHash}" | openssl dgst -sha256 -hmac "${5}" -hex | awk '{print $2}'
}
# ===== 1) 取令牌 =====
TS=$(date +%s); NONCE=$(openssl rand -hex 8)
BODY="{\"appsecret\":\"${SECRET}\"}"
SIGN=$(sign "$APPID" "$TS" "$NONCE" "$BODY" "$SECRET")
TOKEN=$(curl -s -X POST "${BASE}/open/v1/auth/token?appid=${APPID}×tamp=${TS}&nonce=${NONCE}" \
-H "X-Open-Sign: ${SIGN}" -H "Content-Type: application/json" -d "${BODY}" \
| python3 -c 'import sys,json;print(json.load(sys.stdin)["data"]["access_token"])')
echo "TOKEN=${TOKEN}"
# ===== 2) 连通性自检 =====
TS=$(date +%s); NONCE=$(openssl rand -hex 8)
SIGN=$(sign "$APPID" "$TS" "$NONCE" "" "$TOKEN")
curl -s "${BASE}/open/v1/ping?appid=${APPID}×tamp=${TS}&nonce=${NONCE}" \
-H "X-Open-Sign: ${SIGN}" -H "X-Open-Token: ${TOKEN}"
# ===== 3) 绑定会员 =====
TS=$(date +%s); NONCE=$(openssl rand -hex 8)
BODY='{"out_uid":"DEMO-001","phone":"13800001234"}'
SIGN=$(sign "$APPID" "$TS" "$NONCE" "$BODY" "$TOKEN")
curl -s -X POST "${BASE}/open/v1/member/bind?appid=${APPID}×tamp=${TS}&nonce=${NONCE}" \
-H "X-Open-Sign: ${SIGN}" -H "X-Open-Token: ${TOKEN}" -H "Content-Type: application/json" -d "${BODY}"
# ===== 4) 上报消费(让利 20 元 = 2000 分)=====
TS=$(date +%s); NONCE=$(openssl rand -hex 8)
BODY='{"out_uid":"DEMO-001","out_order_id":"DEMO-ORD-001","seq":1,"profit":2000,"order_amount":20000}'
SIGN=$(sign "$APPID" "$TS" "$NONCE" "$BODY" "$TOKEN")
curl -s -X POST "${BASE}/open/v1/order/consume?appid=${APPID}×tamp=${TS}&nonce=${NONCE}" \
-H "X-Open-Sign: ${SIGN}" -H "X-Open-Token: ${TOKEN}" -H "Content-Type: application/json" -d "${BODY}"
# ===== 5) 查余额(积分应为 20)=====
TS=$(date +%s); NONCE=$(openssl rand -hex 8)
SIGN=$(sign "$APPID" "$TS" "$NONCE" "" "$TOKEN")
curl -s "${BASE}/open/v1/member/balance?appid=${APPID}×tamp=${TS}&nonce=${NONCE}&out_uid=DEMO-001" \
-H "X-Open-Sign: ${SIGN}" -H "X-Open-Token: ${TOKEN}"
# ===== 6) 按单号查处理结果 =====
TS=$(date +%s); NONCE=$(openssl rand -hex 8)
SIGN=$(sign "$APPID" "$TS" "$NONCE" "" "$TOKEN")
curl -s "${BASE}/open/v1/order/query?appid=${APPID}×tamp=${TS}&nonce=${NONCE}&out_order_id=DEMO-ORD-001" \
-H "X-Open-Sign: ${SIGN}" -H "X-Open-Token: ${TOKEN}"
Postman 环境变量(导入后只需改 TOKEN):
| 变量 | 值 |
|---|---|
base | https://a.jetu.cc |
appid | bfop261012c8ab974b60 |
secret | (沙箱 appsecret,见 §2.2) |
token | 取令牌后填入 |
附录 F、服务等级与技术支持
F.1 服务指标(生产环境)
| 指标 | 承诺值 | 说明 |
|---|---|---|
| 可用性 | ≥ 99.9%(月度) | 不含计划维护窗口 |
| 接口响应(P95) | ≤ 300 ms | 查询类接口 |
| 接口响应(P99) | ≤ 1000 ms | 写入类接口(含入池与积分记账) |
| 单接入方限流 | 600 次/分钟(默认,可调) | 单接口维度另有独立配额 |
| 令牌有效期 | 2 小时 | 支持轮换与重叠期 |
F.2 技术支持渠道与响应时间
| 级别 | 场景 | 响应时间 | 渠道 |
|---|---|---|---|
| P0 严重 | 生产环境全部接口不可用 / 资产数据异常 | 30 分钟内 | 电话 + 专属对接群 |
| P1 高 | 核心接口(下单/核销)异常;数据不一致 | 2 小时内 | 专属对接群 |
| P2 中 | 非核心接口异常;文档疑问 | 1 个工作日内 | 对接群 / 工单 |
| P3 低 | 咨询、优化建议、新需求 | 3 个工作日内 | 对接群 / 工单 |
报障请务必提供:request_id、appid、out_order_id、发生时间、完整请求与响应。 有了 request_id,我们能在调用日志里精确定位到那一次请求(含请求参数、返回、耗时)。
F.3 联调支持
| 事项 | 说明 |
|---|---|
| 沙箱账号 | 文档 §2.2 直接提供,无需申请 |
| 加速释放 | 沙箱可临时把释放周期调成 1 天(需告知我们) |
| 独立沙箱 | 需要与他人隔离的独立沙箱账号可单独开通 |
| 联调会议 | 重要接入方可安排技术对接会(含接口走查) |
F.4 数据与安全
| 项 | 说明 |
|---|---|
| 传输加密 | 生产环境 HTTPS;沙箱为便于调试为 HTTP(不要传真实个人信息) |
| 凭证存储 | appsecret 平台侧仅存 bcrypt 哈希,明文只在创建/重置时返回一次 |
| 密钥轮换 | 支持轮换(有重叠期,旧密钥在新密钥生效后仍可用一段时间);泄露应急走重置 |
| 个人信息 | 手机号/姓名/地址默认脱敏;提供查询与匿名化通道 |
| 数据导出 | 合作终止时可导出全部数据交给贵司(流式 CSV) |
| 规则快照 | 每笔业务固化当时生效的规则,事后改配置不影响已发生的账 |
F.5 接口变更策略
- 接口只增不改:已发布的接口路径、参数语义、返回字段含义不会变更。
- 允许新增:新错误码、新接口、响应中新增字段(贵司应有忽略未知字段的容错)。
- 如需破坏性变更:提前 30 天书面通知,并提供并行过渡期(新旧版本同时可用)。
- 文档每次变更都在「变更记录」中留痕,并更新版本号。
十五、变更记录
| 版本 | 日期 | 变更 |
|---|---|---|
| v1.5.1 | 2026-10-12 | ★ 修正积分与券的换算方向写反:§0.3 表格与附录 C 场景四流程图原写「5 积分 = 1 元券」,与实际相反。按代码 Member.php 释放公式 扣积分 = 券额 ÷ 5 ⇒ 正确为 1 积分 = 5 元券(发 1 元券扣 0.2 积分)。原文同行的「20 积分最多释放 100 元券 / 上限 = 积分 × 5」本就正确,与错误比例自相矛盾,一并统一 |
| v1.5.0 | 2026-10-12 | ★★ 移除 POST /open/v1/coupon/grant(直接发券) —— 它绕过奖励池直接给会员加券,使券与积分、利润脱钩(池子相关代码 0 行),会凭空产生无资金支撑的抵扣。券的唯一合法来源是奖励池按配置释放(上限 = 让利额 × 5),详见 §6.14。接口总数 21 → 20;配置项下线 grant_max_per_order / grant_max_per_day;错误码 40214/40215 保留编号但标记已废弃;业务流水 action=3 编号保留不复用 |
| v1.4.0 | 2026-10-12 | ★ 商用级文档扩充:新增 · §0.3 业务资产模型速览(一张图 + 数字实例 + 三个常见误解,解决"看不懂资产怎么流转") · §2.2 沙箱测试账号(直接可用的 appid/appsecret + 限额表 + 60 秒自测命令,复制即可跑) · 附录 B 数据字典与枚举(事件类型 / 方向 / 入池状态 / 券口径字段;并明确区分「业务流水 action=事件类型」与「积分券流水 action=方向」) · 附录 C 端到端集成时序(下单 / 券抵扣 / 退款 / 自动释放 四个场景) · 附录 D 集成问题排查手册(15 类现象 → 原因 → 排查 → 解决) · 附录 E curl / Postman 快速验证集合(含 bash 签名函数,复制即跑) · 附录 F 服务等级与技术支持(SLA 指标 / 报障分级响应 / 联调支持 / 数据安全 / 接口变更策略) · 接口总览新增「接入优先级」列(必接 6 / 建议 4 / 可选 10) · 顶部新增「文档导航(按角色选读)」 |
| v1.3.0 | 2026-10-12 | ★ 新增 3 个「只读查询类」接口(§6.19~§6.21):GET order/query(按业务单号主动确认处理结果 —— 本平台不做回调,超时后用它确认,只读无副作用)、GET member/list(会员列表 + 各自资产,批量对账)、GET billing/usage(本期用量与账单,自己看成本);接口总数 18 → 21(其中 10 个只读查询类); §0.2.4 补「超时确认」两条并行路径;§5.2 明确异常时也返回 JSON 信封(HTTP 500 时响应体为 code=50001 的 JSON,不会是 HTML) |
| v1.0 | 2026-10-12 | 首版:鉴权、签名、信封、错误码、幂等、限流、可见性、沙箱、合规要求 |
| v1.1.0 | 2026-10-12 | 新增 §3.1 密钥轮换 vs 重置(轮换不断服、重置立即失效);自检清单加轮换约定项;FAQ 加对应排查 |
| v1.2.0 | 2026-10-12 | ★ 面向对接方重写导读:新增「〇、接口总览」(18 接口一览 + 改资产接口三条统一要求)、 「〇之二、术语与公共字段」(术语表 / 公共请求参数 / 公共响应字段 / ★★ 本平台不做回调,全部同步返回 / 超时重试建议 / 金额精度口径)、 附录 A 各接口请求参数速查表(字段·类型·必填一次列全,由代码提取核对);修正章节编号 |
| v1.1.1 | 2026-10-12 | ★ 新增错误码 40108 合作已终止(与 40102 停用彻底分开:停用可恢复、终止不可恢复);★ 40102 描述收窄为"停用"(不再包含终止)★ 限流补单接口维度( rate_limit_api_per_minute,默认不限)—— 防单点打爆,只拦被超限的那一个接口 |
| v1.1.0 | 2026-10-12 | 合规门禁/沙箱/计费/对账等口径成文 |
| v1.0.10 | 2026-10-12 | 开放 coupon/transfer(券转赠)(§6.12.1)+ 40211~40213;★ 明确口径:券不支持提现、支持转赠,转赠开关由商户后台配置(默认关) ★ 修正:本模块写入的券流水(发券/核销/回退/转赠)此前 ordernum 为空 ⇒ 已修,现全部带单号可倒查 |
| v1.0.9 | 2026-10-12 | ★ 补两个漏做的动作:order/consume 同步发放积分(与入池额 1:1)+ 让利率超 20% 拒绝(§6.8.0);order/refund 扣回积分(= 发出 − 已释放消耗,§6.9.1)。★ 明确:平台不乘邦斧会员等级倍率(等级在你方,倍率请你方算好报出) |
| v1.0.8 | 2026-10-12 | 新增 §6.8.1:pool/summary 返回与商家后台看板同名的 current_pool/history_pool 等字段(接口与看板可直接对上);补充积分口径:释放发券扣积分 = min(券额÷5, 会员持有积分),积分不是发券前提,退款不动积分 |
| v1.0.7 | 2026-10-12 | 开放 integral/logs、integral/adjust、member/data-request(§6.10~§6.12);★ 修正:积分是 4 位小数的数值,不是整数,接口以字符串返回,禁止取整(取整丢用户资产); 新增 40207~40210 |
| v1.0.6 | 2026-10-12 | 开放 order/refund(退款回冲)——订单退款后从释放基数里剔除,防"退款订单继续释放券";写明"释放券不回退 / 你方核销的券需另行回退"两类券的边界 |
| v1.0.5 | 2026-10-12 | 开放券组 5 个接口(§6.9~§6.12)与消费入池 / 奖励池概览(§6.7~§6.8); ★ 金额单位统一为整数分;新增 40204/40205/40206;说明 coupon/list 为何不适用(券是余额制不是卡券制) |
| v1.0.4 | 2026-10-12 | member/balance 明确可用券只含商家专属券(平台通用券不在本次范围,单列不计入可用);新增 coupon_platform_cents / coupon_scope_note 字段 |
| v1.0.3 | 2026-10-12 | 开放 A 组「会员与资产」4 个业务接口(§6.3~§6.6):member/bind、member/unbind、member/profile、member/balance;新增错误码 40201/40202/40203;写明券余额两层相加与「冻结是开关非金额」的口径 |
| v1.0.2 | 2026-10-12 | 新增 IP 调用白名单(§9.2)与错误码 40107;限流超限响应补 Retry-After 头;第九节更名为「限流与访问控制」 |
| v1.0.1 | 2026-10-12 | 新增错误码 40106(服务到期);明确 40301 仅作用于非豁免的业务接口;明确重试必须换新 nonce、40004 不代表业务失败;澄清未定义路径需鉴权通过才返 40006 |
契约承诺:签名规则、错误码语义一经发布不再变更,只允许新增错误码或接口;如有必要变更,提前 30 天书面通知并提供并行过渡期。