产品授权 · 产品费率设置 · 扣费流程说明
注意面向全链路的通用说明:运营平台、代理、商户、持卡人四方各自「能配什么、配到哪一层、改完什么时候生效、扣费时按什么顺序取价」。 本文只讲规则与流程,不披露任何定价数值(平台成本侧、平台对商户售价、代理价差、价差计提公式均不在本文范围内)。需要具体价格时,请以运营平台与商户后台展示为准。 版本:2026-09-30 · 适用范围:
docs/PRD/allinks现行版本
目录
- 1. 概述:谁配什么、影响谁
- 2. 角色与配置职责
- 3. 产品授权
- 4. 产品费率设置
- 5. 变更冷却期
- 6. 扣费逻辑:取价四步
- 7. 费项目录与叠加互斥规则
- 8. 扣费时机与扣费科目
- 9. 金额计算模型
- 10. 错误码速查
- 11. 排错速查
- 12. 变更记录
1. 概述:谁配什么、影响谁
平台上存在两条互相独立的费率链,它们不是同一个东西,配置入口、冷却规则、错误码都不同。初次接触最容易踩的坑就是把两者混为一谈。
| 价差链 | 实扣链 | |
|---|---|---|
| 管什么 | 代理 → 商户 → 持卡人 三层之间的分配比例 | 商户/持卡人实际被扣多少钱 |
| 谁能改 | 运营平台、代理(有归属校验) | 运营平台(商户只能覆盖售价侧,见 §4.4) |
| 配置载体 | 商户费率 / 持卡人费率 行 | 费项(FeeItem)+ 商户覆盖 |
| 变更冷却 | 已有(商户费率 7×24h、持卡人费率 3×24h) | 2026-09-30 起补齐,默认 24 小时(见 §5) |
| 拒绝时的错误码 | 3103 RATE_COOLDOWN | FEE_423 FEE_COOLDOWN |
本文档主线是实扣链:产品授权 → 产品费率设置(费项) → 扣费。价差链只在下层不得低于上层(§4.3)与冷却时长对照处提及。
一句话概括各层职责:
运营平台 产品目录 + 平台费项(成本侧/售价侧) ← 唯一能新建/编辑/停用费项的角色
↓ 产品授权(授权哪些产品给哪个商户 + 开卡配额 + 交易限额)
商户 覆盖费项售价侧 + 给持卡人配实付费率 ← 不能新增/删除费项
↓ 商户覆盖(写即生效,无独立审批)
持卡人 不可自助改费率,只能看到自己账户上的实际发生额2. 角色与配置职责
| 角色 | 能改什么 | 在哪配 | 关键限制 |
|---|---|---|---|
| 运营平台 | 产品目录(上下架、默认币种) | 平台管理 → 产品管理 | — |
| 平台费项:新建 / 编辑 / 停用 / 补挂产品 | 平台管理 → 产品费项目录、产品详情 → 费率设置 | 每次成功变更后进入变更冷却(§5) | |
| 商户的产品授权与开卡配额、交易限额 | 平台管理 → 商户详情 → 产品授权 | 敏感写,需 2FA 动态验证码 | |
| 商户费率 / 持卡人费率 | 平台管理 → 商户详情 → 产品费率配置 | 有下层不得低于上层、上限、冷却三重校验 | |
| 代理 | 下级商户的产品授权 | 当前无此入口,仅可查看名下商户 | — |
| 下级商户费率、持卡人费率 | 代理后台 → 商户费率 | 仅限本代理名下且状态正常的商户 | |
| 商户 | 费项售价侧覆盖(固定额 / 费率二选或都覆盖) | 商户后台 → 渠道 → 费率 | 不能覆盖成本侧;不能覆盖未挂产品的全局费项;写即生效 |
| 持卡人实付费率 | 商户后台 → 渠道 → 费率 | 不得低于本商户商户费率;不得高于平台上限 | |
| 持卡人 | 无 | — | 全系统没有任何持卡人侧费率写入口 |
注意说明:运营平台页面文件名为「商户产品费率配置」,但它是平台管理员在配置某个商户的授权与费率,不是商户自助页面。商户自助页面是只读 + 覆盖两类动作。
3. 产品授权
3.1 业务含义
产品授权回答的是:「这个商户能不能卖这个卡产品、能开多少张卡、单笔/单日/单月能刷多少」。它不涉及价格,只涉及「能不能做」和「做多少」。
授权是商户可售产品列表的唯一真源。商户在后台看到的可售产品 = 授权表中启用状态的记录 ∩ 平台产品目录中已上架且资料齐备的产品。商户端只读,不能自己维护这张表。
3.2 配置方式
| 项 | 说明 |
|---|---|
| 配置角色 | 仅运营平台(需商户写权限 + 2FA 动态验证码) |
| 接口 | PUT /admin/api/v1/merchants/{merchantId}/products |
| 语义 | 增量更新,不是全量覆盖。请求体中未出现的授权项保持原样;撤销授权要把该项显式提交为「停用」 |
| 幂等 | 需带 Idempotency-Key;同一幂等键带不同请求体会报 1009 IDEMPOTENCY_CONFLICT |
| 并发 | 请求体带 version 乐观锁,版本不匹配返回 OPTIMISTIC_LOCK |
请求体每项字段:
| 字段 | 必填 | 说明 |
|---|---|---|
productId | 是 | 平台产品 ID,必须是产品目录中已存在的卡产品 |
status | 是 | 1 = 启用授权;0 = 撤销授权(停用后该产品从商户可售列表移除) |
cardQuota | 否 | 开卡配额,null = 不限 |
limitSingleMax | 否 | 单笔交易限额上限 |
limitDailyMax | 否 | 单日累计交易限额上限 |
limitMonthlyMax | 否 | 单月累计交易限额上限 |
3.3 生效与状态
授权状态只有两态:1 启用 / 0 停用。授权变更没有审批流,运营平台提交即生效,并写入只读审计(记录动作、操作人、变更前后值)。
生效期字段在授权记录中存在,但当前平台接口不接受运营填写,一律按无界处理(启用即长期有效,停用即失效)。若业务上需要「某段时间内有效」,目前需要在产品目录侧用上下架来近似控制。
3.4 配额与限额的执行口径
- 交易限额三字段是真生效的:交易发起时校验单笔/单日/单月上限,超限直接拒绝该笔交易并返回参数校验类错误。
警告警告:开卡配额不是硬性名额控制。 目前系统不按开卡张数拦截开卡动作,配额超限不会阻止开卡。请不要把「设置了开卡配额」当作硬性名额控制,需要硬控时应使用交易限额或产品目录侧的上下架。
4. 产品费率设置
4.1 两条链的分工
| 价差链(费率行) | 实扣链(费项) | |
|---|---|---|
| 回答的问题 | 商户按什么比例向持卡人分销、平台按什么比例向商户结算 | 商户/持卡人实际被扣多少 |
| 关键对象 | 商户费率、持卡人费率 | 费项(FeeItem)+ 商户覆盖 |
| 层级 | 平台授权价 → 商户费率 → 持卡人费率(逐层含成本) | 平台费项 → 商户售价覆盖 |
| 配置页面 | 商户详情 → 产品费率配置 | 产品详情 → 费率设置;产品费项目录 |
本节重点是实扣链(费项),层级约束部分会引用价差链。
4.2 费项字段字典
一个费项 = 「某个产品 + 某个收费项目 + 某个币种」下的一个定价版本。
| 字段 | 说明 | 配置注意 |
|---|---|---|
feeCode | 收费项目码,取自官方目录(§7) | 目录外的码不允许新建 |
feeType | 收费大类:交易类 / 退款争议类 / ATM 类 / 账户类 / 周期类 | 与目录语义对齐 |
rateMode | 计费模式:FIXED / RATE / FIXED_PLUS_RATE | 三态计算模型见 §9,与实际扣费口径必须一致 |
| 金额字段 | 固定额,单位为产品币种,传输与存储一律为字符串,禁止数字类型 | 例:"2.50",不是 2.5 |
| 费率字段 | 万分比,"250" 表示 2.5% | 单位是万分比不是百分比,见 §9 |
currency | 币种,必须与产品默认币种一致 | 一个币种一条独立费项,不跨币种共用 |
minAmount / maxAmount | 适用金额区间,左闭右开 min ≤ 金额 < max | 留空 = 不设上下限(任意金额命中) |
regionList | 适用地区清单 | 留空 = 全球适用 |
mccList | 适用商户类别码清单 | 留空 = 全类别适用 |
chargeSubject | 扣费科目:卡余额 / 账户可用 / 商户通道头寸 | 多数交易类为卡余额;账户类为账户可用 |
description | 说明文字 | 便于后续核对 |
active | 是否启用 | 停用是软删,不物理删除 |
警告警告:区间与清单留空的口径是「全命中」,不是「不生效」。 这是运营最容易配错的一条:
FEE_SPECIAL_REGION(特殊地区商户手续费)如果地区清单留空且处于启用状态,会对所有地区的每笔交易命中计费。上线前务必填入目标地区清单,或先保持停用。
4.3 层级约束:下层不得低于上层
实扣链与价差链共同遵守一条原则:任何一层对外收取的价格,都不得低于它上游给这一层的成本。
平台授权价 ≤ 商户费率(价差链)
平台费项售价 ≤ 商户覆盖后的售价(实扣链)
商户费率 ≤ 持卡人实付费率(价差链)- 商户把费率或覆盖价配得比上游成本低,会被服务端直接拒绝,错误码
3101RATE_BELOW_FLOOR。 - 商户把费率配得高于平台上限,会被拒绝,错误码
3102RATE_ABOVE_CEILING。平台上限目前是系统内置约束,不是可配置项。 - 覆盖成本侧的防倒挂校验已按 2026-09-20 的需求调整放开,商户可自定义售价,实扣时不再因倒挂被拒。因此定价合理性由商户自行负责,平台只保留下限与上限两道硬闸。
- 倒挂在费率中心「试算」页以数据形式呈现:每条命中的费项并排给出实扣售价与成本价,并标出该费项是否被商户覆盖,运营一眼可辨。试算不会为实扣链的倒挂单独弹告警——页面上唯一叫「费率倒挂」的告警属于价差链(商户费率费用低于授权成本费用),与本条不是一回事。实扣链倒挂只落服务端 WARN 日志,不阻断交易。
4.4 商户覆盖规则
商户对平台费项只能做「售价侧覆盖」,且必须满足:
| 规则 | 说明 | 违反时 |
|---|---|---|
| 只能覆盖平台已有费项 | 商户没有新增或删除费项的入口 | 无入口 |
| 只覆盖售价侧 | 覆盖请求只能提交固定售价与费率,成本侧不可覆盖 | 请求体不接受成本字段 |
| 费项必须已挂产品 | 全局费项(未挂产品)不允许被覆盖,需运营先把费项挂到产品上 | 参数校验错误 |
| 按逻辑维度锚定 | 覆盖不锚物理版本行,锚定「产品 + 费项码 + 币种」 | — |
| 写即生效 | 覆盖没有独立审批流,商户提交后直接生效 | — |
| 生效区间 | 定价引擎支持生效起止时刻(effectiveStart ≤ now < effectiveEnd,任一为空即该侧无界),但商户侧的提交接口尚未开放这两个字段,服务端一律写入空值。因此现网所有覆盖都是无界的:提交即对全部后续交易生效,不会自动到期。 撤销需商户主动删除覆盖 | — |
| 撤销覆盖 | 商户可删除自己的覆盖记录,删除后回落到平台费项 | 目标覆盖不存在时报 FEE_404 |
平台对商户的覆盖关系有约束:同一费项存在有效覆盖时,平台侧不允许停用该费项,会返回 4003 FEE_ITEM_IN_USE,防止平台操作直接打断商户已生效的定价。
5. 变更冷却期
5.1 为什么有冷却期
费项配错价是直接的资损:改错一个售价或误停用一个费项,影响会在下一笔交易立刻显现,且往往已经无法挽回。变更冷却期给运营留出一个「发现误操作、来不及扩散」的拦截窗口。
此前只有价差链有冷却,实扣链完全没有,认知上不一致。2026-09-30 起,实扣链补齐同构语义。
5.2 规则
| 项 | 规则 |
|---|---|
| 默认时长 | 24 小时 |
| 是否可调 | 时长存在数据列 cooldown_hours 里,改列即改时长,不需要发版。但目前没有管理界面也没有接口能写这一列,只能由 DBA 或运维直接改库;调整只对该费项链此后的新建生效(重建链时承接链上最新行的现值),已在冷却中的行不会被追溯缩短或延长。全新费项链用代码内置的默认 24 小时 |
| 覆盖范围 | 新建费项 / 编辑费项 / 停用费项 三类写操作,成功后立即进入冷却 |
| 不覆盖 | 商户侧的费项售价覆盖不进入本冷却(商户改价走价差链那一侧的规则) |
| 冷却挂载位置 | 挂在该费项链的「当前生效版本」上;编辑产生新版本时冷却值随新版本承接 |
| 存量数据 | 升级前的存量费项冷却截止时刻为空,视为不在冷却,下一次成功变更后才开始计算 |
冷却期间再次提交同类写操作,服务端返回 FEE_423,并在提示中带上冷却截止时刻,前端据此展示剩余时间。
5.3 紧急变更(绕过冷却)
平台保留了绕过开关,用于确有紧急理由的场景(例如上游突发故障必须立刻停用一个费项)。
使用绕过开关必须同时满足:
- 请求显式声明「紧急变更」;
- 强制填写变更原因(缺失或只填空格一律拒绝,服务端校验,不依赖前端提示);
- 经过 2FA 动态验证码;
- 绕过标记与变更原因写入只读审计,事后不可修改、不可清除。
变更原因是三类写操作(新建 / 编辑 / 停用)共用的审计字段:
- 勾选了绕过时必填,留空直接被服务端拒绝;
- 没勾选时选填,留空不会报错,系统会按动作落一条兜底文案(「管理后台新建费项 / 管理后台费项编辑 / 管理后台停用费项」);
- 落库到费项版本链的
change_reason列,与描述字段是两回事——描述是给人看的业务备注,变更原因是审计口径,一经写入不可修改。
2026-09-30 修正:此前管理后台根本没把变更原因传给服务端,落库的一直是硬编码文案,所有变更(含全部紧急绕过)在审计里长得一模一样,停用记录看上去还像是「新建」。现已打通新建 / 编辑 / 停用三条写路径,停用弹窗也补上了原因输入框。
绕过不是常规操作。每次绕过都会在审计留痕,请把它当成需要事后复盘的例外,而不是「嫌麻烦就勾一下」的开关。
5.4 误操作的止损顺序
警告警告:止损动作本身也要冷静确认。停用一个「本来就没人用」的费项不会造成损失,但停用一个正在被大量交易命中的费项会立刻引发大面积异常。 停用前先看该费项近期的实际扣费笔数,确认影响面之后再动手。
发现配错了,按这个顺序处理:
- 先停用有问题的费项(紧急绕过),让错误定价立即退出取价;
- 核对是否有 legacy 全局费项会接管扣费(见 §11.1,停用不等于停止收费);
- 再用正确值重新配置(新费项或新版本行);
- 核对商户覆盖是否也需要同步调整——商户覆盖优先级高于平台费项;
- 复盘这次绕过的原因,补齐配置规范。
6. 扣费逻辑:取价四步
一笔交易真正产生扣费时,系统按固定四步选出最终生效的费项版本。四步是顺序依赖的,任一步不命中就顺延到下一步。
① 由卡反查产品 卡 → 卡所属产品(拿不到产品 = 无产品上下文)
↓
② 取产品费项 产品 + 费项码 + 币种 + 交易时刻,命中该产品下的当前生效版本
↓ 未命中
③ 回退全局费项 未挂产品的全局费项(来源标记 LEGACY)
↓ 未命中
④ 套商户覆盖 在②③命中的基础上,套该商户的售价侧覆盖(来源标记 OVERRIDE)6.1 四步详解
第 ① 步:由卡反查产品。 扣费以卡为入口,先由卡找到它所属的产品。卡上没有产品上下文时,后续的产品费项查询无法进行。
第 ② 步:取产品费项。 按「产品 + 费项码 + 币种 + 交易发生时刻」查该产品下的费项,并且必须处于生效状态:启用中,且交易时刻落在生效窗口内(生效窗口左闭右开)。同一链有多个版本行时,取生效时刻最晚的那一版。
第 ③ 步:回退全局费项。 第 ② 步没命中(例如该产品下这个收费项目压根没配),系统会去查未挂产品的全局费项。命中则使用,并在扣费流水上把取价来源标记为 LEGACY。
这一步是「停用 ≠ 停止收费」的根源。 停用一个产品费项,只是让第 ② 步不命中,第 ③ 步会立刻顶上,只要全局费项还在启用,交易照样扣费,而且扣的还是全局那一档价格。要真正停止某项收费,必须确认第 ③ 步也不命中。
第 ④ 步:套商户覆盖。 前两步命中任意一个之后,才查这个商户对该费项的售价侧覆盖。覆盖必须同时满足「已生效」与「在生效区间内」才会套用。套用后取价来源标记为 OVERRIDE,只改售价侧,成本侧、适用区间、扣费科目仍取平台费项。
6.2 三种取价来源
| 来源标记 | 含义 | 取的是谁的价 |
|---|---|---|
PLATFORM | 命中产品费项 | 平台为该产品配置的价格 |
LEGACY | 产品费项未命中,回退到全局费项 | 平台全局配置的价格 |
OVERRIDE | 在上述基础上套用了商户覆盖 | 商户自定义的售价 |
排错时先看扣费流水上的取价来源,就知道钱是被哪一档价格扣走的。
6.3 找不到可用费项时
系统存在两条扣费入口,行为不同:
- 主扣费入口:找不到可用费项时拒绝并报错(
FEE_404),不会静默放过; - 可选扣费入口(开卡费、月管理费等):找不到可用费项时跳过不扣。
也就是说,「费项没配」在不同场景下的结果不同。周期类与账户类费项属于后者,未配置就是不扣,不会阻断业务。
6.4 币种红线
取价币种恒等于卡余额币种,系统不做任何币种折算,也不会回退到其他币种的费项。为某币种配费项时,必须用该币种建行;只配了美元而卡片余额是欧元,该笔交易取不到美元费项,也不会自动去取美元价格。
7. 费项目录与叠加互斥规则
7.1 官方目录
以下为可配置的收费项目。实际启用哪些、按什么模式、适用区间是什么,全部由运营平台按产品与币种逐条配置,本表只说明每个项目「什么时候会被触发」。
| 费项码 | 中文名 | 收费大类 | 计费模式 | 触发场景 |
|---|---|---|---|---|
FEE_AUTH | 授权交易手续费 | 交易 | RATE | 授权通过时按交易额计 |
FEE_TX_FLAT | 消费笔费 | 交易 | FIXED | 授权通过时按笔计 |
FEE_TX_SMALL | 小额交易手续费 | 交易 | FIXED_PLUS_RATE | 交易额落在配置的小额区间内时计,取代消费笔费 |
FEE_CROSS_BORDER | 跨境交易手续费 | 交易 | RATE | 清算确认为跨境时计 |
FEE_3DS | 3DS 验证费 | 交易 | FIXED | 3DS 挑战成功时计 |
FEE_AUTH_DECLINE | 授权失败手续费 | 交易 | FIXED | 授权被拒时计(默认关闭) |
FEE_SPECIAL_REGION | 特殊地区商户手续费 | 交易 | FIXED_PLUS_RATE | 商户地区命中配置清单时计 |
FEE_REFUND | 退款手续费 | 退款争议 | FIXED | 退款成功时计 |
FEE_CHARGEBACK | Chargeback 手续费 | 退款争议 | FIXED | 争议立案即计,无论胜负 |
FEE_ATM_WITHDRAW | ATM 提现手续费 | ATM | FIXED_PLUS_RATE | ATM 取现时计 |
FEE_ATM_INQUIRY | ATM 查询手续费 | ATM | FIXED | ATM 余额查询时计 |
FEE_OPEN_CARD | 开卡费 | 账户 | FIXED | 开卡成功时计 |
FEE_MONTHLY | 月管理费 | 周期 | FIXED | 每月 1 日批处理扣收 |
7.2 「配置了但不扣费」的费项码
以下费项码在目录中保留展示名,但扣费引擎未实现:配上去不会产生任何实际扣费。运营平台的新建下拉中已剔除,后端写入口也会直接拒绝,历史存量数据保留仅供查看。
| 费项码 | 中文名 | 说明 |
|---|---|---|
FEE_RECHARGE | 充值手续费 | 引擎未实现 |
FEE_WITHDRAWAL | 提现手续费 | 引擎未实现 |
FEE_SIGN_VIRTUAL | 虚拟卡开卡费 | 引擎未实现,请改用 FEE_OPEN_CARD |
FEE_SIGN_PHYSICAL | 实体卡开卡费 | 引擎未实现,请改用 FEE_OPEN_CARD |
FEE_REISSUE | 换卡费 | 引擎未实现 |
FEE_REPLACE | 挂失/补卡费 | 引擎未实现 |
FEE_FX | 跨境汇兑费 | 引擎未实现 |
FEE_SPECIAL_MCC | 特殊商户费 | 引擎未实现 |
FEE_INACTIVE | 休眠卡费 | 引擎未实现(2026-09-30 起并入本名单,见下方提示) |
警告警告:给上表中的费项码配了价,系统不会报错,但也不会产生任何实际扣费——钱不会被扣,但业务上以为扣了。
FEE_INACTIVE(休眠卡费)特别说明:它此前一直混在上节的可配目录里,是本名单中唯一一个「需求文档明确写着商户可开启、默认关闭只差运营点一下」的码——运营会把它当正常业务项配上去,配完不扣费即静默少收。2026-09-30 起已并入本名单,新建下拉与后端写入口一并拒绝。 另有历史兼容码FEE_SIGN(开卡费旧名),同样不参与扣费,新配置统一使用FEE_OPEN_CARD。
7.3 叠加与互斥
多费项命中时的规则:
| 组合 | 关系 | 说明 |
|---|---|---|
FEE_AUTH + FEE_TX_FLAT | 叠加 | 两者同时计入,同一笔交易按各自规则各扣一次 |
FEE_AUTH + FEE_TX_SMALL | 叠加 | 授权手续费独立计入,小额手续费另计 |
FEE_TX_SMALL + FEE_TX_FLAT | 互斥 | 交易额命中小额区间时只计小额手续费,取代消费笔费;未命中才计消费笔费 |
警告警告:小额手续费不设区间 = 消费笔费被全线取代。 小额区间的判定是左闭右开:
min ≤ 交易额 < max。上下限都留空表示任意金额都命中,会变成「所有交易都取代消费笔费」——这是一个高危配置,务必显式设置上下限。
系统不会在配置期拒绝「同时配了小额和消费笔费」,因为这本身是合法配置(区间不重叠时各按各的)。真正的互斥是在取价时按金额区间动态判定的。
8. 扣费时机与扣费科目
8.1 扣费时机
| 费项 | 触发时点 | 触发场景标识 |
|---|---|---|
FEE_AUTH / FEE_TX_FLAT / FEE_TX_SMALL | 授权通过后、扣本金之前 | 授权通过 |
FEE_AUTH_DECLINE | 授权被拒时(余额不足、限额等) | 授权拒绝 |
FEE_3DS | 3DS 挑战成功时 | 3DS 验证 |
FEE_REFUND / FEE_ATM_WITHDRAW / FEE_ATM_INQUIRY | 交易报文到达后按交易类型分类扣费 | 退款 / ATM 取现 / ATM 查询 |
FEE_CROSS_BORDER / FEE_SPECIAL_REGION | 消费清算成功后 | 清算 |
FEE_CHARGEBACK | 争议立案时,无论最终胜负 | 争议立案 |
FEE_OPEN_CARD | 开卡成功、卡已落库之后(开卡费失败不回滚已出卡) | 开卡 |
FEE_MONTHLY | 定时批处理,每月 1 日 03:00 逐卡扣收当月月管理费 | 月度批处理 |
关于月管理费批处理的三点说明:
- 批处理有总开关,开关缺失时按关闭处理(fail-close),不会在无人确认的情况下自动扣钱;
- 批处理带分布式锁,多实例部署不会重复执行;
- 逐卡独立事务,单卡失败只影响该卡,不会中断整批。
8.2 扣费科目
| 科目 | 扣费对象 | 典型费项 |
|---|---|---|
| 卡余额 | 持卡人卡上的可用余额,与消费同一层 | 交易类、退款争议类、ATM 类 |
| 账户可用 | 商户/持卡人账户的可用余额 | 账户类(充值、提现) |
| 商户通道头寸 | 商户在通道侧的头寸 | 开卡费等由商户后台提交的场景 |
开卡费的扣费科目按提交方路由:由商户后台提交的开卡,从商户通道头寸扣;由平台侧发起的开卡,从卡余额/账户可用扣。配置开卡费前请确认走的是哪条路径。
8.3 幂等与回滚
- 所有扣费都有幂等键,同一笔业务的重放不会重复扣费,只会返回既有流水;
- 同一笔交易内的多项扣费在同一个事务内执行,任一项失败则整体回滚(该笔授权相应转为拒绝);
- 已产生的扣费流水不受后续费率变更影响。改费率只改未来,不改历史——这是账务可追溯的基本要求。
9. 金额计算模型
9.1 计费模式三态
| 模式 | 计算式 |
|---|---|
FIXED | 固定额 |
RATE | 交易额 × 费率 ÷ 10000 |
FIXED_PLUS_RATE | 固定额 + 交易额 × 费率 ÷ 10000 |
费率的单位是万分比,不是百分比。 "250" 表示 2.5%,不是 250%,也不是 2.5。这是配置时最高频的错误来源。
9.2 精度与舍入
- 所有金额与费率的运算使用高精度十进制,中间过程不做截断;
- 最终结果保留 8 位小数,四舍五入;
- 金额一律以字符串在接口之间传输(
"2.50"),禁止使用数字类型,避免浮点误差在链路上被放大。
9.3 示意算例
以下数字仅为计算过程示意,不代表任何真实费率配置。
设某笔交易额为 "100.00",某产品费项为「固定额 + 费率」模式,固定额配 "1.00"、费率配 "250"(万分比,即 2.5%):
费率部分 = 100.00 × 250 ÷ 10000 = 2.50000000
固定部分 = 1.00
本项扣费 = 1.00 + 2.50 = 3.50若同一笔交易还命中了授权手续费(纯费率模式,费率配 "50",即 0.5%):
授权手续费 = 100.00 × 50 ÷ 10000 = 0.50000000
两项叠加,本笔合计 = 3.50 + 0.50 = 4.00如果商户对授权手续费做了售价侧覆盖,则用覆盖后的费率代入同一公式,其余(固定额、科目、适用区间)仍取平台配置。
9.4 适用区间的判定
区间判定发生在取价阶段,用于决定某个费项本次是否命中:
命中条件:minAmount ≤ 交易额 < maxAmount
其中 minAmount 留空视为不设下限,maxAmount 留空视为不设上限10. 错误码速查
10.1 费率链(价差链)
| 错误码 | 含义 | 常见触发 |
|---|---|---|
3101 | 费率低于下层成本价 | 下层费率配得比上游成本低 |
3102 | 费率超过平台上限 | 下层费率配得过高 |
3103 | 费率变更冷却中 | 冷却期内再次改价 |
3104 | 商户不属于该代理或状态不可配置 | 归属不符,或商户状态非正常 |
3105 | 产品未授权给该商户/代理 | 未做产品授权就配费率 |
10.2 费项链(实扣链)
| 错误码 | 含义 | 常见触发 |
|---|---|---|
FEE_404 | 费项不存在或未启用 | 按费项 ID 操作了不存在的行 |
FEE_404 | 商户费率覆盖不存在 | 撤销一个不存在的覆盖 |
FEE_409 | 同费项已存在生效行 | 重复创建同一「产品 + 费项码 + 币种」的生效行 |
FEE_423 | 费项变更冷却中,请稍后再试 | 冷却期内新建/编辑/停用费项 |
FEE_400 | 售价不得低于成本价 | 该校验在商户覆盖写路径已放开,此码主要出现在平台侧 |
4003 | 费项存在商户覆盖,禁止停用 | 商户覆盖生效期间停用平台费项 |
1001 | 新配置费项必须挂接产品 | 新建费项时未选产品 |
1009 | 幂等键冲突 | 同一幂等键带了不同请求体 |
10.3 敏感写通用
| 错误码 | 含义 |
|---|---|
3410 / 3412 / 3415 | 2FA 验证码校验失败 / 未启用 MFA / MFA 服务不可用 |
3411 | 2FA 验证码限速中,请稍后再试 |
OPTIMISTIC_LOCK | 版本已变化(有人先改过),请刷新后重试 |
11. 排错速查
11.1 停用产品费项 ≠ 停止收费(资损警示)
这是本系统最容易造成资损的一个认知误区。
警告危险:这是本系统最容易造成资损的认知误区。 停用一个产品费项,只是让取价第 ② 步不命中;取价第 ③ 步会立刻回退到未挂产品的全局费项继续扣费,扣费流水上的取价来源会显示为
LEGACY。
要真正停止某项收费,必须做到:
- 停用该产品下的费项;
- 确认同名费项的全局版本也已停用(否则会继续按全局那一档扣);
- 核对商户是否已有覆盖(覆盖优先级最高,需商户侧撤销);
- 用一笔小额真实交易验证扣费流水上不再出现该项。
11.2 商户改了费率,平台侧看不到变化
商户覆盖的优先级高于平台费项。平台看到的仍是平台自己配的价,实际扣的是商户覆盖价。核对商户后台的覆盖记录与生效区间。
11.3 商户配的费率被拒
按错误码定位:3101 是配低了(低于上游成本),3102 是配高了(超过平台上限),3105 是这个产品还没做授权,先做授权。
11.4 某笔交易没有扣某项费
按这个顺序查:
- 该笔交易的金额是否落在费项的适用区间(小额手续费这类尤其容易漏);
- 费项的地区清单 / 商户类别清单是否为空——为空是「全命中」而非「不生效」,这一条如果为空反而会全量命中;
- 费项是否处于生效窗口内(版本链有生效起止),或已被停用;
- 币种是否与卡余额币种一致(不做折算,见 §6.4);
- 该收费项目是否本就在「引擎未实现」清单里(§7.2),配了也不扣;
- 商户是否已经撤销了覆盖。
11.5 扣费金额算出来不对
多半是费率单位搞错。费率是万分比:"250" = 2.5%,不是 250%,也不是 2.5。另一个常见原因是把 RATE 模式配成了固定额语义,或反过来。
11.6 提交变更被拒,提示冷却中
等冷却结束,或在确有紧急理由时使用紧急变更(绕过冷却)——必须填变更原因,经 2FA 验证,绕过标记落只读审计。详见 §5.3。
提示文案形如:
费项链 [30/FEE_TX_FLAT/EUR] 编辑冷却中,剩余 6 小时 12 分钟,冷却时长 24 小时方括号里是费项链标识 [产品ID/费项码/币种],冷却挂在链上、链与链互不影响——同一个费项码在不同产品或不同币种下是彼此独立的多条链,只看费项码会误判成「整条目录都在冷却」。请按括号里的产品与币种确认你等的确实是自己刚才改的那一条。
11.7 提示版本已变化
有其他人(或另一个会话)先改过这条配置。刷新页面拿到最新版本号再提交,不要盲目重试覆盖。
12. 变更记录
| 日期 | 变更内容 | 影响范围 |
|---|---|---|
| 2026-09-30 | 实扣链费项补齐变更冷却期:新建/编辑/停用后进入冷却,默认 24 小时、时长可配置;平台提供需填变更原因的紧急绕过开关;新增错误码 FEE_423 | 运营平台费项配置、费项停用 |
| 2026-09-30 | 费项改为版本链语义:编辑不再原地覆盖,而是追加新版本行并闭窗旧行;回滚 = 以旧值追加新版本 | 运营平台费项配置 |
| 2026-09-20 | 商户覆盖成本侧的防倒挂校验放开,商户售价可自定义;平台侧改为试算告警 | 商户费项售价覆盖 |
| 2026-09-05 | 平台费项目录补齐预置种子,八个引擎未实现的费项码停用并从新建目录剔除 | 平台费项目录 |
文档定位:本文是规则说明,不替代接口契约文档。字段级契约以接口文档与数据库 schema 为准;如出现冲突,以 docs/DOC-SSOT.md 的裁决为准。