Monnify 虚拟账号按 bizCode 归属管理 — 迭代需求
Monnify 已明确不支持同一客户在同一商户号下创建多个 Reserved Account。本需求最终采用:同一客户只创建一个 Reserved Account,通过多个银行账号按客户维度分配给不同
bizCode。
1. 业务模型
Monnify 商户号 + 客户 = 一个 Reserved Account
一个 Reserved Account -> 多个合作银行账号
一个客户的每个银行账号 -> 一个 bizCode例如:
商户 M + 客户 A
-> accountNumber 1 -> bizCode_A
-> accountNumber 2 -> bizCode_B
-> accountNumber 3 -> 未分配/备用同一客户不同业务线必须使用不同的实际银行账号。账号 A 的收款只能进入 bizCode_A,账号 B 的收款只能进入 bizCode_B。
2. Monnify 接口
| 用途 | Production 地址 |
|---|---|
| 获取 Token | POST https://api.monnify.com/api/v1/auth/login |
| 创建 Reserved Account | POST https://api.monnify.com/api/v2/bank-transfer/reserved-accounts |
| 查询 Reserved Account | GET https://api.monnify.com/api/v2/bank-transfer/reserved-accounts/{accountReference} |
| 增加关联银行账号 | PUT https://api.monnify.com/api/v1/bank-transfer/reserved-accounts/add-linked-accounts/{accountReference} |
| 查询 Reserved Account 交易 | GET https://api.monnify.com/api/v1/bank-transfer/reserved-accounts/transactions |
Sandbox 将域名替换为 https://sandbox.monnify.com。官方参考:Monnify API、Reserved Account。
3. 首次创建客户 Reserved Account
客户首次进入任意业务线时,只调用一次创建接口:
POST https://api.monnify.com/api/v2/bank-transfer/reserved-accounts
Authorization: Bearer {accessToken}
Content-Type: application/json{
"accountReference": "CUST_10001_RESERVED_001",
"accountName": "Customer 10001",
"currencyCode": "NGN",
"contractCode": "{MONNIFY_CONTRACT_CODE}",
"customerEmail": "{CUSTOMER_EMAIL}",
"customerName": "{CUSTOMER_NAME}",
"bvn": "{CUSTOMER_BVN}",
"nin": "{CUSTOMER_NIN}",
"getAllAvailableBanks": true
}getAllAvailableBanks=true 的含义是:在同一个 Reserved Account 下申请所有可用合作银行账号,不是创建多个独立 Reserved Account,也不是直接生成多个 bizCode 账号。
返回结果可能类似:
accountReference = CUST_10001_RESERVED_001
reservationReference = RESERVATION_001
-> bankCode 50515 / accountNumber 账号 1
-> bankCode 044 / accountNumber 账号 2
-> bankCode 035 / accountNumber 账号 3这几个银行账号共享同一个 accountReference / reservationReference,但我方可以将不同的实际 accountNumber 分配给不同 bizCode。
4. bizCode 与银行账号的映射规则
不能维护全局的“银行 code -> bizCode”映射,必须按客户保存实际账号映射:
| 客户 | 商户号 | accountReference | bankCode | accountNumber | bizCode | 状态 |
|---|---|---|---|---|---|---|
| 客户 A | 商户 M | CUST_10001_RESERVED_001 | 50515 | 账号 1 | bizCode_A | 已分配 |
| 客户 A | 商户 M | CUST_10001_RESERVED_001 | 044 | 账号 2 | bizCode_B | 已分配 |
| 客户 A | 商户 M | CUST_10001_RESERVED_001 | 035 | 账号 3 | — | 未分配 |
具体规则:
- 账号池以实际
accountNumber为单位。 - 一个客户的一个
accountNumber只能分配给一个bizCode。 - 一个客户的同一个
bizCode只能有一个当前有效accountNumber。 - 每个客户单独建立映射,不能假设所有客户的同一银行 code 都对应同一业务线。
- 收款时必须根据实际转入的
accountNumber找到客户和bizCode;仅凭accountReference无法区分同一 Reserved Account 下的多个业务线。 - 如果到账通知不包含实际转入的
accountNumber,必须让 Monnify 确认通知字段,否则无法可靠完成业务线匹配。
4.1 银行偏好与分配顺序
preferredBanks 只用于补充或选择合作银行,不直接决定业务归属。可为不同 bizCode 设置银行偏好顺序:
| bizCode | 首选银行 | 备选银行 | 分配规则 |
|---|---|---|---|
bizCode_A | 50515 | 044 | 优先选择客户账号池中 50515 的未分配账号 |
bizCode_B | 044 | 035 | 优先选择 044,已占用时选择 035 |
新 bizCode_C | 035 | 50515 | 优先选择 035 的未分配账号 |
这是我方分配规则,Monnify 不会校验银行账号与 bizCode 的关系。如果同一客户的首选银行已被其他业务线占用,则按备选银行分配;没有可用账号时进入账号扩展流程。
5. 新 bizCode 如何分配账号
客户 A 已有:
账号 1 -> bizCode_A
账号 2 -> bizCode_B
账号 3 -> 未分配客户 A 后续申请新 bizCode_C:
- 查询客户 A 的现有 Reserved Account 账号池。
- 查询客户 A 在
bizCode_C下是否已有账号。 - 已有则直接复用,不重新创建。
- 没有则按
bizCode_C的银行偏好,从未分配账号池选择账号 3。 - 将账号 3 分配给
bizCode_C,并只在业务线 C 页面展示。
如果账号池没有可用账号,不得再次调用创建 Reserved Account 申请第二个客户账号。应调用:
PUT https://api.monnify.com/api/v1/bank-transfer/reserved-accounts/add-linked-accounts/{accountReference}例如新增 035 银行账号:
{
"getAllAvailableBanks": false,
"preferredBanks": ["035"]
}该接口是在原 Reserved Account 下增加关联银行账号,不会创建新的 accountReference 或第二个 Reserved Account。新账号返回并确认可用后,再分配给新 bizCode。Add Linked Accounts
如果 Monnify 没有可增加的合作银行账号,则该客户无法在当前商户 Reserved Account 下继续新增独立业务线账号,应使用其他收款方式或由 Provider 提供扩展能力。
6. 账号失效与重新分配
6.1 单个银行账号失效
只影响该客户当前使用该账号的 bizCode:
账号 1(bizCode_A)失效
-> 停止展示账号 1
-> 从客户 A 未分配账号池选择账号 3
-> 将账号 3 分配给 bizCode_A
-> 账号 1 保留历史交易如果没有未分配账号,先通过 Add Linked Accounts 增加账号,再完成替换。历史订单保留原账号和原 bizCode,其他业务线账号不变。
6.2 整个 Reserved Account 失效
由于 Monnify 不支持同一客户创建第二个 Reserved Account,不能通过 POST 再创建一个新的客户账号。必须:
- 联系 Monnify 恢复或迁移原 Reserved Account;或
- 启用其他收款方式;或
- 由 Provider 提供正式的账号迁移方案。
不能把另一个客户的账号或其他业务线账号临时分配过来。
7. 业务流程图
flowchart TD A[客户进入 bizCode] --> B{客户是否已有 Reserved Account} B -- 否 --> C[POST 创建一个 Reserved Account] C --> D[getAllAvailableBanks=true] D --> E[得到多个银行账号并建立账号池] B -- 是 --> E E --> F{该 bizCode 是否已有账号} F -- 是 --> G[复用当前账号] F -- 否 --> H{是否有未分配银行账号} H -- 是 --> I[按 bizCode 银行偏好分配账号] H -- 否 --> J[PUT 增加关联银行账号] J --> I I --> K[展示该 bizCode 账号] G --> K K --> L[客户转账] L --> M[按实际 accountNumber 匹配客户和 bizCode] M --> N{订单和金额校验} N -- 通过 --> O[进入对应业务线入账] N -- 不通过 --> P[人工确认] Q[单个银行账号失效] --> R[从未分配账号池替换] R --> K S[新增 bizCode] --> A
8. 匹配与异常规则
- 客户页面只展示当前客户、当前
bizCode的有效账号。 accountReference只能定位客户的 Reserved Account,不能单独定位bizCode。- 业务线匹配唯一依赖实际转入的
accountNumber与我方客户账号映射。 - 客户姓名、邮箱、BVN/NIN、金额和备注不能单独用于业务线匹配。
- 未知账号、账号失效后到账、账号未分配
bizCode或金额异常时,不自动转入其他业务线。 - 同一客户不同业务线资金不得自动合并、跨业务线抵扣或转移。
9. 运营与验收
运营应能查看客户、商户号、accountReference、reservationReference、银行、实际账号、当前 bizCode、账号状态和分配时间。
验收标准:
- 同一客户只创建一个 Reserved Account,首次创建可以返回多个银行账号。
- 客户 A 的不同实际银行账号可以分别分配给
bizCode_A和bizCode_B。 - 客户 A 进入新
bizCode时,优先从未分配账号池分配,不重复创建 Reserved Account。 - 账号池不足时,可以通过 Add Linked Accounts 增加银行账号后再分配。
- 收款可以根据实际
accountNumber正确匹配到客户和bizCode。 - 单个银行账号失效时,只影响对应
bizCode,可以使用未分配账号替换。 - 整个 Reserved Account 失效时,不通过 POST 创建第二个账号,进入 Provider 恢复/迁移或替代收款流程。
- 不同
bizCode账号不能互相展示、互相替代或自动合并。
10. 上线前确认项
- Monnify 到账通知是否稳定返回实际转入的
accountNumber,而不是只返回accountReference。 - 每个客户最多可关联多少合作银行账号,是否需要 Provider 额外开通。
- 新增关联银行账号时,Provider 可用银行及失败规则。
bizCode的银行偏好顺序由谁维护,银行不可用时是否允许使用备选银行。- Sandbox 使用 Payment Simulator 验证多银行账号到账和账号匹配;官方文档说明 Sandbox 不支持真实交易。Sandbox 说明