邦斧开放平台 · 对外接口文档 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 分钟

三条最省时间的提示(很多对接方在这里绕远路):

  1. 先用沙箱账号把链路打通(§2.2 直接给了可用凭证),不要拿生产凭证等开通流程。
  2. 先用 §4.4 的自检数据验签名,再写业务代码 —— 签名错会导致"所有接口都报 40002",很难定位。
  3. 本平台不做回调(§0.2.4),不用写回调验签/状态机;上报结果用 order/query 主动查。

〇、接口总览

共 20 个接口(其中 10 个是「只读查询类」:#2 #5 #6 #9 #10 #13 #14 #18 #19 #20 —— 只读不写、不需要幂等键、 随便调不会改任何数据)。建议按「先连通 → 再绑会员 → 再报业务 → 用查询类对账」的顺序接入。

0.1 一张表看懂所有接口

#方法路径用途优先级改资产幂等键
1POST/open/v1/auth/token签发令牌(2 小时)必接——
2POST/GET/open/v1/ping连通性自检必接——
3POST/open/v1/member/bind绑定外部会员必接—out_uid
4POST/open/v1/member/unbind解绑可选—out_uid
5GET/open/v1/member/profile会员资料(已脱敏)建议——
6GET/open/v1/member/balance积分与券余额必接——
7POST/open/v1/order/consume上报消费(让利入池 + 发积分)必接✔out_order_id + seq
8POST/open/v1/order/refund退款回冲(含扣回积分)建议✔out_order_id + seq
9GET/open/v1/pool/summary奖励池概览(只读)可选——
10GET/open/v1/integral/logs积分流水可选——
11POST/open/v1/integral/adjust积分人工调整(默认关)可选✔out_order_id + seq
12POST/open/v1/member/data-request个人信息合规通道可选✔out_order_id + seq
13GET/open/v1/coupon/balance券余额可选——
14GET/open/v1/coupon/logs券流水可选——
15POST/open/v1/coupon/verify券核销(扣减)必接✔out_order_id + seq
16POST/open/v1/coupon/unverify券回退(订单取消/退款)建议✔out_order_id + seq
17POST/open/v1/coupon/transfer券转赠(默认关)可选✔out_order_id + seq
18GET/open/v1/order/query按业务单号查处理结果(超时确认,只读)建议——
19GET/open/v1/member/list会员列表 + 各自资产(批量对账,只读)可选——
20GET/open/v1/billing/usage本期用量与账单(自己看成本,只读)可选——

优先级说明:必接 6 个(不接则功能不完整)· 建议 4 个(退款、券回退、超时确认、会员资料)· 其余 可选。

最小可用接入 = 必接的 6 个,约 1 天可打通。

「改资产」= 会改变会员积分或券的接口。这类接口必须实现幂等(用上表的幂等键),

只有它们需要传 out_order_id;查询类接口不需要。

0.2 「改资产」接口的统一要求(三条,务必先看)

  1. out_order_id 必须是稳定的业务单号(不是随机串、不是时间戳)——

重复上报靠它去重;用随机串会导致同一笔钱被记两次。

  1. 金额一律整数分(1000 = 10 元)。全站不出现浮点金额。
  2. 重复调用是安全的:同幂等键再次提交会返回首次的结果并带 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%)

时点本批释放券会员积分会员可用券说明
下单当时—200让利入池 + 发等额积分
第 1 批10 元20 − 2 = 1810 元扣 10÷5 = 2 积分
第 2 批5 元18 − 1 = 1715 元扣 5÷5 = 1 积分
第 3 批2.5 元16.517.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 公共请求参数(所有接口都要带)

参数位置类型必填说明
appidURL querystring是接入方标识
timestampURL queryint是当前 Unix 秒级时间戳。与服务器相差超过 ±300 秒会被拒(40003)
nonceURL querystring是随机串(建议 16 位随机 hex)。同一 nonce 5 分钟内不可重复,否则报 40004
X-Open-SignHeaderstring是签名,算法见 §4
X-Open-TokenHeaderstring业务接口是 / auth/token 否访问令牌。取令牌时用 appsecret 自身验签
request_idBody 或 querystring否(强烈建议)幂等辅助;填了就按它去重,超时重试请换新值
Content-TypeHeader—POST 是application/json

0.2.3 公共响应字段(所有接口统一)

{ "code": 0, "msg": "成功", "data": { }, "request_id": "本次请求的 request_id(回显)" }
字段类型说明
codeint0 表示成功;非 0 见 §七 错误码表。请只判 code,不要判 msg 文本
msgstring给人看的中文提示,不要用于程序判断(措辞可能优化)
dataobject/null业务数据;失败时为 null
request_idstring回显贵司传的 request_id,便于双方对账定位

msg 会写进用户界面吗?不会 —— 它是给贵司技术人员排障看的。面向消费者的文案请贵司自己组织。

0.2.4 ★★ 交互模式:本平台不做回调,全部同步返回

这一点请务必先知道,可以省掉大量对接工作:

(这是业务规则,不是接口延迟)。贵司只需定时查 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 倍错误的地方)


一、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>&timestamp=<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>&timestamp=<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
appidbfop261012c8ab974b60
appsecretbab2b513dee1dd7e65ad75804f1bb84f7ef50a1e96fd956b
数据范围仅沙箱专用商家的数据(碰不到任何真实客户商家的数据)

这个账号的限额(刻意压到最低,防止误用):

项沙箱值生产默认值
限流30 次/分钟(单接口 10 次/分钟)600 次/分钟
单笔发券上限10 元1000 元
单日累计发券上限50 元10000 元
积分人工调整关闭默认关闭,需平台开启
个人信息匿名化关闭默认关闭,需平台开启
券转赠开启(便于体验)默认关闭,商户后台可开
计费不计费按合同

拿到账号后 60 秒自测(复制即可跑):

# 1) 取令牌(把 <ts> 换成当前秒级时间戳、<nonce> 换成任意随机串)
curl -s "https://a.jetu.cc/open/v1/auth/token?appid=bfop261012c8ab974b60&timestamp=<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&timestamp=<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

安全提醒:

3.1 密钥轮换 vs 密钥重置(★ 请分清,用错会中断服务)

平台提供两个操作,后果完全不同:

轮换(计划性,推荐)重置(应急)
用途按安全规范定期更换密钥密钥泄露、必须立即作废
旧密钥保留重叠期(默认 24 小时)内仍可用立即失效
已签发的 access_token全部继续有效(不断服)立即全部失效
客户侧体验无中断:先上新密钥跑通、再下旧密钥服务中断,直到换上 新密钥

⇒ 定期轮换请要求平台用「轮换」(说清是轮换,避免被误当作重置而中断你的服务)。

推荐的轮换操作顺序(全程零失败):

① 请平台执行「轮换」→ 你方拿到新密钥(明文只显示一次)
② 你方把新密钥配置上线(此时新、旧密钥同时有效,重叠期内随便切)
③ 观察确认新密钥调用正常
④ 重叠期自然结束,旧密钥自动失效 —— 你方无需做任何操作

你方应在自己系统里记录密钥的启用/停用时间,避免把两把密钥的用途搞混(例如误把旧密钥留在配置里)。


四、签名算法(契约,不可变)

4.1 规则

payload = appid + "\n" + timestamp + "\n" + nonce + "\n" + request_id + "\n" + sha256hex(rawBody)
sign    = HMAC-SHA256(payload, secret)          输出小写十六进制

4.2 参数位置(硬规定)

参数位置
appid、timestamp、nonce、request_idURL 查询串(query string)
签名 signHTTP 请求头 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 签名自检(★ 请务必先用这组数据验通,再写业务代码)

用下面这组固定输入跑你方实现,结果必须逐字节一致:

输入值
appidbfoptest0001
timestamp1800000000
nonceabcdef1234567890
request_iddemo-0001
rawBody{"note":"hello"}
secret000000000000000000000000000000000000000000000000(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": "你在查询串里传的值原样回传"
}
字段说明
code0 = 成功;非 0 = 错误(见第七节)。请用 code 判断成功,不要用 msg(msg 是人看的文案,可能微调)
msg人话说明,可直接展示给运营
data业务数据;无数据时为 null
request_id原样回传,便于对账与排查

幂等命中额外带 "idempotent": true(见第八节)。

5.2 HTTP 状态码

code 区间HTTP 状态
0200
40001–40099400
40101–40199401
40301–40399403
404xx(接口不存在 40006)404
40901409
42901429
500xx500

请同时判断 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 传输与编码


六、接口清单

6.1 POST /open/v1/auth/token —— 签发令牌

项内容
查询串appid、timestamp、nonce、request_id(可选)
请求头X-Open-Sign
请求体{"appsecret":"<你的密钥>"}
签名密钥appsecret
幂等否(每次调用签发新令牌)
豁免本接口豁免合规门禁(不校验 agreement_status);但同样不豁免「开通状态」(未开通 → 40102)
响应 dataaccess_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
响应 dataappid、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(不报错)
响应 dataout_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(不报错,避免重试风暴)
响应 dataout_uid、mid、unbound(本次是否真的解绑了)

★ 解绑不影响用户已有积分与券:权益保留在邦斧侧,只是外部身份不再关联。

解绑后该 out_uid 再查余额会得到 40203;若之后重新绑定同一个会员,会复用原有映射(历史流水不断)。

6.5 GET /open/v1/member/profile —— 会员资料(已脱敏)

项内容
查询串appid、timestamp、nonce、out_uid、request_id(可选)
响应 datamid、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,不会重复入池
响应 datarecord_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 同一套键,所以必须传上报时用的那个订单号)
幂等是。重复调用不会重复回冲
响应 datafound(该订单是否入过池)、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 重复核销不会重复扣减
响应 dataused_cents、left_cents、idempotent

★ 一次消费要核销多次怎么办(如分单核销):用不同的 seq。

6.16 POST /open/v1/coupon/unverify —— 券回退(订单取消 / 退款)

项内容
请求体{"out_uid":"...","out_order_id":"V-1","seq":1}
金额来源取自原核销记录,不需要也不允许你方指定金额 —— 杜绝"退得比扣得多"
一次一退一次核销只能回退一次;重复回退返回成功且 idempotent:true,不会重复加券
找不到对应核销40206
响应 datarefunded_cents、left_cents、idempotent

6.19 GET /open/v1/order/query —— 按业务单号查询处理结果(★ 超时确认用)

为什么有这个接口:本平台不做回调(见 §0.2.4),上报后如果遇到网络超时,贵司需要一种 不产生任何副作用的方式确认"这笔到底处理成功了吗"。这个接口就是干这个的。

请求参数

参数类型必填说明
out_order_idstring是业务单号(贵司自己的单号,与上报时一致)
seqint否事件序号。不传 = 查该单号下的全部事件(最多 50 条)

响应 data 字段

字段类型说明
foundbool本平台是否查到该单号的处理记录
event_countint查到的事件条数
events[]array每条事件:action(consume/refund/grant/verify/unverify/transfer/adjust/privacy)、seq、amount_cents、integral、biz_id、processed_at
coupon_logsint该单号在券流水里的条数
integral_logsint该单号在积分流水里的条数
pool[]array入池记录:in_pool_cents(入池金额,分)、back_status、back_status_text("有效(会参与后续释放)" / "已因退款作废(不再参与释放)")、record_id
hintstring给贵司的处置建议(查不到时会明确告诉你下一步怎么做)

★ found: false 不等于失败。 可能是:还没到达本平台、仍在重试中、或者单号写错了。 此时正确做法是重发——用同一 out_order_id + seq(有幂等保护,不会重复记账), 不要换新单号(换新单号会变成一笔新的业务)。

示例

GET /open/v1/order/query?appid=bfop260101xxxxxxxx&out_order_id=SO20261012001&timestamp=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 在会员上千时不可行。

请求参数

参数类型必填说明
pageint否页码,默认 1
limitint否每页条数,默认 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 —— 本期用量与账单

为什么有这个接口:贵司需要在自己系统里看"这个月调了多少次、要交多少钱",不用每次问平台。

请求参数

参数类型必填说明
periodstring否账期,格式 YYYY-MM,默认当月

响应 data 字段

字段类型说明
usage.http_callsint本期实际收到的请求数 = 日志行数 + 幂等重放次数(用它能和贵司自己的请求日志对上)
usage.success / usage.failedint成功 / 失败次数
usage.idempotent_replayint幂等命中次数 —— 不计费
usage.billable_callsint计费调用数(只算成功且非沙箱)
usage.is_sandboxint沙箱接入方为 1(沙箱整月调用不计费)
billobject\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
40004nonce 重复同一 nonce 在 5 分钟内二次使用(含网络重试原样重发)每次请求生成新 nonce
40005请求体不是合法 JSONContent-Type 声明 JSON 但内容非 JSON修正序列化
40006接口不存在路径拼错核对路径
40101appid 不存在appid 写错 / 环境不对(测试凭证打了生产)核对凭证与环境
40102接入方服务已停止① 被平台停用(一键断服,旧令牌同时失效;可恢复)② 该接入方尚未被平台开通(常见:刚拿到凭证就调)先确认是否已「签约 + 开通」;否则联系平台
40103appsecret 校验失败密钥错误 / 已被重置使用最新密钥
40104access_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 你方必须做的

  1. 写接口必带 request_id,取值建议:你方业务单号 + 操作类型(如 ORDER123456:consume)
  2. 超时不要换 request_id:超时后用同一个 request_id 重发,平台会告诉你真实结果
  3. 非幂等接口(如 auth/token)不要复用 request_id
  4. 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

上线前请把这三件事确认掉:

  1. 报准出口 IP:不是「服务器内网 IP」,而是访问外网时对端看到的公网 IP。

可用 curl https://ifconfig.me 在你方服务器上查。若你方走 NAT/网关/云函数,要报网关的出口 IP。

  1. 覆盖变化范围:若你方出口 IP 是浮动池或会扩容,请把整个网段报过来(如 203.0.113.0/24),

否则某台机器扩容后就会突然收到 40107。

  1. 双向对等:平台回调你方(如事件通知,后续开放)时,也需要你方把我方出口 IP 加入你方白名单 ——

届时平台会书面提供固定出口 IP 清单。

运维提醒:40107 通常不是故障,而是你方出口 IP 变了。如果业务突然中断且返回 40107,

先自查出口 IP,再带 request_id 联系平台。


十、调用可见性(排查「我上报了但没到账」)

10.1 平台侧记录

平台对每一次调用都留痕(不论成功失败、不论有没有 request_id),记录:时间、接口、request_id、业务单号、结果码、失败原因、耗时、来源 IP、脱敏后的请求体。

10.2 你方遇到「上报了但没到账」的排查顺序

  1. 你方是否拿到响应? 没拿到 → 网络/超时问题
  2. 响应是 code=0 吗? 不是 → 按第七节处理
  3. 把 request_id 提供给平台方,平台可立刻定位:
  4. 查不到记录 ⇒ 请求根本没到平台(你方没发出、地址写错、被中间层拦掉)
  5. 有记录且是失败 ⇒ 记录里有明确原因(如会员不存在)
  6. 有记录且成功 ⇒ 问题在后续业务环节,带上记录一起排查

10.3 你方应自留


十一、沙箱环境

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/设备/时间),双方均可下载《签署证明》。


十三、接入自检清单(提交联调前请逐项确认)


十四、常见问题

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

字段类型必填说明
appsecretstring是在请求体内(JSON 字段)。仅本接口用它验签,不放进 URL

A.2 POST /open/v1/member/bind

用途:绑定贵司会员与我方账本账户(一对一) 详见:§6.3

字段类型必填说明
out_uidstring是贵司会员唯一标识。全站主键,一经绑定不可改
phonestring二选一会员手机号(11 位)。用于匹配我方已有会员
midint二选一已知我方 mid 时可直接指定(与 phone 二选一)
bind_typeint否(默认 1)绑定方式,默认 1

A.3 POST /open/v1/member/unbind

用途:解绑(资产保留,重新绑可恢复) 详见:§6.4

字段类型必填说明
out_uidstring是要解绑的会员标识

A.4 GET /open/v1/member/profile

用途:会员资料(已脱敏:姓名首字/手机前3后4/地址到省市) 详见:§6.5

字段类型必填说明
out_uidstring是会员标识

A.5 GET /open/v1/member/balance

用途:积分与券余额 详见:§6.6

字段类型必填说明
out_uidstring是会员标识

A.6 POST /open/v1/order/consume

用途:上报消费:让利入池 + 同步发等额积分 详见:§6.7

字段类型必填说明
out_uidstring是会员标识
out_order_idstring是★ 贵司订单号(幂等键,必须稳定唯一)
seqint否(默认 1)同单序号,部分退款时递增
profitint(分)二选一本单让利额。与 member_profit 至少一个
member_profitint(分)二选一消费者侧份额。不传 = 等于 profit
order_amountint(分)是订单实付金额(按实际支付金额核算)

A.7 POST /open/v1/order/refund

用途:退款回冲:剔出释放基数 + 扣回积分(发券同步扣) 详见:§6.8

字段类型必填说明
out_uidstring是会员标识
out_order_idstring是原上报的订单号(幂等键)
seqint否(默认 1)要与上报时一致

A.8 GET /open/v1/pool/summary

用途:奖励池概览(只读,不需 out_uid) 详见:§6.9

字段类型必填说明
———除公共参数外无其他参数

A.9 GET /open/v1/integral/logs

用途:积分流水(分页) 详见:§6.10

字段类型必填说明
out_uidstring是会员标识
pageint否(默认 1)页码
limitint否(默认 20)每页条数

A.10 POST /open/v1/integral/adjust

用途:积分人工调整(默认关闭,需平台开启) 详见:§6.11

字段类型必填说明
out_uidstring是会员标识
amountstring是调整量,可带符号或小数(扣分传负值)。受单笔上限约束(默认 1000)
reasonstring是调整原因(会留痕,请写清楚,事后对账要用)
operatorstring是操作人标识(贵司侧经办人,会留痕)
out_order_idstring是★ 幂等键(内部单号)
seqint否(默认 1)同单序号

A.11 POST /open/v1/member/data-request

用途:个人信息合规通道(查询/删除权,删除=匿名化) 详见:§6.12

字段类型必填说明
out_uidstring是会员标识
typestring否(默认 query)query 查询 / delete 删除(匿名化)
reasonstring否事由(默认「消费者行使删除权」),会留痕
out_order_idstring是★ 幂等键(合规动作也要可追溯)
seqint否(默认 1)同单序号

A.12 位号保留(原「POST /open/v1/coupon/grant」已随直接发券下线,见 §6.14)。

A.13 GET /open/v1/coupon/balance

用途:券余额(商家专属层) 详见:§6.13

字段类型必填说明
out_uidstring是会员标识

A.14 GET /open/v1/coupon/logs

用途:券流水(每笔带单号可倒查) 详见:§6.13

字段类型必填说明
out_uidstring是会员标识
pageint否(默认 1)页码
limitint否(默认 20)每页条数

A.15 POST /open/v1/coupon/verify

用途:券核销(扣减) 详见:§6.15

字段类型必填说明
out_uidstring是会员标识
amountint(分)是核销金额。余额不足拒绝(40205),不自动截断
out_order_idstring是★ 幂等键
seqint否(默认 1)同单序号

A.16 POST /open/v1/coupon/unverify

用途:券回退(订单取消/退款) 详见:§6.16

字段类型必填说明
out_uidstring是会员标识
out_order_idstring是原核销时的单号(幂等键)
seqint否(默认 1)要与核销时一致

A.17 POST /open/v1/coupon/transfer

用途:券转赠(默认关闭,商户后台可开) 详见:§6.12.1

字段类型必填说明
out_uidstring是转出方会员标识
to_out_uidstring是接收方会员标识(须已绑定;不能等于 out_uid)
amountint(分)是转赠金额,必须 > 0
out_order_idstring是★ 幂等键
seqint否(默认 1)同单序号

A.18 GET /open/v1/order/query

参数位置类型必填说明
appidquerystring是接入方 ID
timestampqueryint是秒级时间戳
noncequerystring是随机串(每次不同)
out_order_idquerystring是业务单号
seqqueryint否事件序号;不传 = 查全部事件

请求头:X-Open-Sign(必需)、X-Open-Token(必需)。

A.19 GET /open/v1/member/list

参数位置类型必填说明
appidquerystring是接入方 ID
timestampqueryint是秒级时间戳
noncequerystring是随机串(每次不同)
pagequeryint否页码,默认 1
limitqueryint否每页条数,默认 50,上限 200

请求头:X-Open-Sign(必需)、X-Open-Token(必需)。

A.20 GET /open/v1/billing/usage

参数位置类型必填说明
appidquerystring是接入方 ID
timestampqueryint是秒级时间戳
noncequerystring是随机串(每次不同)
periodquerystring否账期 YYYY-MM,默认当月

请求头:X-Open-Sign(必需)、X-Open-Token(必需)。

附录 B、数据字典与枚举

B.1 业务流水事件类型(order/query 返回的 action)

值名称含义对应接口
1consume上报消费(发积分 + 入池)POST order/consume
2refund退款回冲(扣回积分 + 作废入池)POST order/refund
3grant(已废弃)发券直接发券已下线,见 §6.14;编号保留不复用
4verify券核销(扣减)POST coupon/verify
5unverify券回退POST coupon/unverify
6transfer券转赠(转出视角)POST coupon/transfer
7privacy个人信息请求(查询 / 匿名化)POST member/data-request
8adjust积分人工调整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_statusnormal有效,会参与后续释放
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 的 periodYYYY-MM2026-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[]} ─────────┤

注意事项

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} ─────────────────────────────┤

注意事项

C.3 场景三:订单退款

   │  ① 你方订单退款                            │
   ├──── POST /open/v1/order/refund ──────────▶│
   │      {out_uid, out_order_id, seq}         │  ② 扣回当时发的积分
   │                                           │     (扣回额 = 发出积分 − 已释放消耗)
   │                                           │  ③ 这笔让利从释放基数中剔除
   │◀─── {code:0} ─────────────────────────────┤     ⇒ 不再参与后续发券

注意事项

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}&timestamp=${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}&timestamp=${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}&timestamp=${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}&timestamp=${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}&timestamp=${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}&timestamp=${TS}&nonce=${NONCE}&out_order_id=DEMO-ORD-001" \
  -H "X-Open-Sign: ${SIGN}" -H "X-Open-Token: ${TOKEN}"

Postman 环境变量(导入后只需改 TOKEN):

变量值
basehttps://a.jetu.cc
appidbfop261012c8ab974b60
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 接口变更策略


十五、变更记录

版本日期变更
v1.5.12026-10-12★ 修正积分与券的换算方向写反:§0.3 表格与附录 C 场景四流程图原写「5 积分 = 1 元券」,与实际相反。按代码 Member.php 释放公式 扣积分 = 券额 ÷ 5 ⇒ 正确为 1 积分 = 5 元券(发 1 元券扣 0.2 积分)。原文同行的「20 积分最多释放 100 元券 / 上限 = 积分 × 5」本就正确,与错误比例自相矛盾,一并统一
v1.5.02026-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.02026-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.02026-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.02026-10-12首版:鉴权、签名、信封、错误码、幂等、限流、可见性、沙箱、合规要求
v1.1.02026-10-12新增 §3.1 密钥轮换 vs 重置(轮换不断服、重置立即失效);自检清单加轮换约定项;FAQ 加对应排查
v1.2.02026-10-12★ 面向对接方重写导读:新增「〇、接口总览」(18 接口一览 + 改资产接口三条统一要求)、
「〇之二、术语与公共字段」(术语表 / 公共请求参数 / 公共响应字段 / ★★ 本平台不做回调,全部同步返回 / 超时重试建议 / 金额精度口径)、
附录 A 各接口请求参数速查表(字段·类型·必填一次列全,由代码提取核对);修正章节编号
v1.1.12026-10-12★ 新增错误码 40108 合作已终止(与 40102 停用彻底分开:停用可恢复、终止不可恢复);
★ 40102 描述收窄为"停用"(不再包含终止)
★ 限流补单接口维度(rate_limit_api_per_minute,默认不限)—— 防单点打爆,只拦被超限的那一个接口
v1.1.02026-10-12合规门禁/沙箱/计费/对账等口径成文
v1.0.102026-10-12开放 coupon/transfer(券转赠)(§6.12.1)+ 40211~40213;
★ 明确口径:券不支持提现、支持转赠,转赠开关由商户后台配置(默认关)
★ 修正:本模块写入的券流水(发券/核销/回退/转赠)此前 ordernum 为空 ⇒ 已修,现全部带单号可倒查
v1.0.92026-10-12★ 补两个漏做的动作:order/consume 同步发放积分(与入池额 1:1)+ 让利率超 20% 拒绝(§6.8.0);order/refund 扣回积分(= 发出 − 已释放消耗,§6.9.1)。
★ 明确:平台不乘邦斧会员等级倍率(等级在你方,倍率请你方算好报出)
v1.0.82026-10-12新增 §6.8.1:pool/summary 返回与商家后台看板同名的 current_pool/history_pool 等字段(接口与看板可直接对上);
补充积分口径:释放发券扣积分 = min(券额÷5, 会员持有积分),积分不是发券前提,退款不动积分
v1.0.72026-10-12开放 integral/logs、integral/adjust、member/data-request(§6.10~§6.12);
★ 修正:积分是 4 位小数的数值,不是整数,接口以字符串返回,禁止取整(取整丢用户资产);
新增 40207~40210
v1.0.62026-10-12开放 order/refund(退款回冲)——订单退款后从释放基数里剔除,防"退款订单继续释放券";
写明"释放券不回退 / 你方核销的券需另行回退"两类券的边界
v1.0.52026-10-12开放券组 5 个接口(§6.9~§6.12)与消费入池 / 奖励池概览(§6.7~§6.8);
★ 金额单位统一为整数分;新增 40204/40205/40206;
说明 coupon/list 为何不适用(券是余额制不是卡券制)
v1.0.42026-10-12member/balance 明确可用券只含商家专属券(平台通用券不在本次范围,单列不计入可用);
新增 coupon_platform_cents / coupon_scope_note 字段
v1.0.32026-10-12开放 A 组「会员与资产」4 个业务接口(§6.3~§6.6):member/bind、member/unbind、member/profile、member/balance;
新增错误码 40201/40202/40203;写明券余额两层相加与「冻结是开关非金额」的口径
v1.0.22026-10-12新增 IP 调用白名单(§9.2)与错误码 40107;限流超限响应补 Retry-After 头;
第九节更名为「限流与访问控制」
v1.0.12026-10-12新增错误码 40106(服务到期);明确 40301 仅作用于非豁免的业务接口;
明确重试必须换新 nonce、40004 不代表业务失败;澄清未定义路径需鉴权通过才返 40006

契约承诺:签名规则、错误码语义一经发布不再变更,只允许新增错误码或接口;如有必要变更,提前 30 天书面通知并提供并行过渡期。