Monnify 绑卡、放款、还款对接需求文档
版本:v0.3
日期:2026-06-25
范围:基于 Monnify API Reference、Direct Debit、Reserved Account、Disbursement、Webhook 文档整理。
约定:Monnify 等三方支付交互由pmt负责;短信等非支付三方能力仍按项目现状由对应服务承接。
1. 结论
本次贷款 MVP 采用 Card Tokenization 绑卡还款方案。业务上的“绑卡”定义为:客户通过 Monnify 完成一次卡支付验证,pmt 在支付成功后保存 Monnify 返回的 cardToken,后续按还款计划使用该 token 发起扣款。
- 绑卡主链路:Card Tokenization,首次卡支付成功后获取
cardToken。 - 还款主链路:
Charge Card Token,到期由pmt使用 token 发起扣款。 - 还款兜底链路:Reserved / Virtual Account,客户主动转账还款。
- 后置可选能力:Direct Debit / Mandate,后续如需银行账户直接扣款再接入。
放款使用 Disbursement Single Transfer。卡 token 扣款可能受卡过期、余额不足、发卡行风控、OTP/3DS 策略影响,因此必须保留主动还款入口和失败重试/提醒机制。
2. 基础接入
2.1 环境和认证
| 项目 | Sandbox | Production |
|---|---|---|
| Base URL | https://sandbox.monnify.com | https://api.monnify.com |
| 认证接口 | POST /api/v1/auth/login | 同左 |
| 认证方式 | Basic base64(apiKey:secretKey) 换 Bearer Token | 同左 |
| 后续接口 | Header: Authorization: Bearer <token> | 同左 |
测试凭据见 Monnify API Reference 的 Public Test Credentials:
| 字段 | 值 |
|---|---|
| API Key | MK_TEST_GC3B8XG2XX |
| Secret Key | A663NRZA544DDPEM7KDN7Z8HRV6YXD8S |
| Contract Code | 5867418298 |
生产上线需要替换为 live API Key、Secret Key、Contract Code,并将 Base URL 切到生产域名。
2.2 通用接口清单
| 能力 | Method + Path | 用途 |
|---|---|---|
| 获取银行列表 | GET /api/v1/banks | 获取 Monnify 银行编码,供绑卡/绑账户、放款使用 |
| 校验银行账户 | GET /api/v1/disbursements/account/validate?accountNumber=&bankCode= | 校验账号户名,放款前和创建 mandate 前使用 |
| 获取交易状态 | GET /api/v2/merchant/transactions/query?transactionReference=&paymentReference= | 查询收款/卡支付交易状态 |
| 查询所有交易 | GET /api/v1/transactions/search | 按时间、金额、客户、状态分页对账 |
3. 绑卡/Card Tokenization
3.1 业务含义
客户在 App 中选择绑定还款银行卡,系统拉起 Monnify 卡支付能力,客户输入卡信息并完成银行侧验证。首次支付成功后,pmt 查询交易详情并保存 cardDetails.cardToken。后续还款日,pmt 使用该 token 进行自动扣款。
首次支付可以采用两种产品策略:
| 策略 | 用户感知 | 适用场景 |
|---|---|---|
| 小额验证支付 | 扣一笔低金额用于验证银行卡 | 只做绑卡,不在绑卡时还款 |
| 首期/当期还款支付 | 支付本期还款并保存银行卡 | 还款场景更自然,建议优先 |
MVP 建议采用“首期/当期还款支付并保存银行卡”。如果产品要求在放款前完成绑卡,则可采用小额验证支付。
小额验证支付需要按真实支付处理。Monnify Card Tokenization 文档说明 token 来自客户完成的首次成功卡支付,未说明该笔金额会自动退回。因此不能假设 Monnify 自动退款;如产品承诺退还小额验证金,需要通过退款能力或内部账务补偿另行处理,并确认 Refund API 已开通、费用、到账时效和失败处理策略。
https://developers.monnify.com/docs/collections/recurring-payments/card-tokenization
关键接口
| 步骤 | Method + Path | 说明 |
|---|---|---|
| 初始化交易 | POST /api/v1/merchant/transactions/init-transaction | 创建绑卡验证/首期还款交易,得到 transactionReference |
| 卡支付 | POST /api/v1/merchant/cards/charge | 提交卡信息发起首次扣款 |
| OTP 授权 | POST /api/v1/merchant/cards/otp/authorize | Charge a Card 返回 OTP_AUTHORIZATION_REQUIRED 时使用 |
| 3DS 授权 | POST /api/v1/sdk/cards/secure-3d/authorize | Charge a Card 返回 BANK_AUTHORIZATION_REQUIRED 时使用 |
| 查询交易 | GET /api/v2/merchant/transactions/query | 支付成功后读取 cardDetails.cardToken |
| Token 扣款 | POST /api/v1/merchant/cards/charge-card-token | 后续自动还款使用 |
3.2 用户操作交互
- 用户在 App 选择“绑定还款银行卡”。
- App 展示授权说明:绑定后将在还款日按贷款合同约定自动扣款,可更换或解绑银行卡。
- 用户点击确认,App 拉起 Monnify 卡支付页面或 SDK。
- 用户在 Monnify Checkout/SDK 或我方自建安全卡输入页中输入卡号、有效期、CVV、PIN 等卡信息。
pmt调用Charge a Card。- 如果返回
SUCCESS,前端展示绑定处理中,后端查询交易并保存 token。 - 如果返回
OTP_AUTHORIZATION_REQUIRED,App 展示 OTP 输入框,用户输入 OTP 后pmt调用 OTP 授权接口。 - 如果返回
BANK_AUTHORIZATION_REQUIRED,App 跳转或打开 3DS 验证页,用户完成银行验证后回到 App。 pmt查询交易状态,确认支付成功且返回可复用 token。- App 展示绑定成功,显示卡品牌和后四位。
推荐前端文案:
绑定后,我们将在还款日按贷款合同约定从该银行卡自动扣款。
你可以在还款设置中更换或解绑银行卡。3.3 卡信息采集页面要求
卡信息采集有两种实现方式:
| 方案 | 说明 | MVP 建议 |
|---|---|---|
| Monnify Checkout/SDK | 用户在 Monnify 提供的页面或组件中输入卡号、有效期、CVV、PIN,pmt 不直接接触完整卡数据 | 推荐 |
我方自建页面 + Charge a Card API | 用户在我方页面输入卡信息,pmt 服务端调用 Monnify Charge a Card | 仅在具备 PCI-DSS、安全审计和密钥管理能力后采用 |
如果采用我方自建页面,必须满足以下要求:
- 页面和接口全链路 HTTPS。
- 卡号、CVV、PIN 不落库、不写日志、不进入埋点和错误上报。
- 后端只在本次请求内转发给 Monnify,不做持久化。
- 前端禁止把卡信息传给除
pmt支付接口以外的服务。 - 日志、APM、网关、风控、客服后台必须脱敏。
- 需要确认公司具备处理银行卡敏感信息所需的 PCI-DSS 合规能力。
因此,MVP 优先使用 Monnify Checkout/SDK 承接卡信息输入;只有在产品或技术上必须自建页面时,才走 Charge a Card API 直连模式。
3.4 OTP / 3DS 分流规则
OTP 还是 3DS 由 POST /api/v1/merchant/cards/charge 的响应决定,pmt 不预先判断。
Charge a Card 响应状态
| Monnify 状态 | 我方状态 | 处理 |
|---|---|---|
SUCCESS | BIND_PAID | 查询交易,读取并保存 cardToken |
OTP_AUTHORIZATION_REQUIRED | WAITING_OTP | 展示 OTP 输入框,调用 OTP 授权 |
BANK_AUTHORIZATION_REQUIRED | WAITING_3DS | 跳转 3DS 验证,完成后查询交易 |
| 失败状态 | BIND_FAILED | 提示换卡或重试 |
OTP 授权字段映射:
| 字段 | 取值 |
|---|---|
transactionReference | Charge a Card 返回的 responseBody.transactionReference |
tokenId | Charge a Card 返回的 responseBody.otpData.id |
token | 用户输入的 OTP |
collectionChannel | API_NOTIFICATION |
3DS 授权处理:
| 字段 | 取值 |
|---|---|
transactionReference | Charge a Card 返回的 responseBody.transactionReference |
redirectUrl | 使用 responseBody.secure3dData.redirectUrl 引导用户验证 |
| 验证后动作 | 回到 App 后调用交易查询接口确认最终支付状态 |
OTP 时效要求:
- Monnify API 文档未给出固定 OTP 有效时长,实际有效期通常由发卡行/银行侧控制。
- App 收到
OTP_AUTHORIZATION_REQUIRED后应立即展示 OTP 输入框,不要让用户离开当前流程。 - 前端建议展示 3 分钟倒计时;倒计时只是产品提示,不代表 Monnify 官方有效期。
- 用户提交 OTP 后立即调用
POST /api/v1/merchant/cards/otp/authorize。 - 如果 OTP 过期或授权失败,卡支付接口没有文档化的 card OTP resend 接口;MVP 按失败处理,提示用户重新发起绑卡/支付。
- 同一笔
transactionReference不应反复无限尝试 OTP,建议限制 3 次以内,超过后重新创建交易。
3.5 Token 保存条件
只有同时满足以下条件,才能把支付方式置为 BOUND:
- 交易状态为成功,例如
paymentStatus = PAID或授权接口返回SUCCESSFUL。 - 交易详情返回
cardDetails.cardToken。 cardDetails.reusable = true。cardDetails.supportsTokenization = true。customerEmail与后续 token 扣款使用的客户邮箱一致。
pmt 只保存 Monnify token、卡品牌、后四位、有效期、客户邮箱,不保存 PAN、CVV、OTP、PIN。
3.6 绑卡时序
sequenceDiagram participant App as 客户 App participant FCS as 贷款/FCS participant PMT as pmt participant Monnify as Monnify App->>FCS: 点击绑定还款银行卡 FCS->>PMT: 创建绑卡验证/首期还款交易 PMT->>Monnify: POST /api/v1/merchant/transactions/init-transaction Monnify-->>PMT: 返回 transactionReference App->>Monnify: 输入卡信息 PMT->>Monnify: POST /api/v1/merchant/cards/charge Monnify-->>PMT: 返回 SUCCESS / OTP_REQUIRED / 3DS_REQUIRED alt 需要 OTP App->>FCS: 输入 OTP FCS->>PMT: 提交 OTP PMT->>Monnify: POST /api/v1/merchant/cards/otp/authorize Monnify-->>PMT: 返回支付结果 else 需要 3DS App->>Monnify: 打开 redirectUrl 完成 3DS Monnify-->>App: 返回 App/H5 end PMT->>Monnify: GET /api/v2/merchant/transactions/query Monnify-->>PMT: 返回 cardToken、maskedPan、reusable PMT-->>FCS: 更新支付方式为 BOUND FCS-->>App: 展示绑卡成功
4. 放款
https://developers.monnify.com/docs/disbursements/single-transfers
4.1 接口链路
| 步骤 | Method + Path | 说明 |
|---|---|---|
| 获取钱包余额 | GET /api/v2/disbursements/wallet-balance | 放款前确认 Monnify 钱包余额 |
| 获取/缓存银行列表 | GET /api/v1/banks | 获取目标银行编码 |
| 校验收款账户 | GET /api/v1/disbursements/account/validate | 校验借款人放款账户 |
| 发起单笔放款 | POST /api/v2/disbursements/single | 贷款放款主接口 |
| OTP 授权 | POST /api/v2/disbursements/single/validate-otp | 若返回 PENDING_AUTHORIZATION 且 2FA 开启 |
| 重发 OTP | POST /api/v2/disbursements/single/resend-otp | OTP 过期时使用 |
| 查询放款状态 | GET /api/v2/disbursements/single/summary?reference= | 主动查询 |
| 列表/搜索 | GET /api/v2/disbursements/single/transactions / GET /api/v2/disbursements/search-transactions | 对账和运营查询 |
生产使用 Transfer API 需要满足 Monnify 监管要求并开通权限。上线前还需要联系 Monnify 配置服务器静态 IP 白名单;如需关闭 API disbursement OTP,也需要向 Monnify 申请。
4.2 发起单笔放款请求字段
| 字段 | 必填 | 说明 |
|---|---|---|
amount | 是 | 放款金额 |
reference | 是 | 我方唯一放款引用,建议等于或包含 loanDisbursementId |
narration | 是 | 银行流水备注 |
destinationBankCode | 是 | 借款人收款银行编码 |
destinationAccountNumber | 是 | 借款人收款账号 |
destinationAccountName | 是 | 借款人收款户名,应来自账户校验结果 |
currency | 是 | NGN |
sourceAccountNumber | 是 | Monnify 钱包账号 |
senderInfo | 否 | 代表付款方信息 |
async | 否 | 是否异步转账 |
4.3 放款状态映射
| Monnify 状态 | 我方状态 | 处理 |
|---|---|---|
PENDING_AUTHORIZATION | WAITING_OTP | 等待运营/财务输入 OTP 或走免 OTP 配置 |
PENDING / PROCESSING | DISBURSING | 继续查询或等待回调 |
SUCCESS | DISBURSED | 更新贷款为已放款,生成还款计划 |
FAILED | DISBURSE_FAILED | 可重试,必须使用新 reference 或按幂等策略处理 |
REVERSED | DISBURSE_REVERSED | 回滚贷款状态,进入人工处理 |
4.4 时序
sequenceDiagram participant Ops as 运营/系统任务 participant FCS as 贷款/FCS participant PMT as pmt participant Monnify as Monnify FCS->>PMT: 请求放款 loanId、amount、客户收款账户 PMT->>Monnify: GET /api/v2/disbursements/wallet-balance Monnify-->>PMT: 返回余额 PMT->>Monnify: GET /api/v1/disbursements/account/validate Monnify-->>PMT: 返回户名 PMT->>Monnify: POST /api/v2/disbursements/single Monnify-->>PMT: 返回 SUCCESS 或 PENDING_AUTHORIZATION alt 需要 OTP Ops->>PMT: 输入 OTP PMT->>Monnify: POST /api/v2/disbursements/single/validate-otp Monnify-->>PMT: 返回授权结果 end PMT->>Monnify: GET /api/v2/disbursements/single/summary?reference= Monnify-->>PMT: 返回最终状态 PMT-->>FCS: 通知放款成功/失败
5. 还款
5.1 主链路:Card Token 自动扣款
业务含义:账务系统到期生成应扣金额,pmt 使用已绑定银行卡的 cardToken 发起扣款,扣款成功后 FCS 入账并更新还款计划。
关键接口
| 步骤 | Method + Path | 说明 |
|---|---|---|
| 发起 token 扣款 | POST /api/v1/merchant/cards/charge-card-token | 使用 cardToken 从客户银行卡扣款 |
| 查询交易状态 | GET /api/v2/merchant/transactions/query | 按 paymentReference 查询扣款结果 |
| 分页查询交易 | GET /api/v1/transactions/search | 日终对账 |
发起扣款请求字段
| 字段 | 必填 | 说明 |
|---|---|---|
cardToken | 是 | 绑卡成功后保存的 Monnify token |
amount | 是 | 本次扣款金额,单位 NGN |
customerName | 否 | 客户姓名 |
customerEmail | 是 | 客户邮箱,必须与首次卡交易对应客户一致 |
paymentReference | 是 | 我方唯一扣款引用,建议:RP-{repaymentPlanId}-{installmentNo}-{attemptNo} |
paymentDescription | 否 | 扣款说明,例如 Loan repayment |
currencyCode | 否 | NGN |
contractCode | 是 | Monnify 合同号 |
apiKey | 是 | Monnify API Key |
metaData | 否 | 可放 loanId、repaymentPlanId,不要放敏感信息 |
incomeSplitConfig | 否 | 分账配置,MVP 不使用 |
还款状态映射
| Monnify 状态 | 我方状态 | 处理 |
|---|---|---|
PENDING / PROCESSING | REPAY_PROCESSING | 等待回调或轮询 |
SUCCESS / PAID / SUCCESSFUL | REPAID | 入账,更新本金/利息/罚息/费用 |
FAILED | REPAY_FAILED | 记录失败原因,进入重试或提醒 |
REVERSED | REPAY_REVERSED | 冲正已入账金额,进入人工处理 |
时序
sequenceDiagram participant Job as 还款任务 participant FCS as 贷款/FCS participant PMT as pmt participant Monnify as Monnify Job->>FCS: 到期生成应扣款项 FCS->>PMT: 请求扣款 repaymentId、amount、paymentMethodId PMT->>PMT: 校验 cardToken 可用、生成 paymentReference PMT->>Monnify: POST /api/v1/merchant/cards/charge-card-token Monnify-->>PMT: 返回 transactionReference、paymentReference、扣款状态 PMT->>Monnify: GET /api/v2/merchant/transactions/query?paymentReference= Monnify-->>PMT: 返回最终交易状态 PMT-->>FCS: 通知还款成功/失败 FCS->>FCS: 入账、更新还款计划、触发下一步提醒
5.2 兜底链路:Reserved / Virtual Account 主动还款
业务含义:为每个客户分配虚拟账户,客户主动转账还款。Monnify 通过交易回调通知入账;系统也可按 accountReference 查询交易。
关键接口
| 步骤 | Method + Path | 说明 |
|---|---|---|
| 创建虚拟账户 | POST /api/v2/bank-transfer/reserved-accounts | 为客户/贷款创建还款账户 |
| 查询虚拟账户 | GET /api/v2/bank-transfer/reserved-accounts/{accountReference} | 展示账户信息 |
| 查询账户交易 | GET /api/v1/bank-transfer/reserved-accounts/transactions?accountReference= | 对账和补偿 |
| 修改支付来源限制 | PUT /api/v1/bank-transfer/reserved-accounts/update-payment-source-filter/{accountReference} | 可限制付款来源 |
| 注销虚拟账户 | DELETE /api/v1/bank-transfer/reserved-accounts/reference/{accountReference} | 贷款结清后释放 |
创建虚拟账户请求字段
| 字段 | 必填 | 说明 |
|---|---|---|
accountReference | 是 | 我方唯一账户引用,建议:RA-{userId} 或 RA-{loanId} |
accountName | 是 | 银行转账展示户名 |
currencyCode | 是 | NGN |
contractCode | 是 | Monnify 合同号 |
customerEmail | 是 | 客户邮箱 |
customerName | 是 | 客户姓名 |
bvn | 是 | 客户 BVN |
getAllAvailableBanks | 是 | 是否返回所有可用银行 |
preferredBanks | 是 | 偏好银行,文档示例为 50515 |
restrictPaymentSource | 否 | 是否限制付款来源,降低误入账 |
allowedPaymentSources | 否 | 允许付款账号/BVN 等 |
nin | 否 | 客户 NIN |
时序
sequenceDiagram participant App as 客户 App participant FCS as 贷款/FCS participant PMT as pmt participant Monnify as Monnify FCS->>PMT: 请求创建还款虚拟账户 PMT->>Monnify: POST /api/v2/bank-transfer/reserved-accounts Monnify-->>PMT: 返回账户号、银行、accountReference PMT-->>FCS: 保存并展示给客户 App->>Monnify: 客户转账还款 Monnify-->>PMT: Transaction Completion Webhook PMT->>PMT: 校验签名、幂等检查 PMT->>Monnify: GET /api/v2/merchant/transactions/query Monnify-->>PMT: 确认 PAID PMT-->>FCS: 通知入账 FCS->>FCS: 分配本金/利息/罚息/费用
6. 回调、安全和对账
6.1 Webhook
Monnify Dashboard 需要配置以下 URL:
| 类型 | 用途 |
|---|---|
| Transaction Completion | 卡支付、转账收款、虚拟账户入账 |
| Disbursement | 放款结果通知 |
| Settlement | 结算对账 |
| Refund | 退款结果,如后续启用 |
回调处理要求:
- 校验请求头
monnify-signature。 - 按文档使用 Secret Key + 原始请求体计算 SHA-512 后比较签名。
- 回调只做轻量处理,先落库再异步处理,及时返回 HTTP 200。
- 用
transactionReference、paymentReference、reference做幂等键,重复回调不能重复入账或重复推进状态。 - 回调后再调用查询接口确认状态,不只信任回调 payload。
- 如条件允许,按 Monnify Dashboard 或支持团队提供的信息限制回调来源 IP。
6.2 对账
| 场景 | 对账接口 | 频率 |
|---|---|---|
| 放款 | GET /api/v2/disbursements/search-transactions、GET /api/v2/disbursements/single/summary | T+0 每 15 分钟补偿,T+1 日终 |
| 卡 token 扣款 | GET /api/v2/merchant/transactions/query、GET /api/v1/transactions/search | T+0 每 15 分钟补偿,T+1 日终 |
| 虚拟账户还款 | GET /api/v1/bank-transfer/reserved-accounts/transactions、GET /api/v2/merchant/transactions/query | T+0 每 15 分钟补偿,T+1 日终 |
8. MVP 实施范围
8.1 必做
- Monnify 认证 token 获取和缓存。
- 银行列表同步与账户校验。
- Card Tokenization 绑卡、OTP/3DS 分流、交易查询、token 落库。
- 单笔放款、OTP 授权、放款状态查询。
- Card Token 自动还款扣款、扣款状态查询。
- Reserved Account 创建与交易查询,作为手动还款兜底。
- Webhook 接收、签名校验、幂等、异步处理。
- T+0 补偿任务和 T+1 对账任务。
9. 验收标准
- Sandbox 能完成 Card Tokenization 绑卡流程,覆盖
SUCCESS、OTP、3DS 分支,并正确保存cardToken、maskedPan、后四位、有效期和状态。 - Sandbox 能完成单笔放款发起、OTP 授权和状态查询,成功后 FCS 只推进一次放款状态。
- Sandbox 能完成
Charge Card Token扣款发起和状态查询,成功后 FCS 只入账一次。 - Sandbox 能创建 Reserved Account,并通过交易查询或回调完成主动还款入账。
- Webhook 签名校验失败时拒绝处理;重复 webhook 不重复入账。
- 网络超时、Monnify 5xx、业务失败均进入可观测的补偿队列。
10. 参考资料
- Monnify API Reference: https://developers.monnify.com/api
- OpenAPI Collection: https://developers.monnify.com/collection/monnify-collection.yml
- Direct Debit: https://developers.monnify.com/docs/collections/recurring-payments/direct-debit
- Reserved / Virtual Accounts: https://developers.monnify.com/docs/collections/recurring-payments/reserved-accounts
- Disbursement: https://developers.monnify.com/docs/disbursements
- Webhook Event Types: https://developers.monnify.com/docs/webhooks/event-types
- Going Live: https://developers.monnify.com/docs/live