印度银行 API 如何自动处理 NEFT 付款?
结论
可以自动处理,但普通银行账户加上 API token、customer id 和金额,并不足以直接发起 NEFT 转账。
你通常需要开通银行的企业支付 API、Host-to-Host 服务,或者接入具备相应资质的支付服务商。银行可能还会要求预先登记收款人、设置固定出口 IP、使用数字签名、执行双人审批、遵守交易限额,并对回调进行验签。
customer id 只是自定义应用中的内部标识。转账时,系统仍要根据它读取收款人姓名、银行账号、IFSC、金额、业务用途等银行要求的字段。
为什么普通网银接口不够
NEFT 是银行间资金转账网络,并不是任意应用都能直接调用的公共 API。应用必须通过开户银行或合规服务商提供的接口提交付款指令。
具体能做什么,取决于银行和账户类型:
- 个人账户一般没有自动批量付款 API。
- 企业往来账户通常可以申请 Corporate Banking API 或 Host-to-Host 接入。
- 某些银行要求先通过 API 或网银登记 beneficiary,登记完成后才能付款。
- 有些接口可以全自动执行,有些仍需授权人登录网银审批。
- 银行可能对单笔金额、单日累计金额及收款人启用时间作出限制。
选择银行或服务商前,需要确认其接口是否支持 NEFT payout,而不是只支持余额和交易流水查询。
推荐的系统流程
1. 开通企业付款能力
向开户银行申请企业 API,并确认:
- 是否支持 NEFT 转账;
- 是否支持批量付款;
- 是否必须提前登记收款人;
- 是否需要 maker-checker 审批;
- 认证方式是 OAuth 2.0、API key、mTLS 还是请求签名;
- 单笔和每日交易限额;
- 是否提供状态查询和 webhook;
- 测试环境及生产环境有哪些接入要求。
如果银行没有合适的 API,可以评估提供 payout API 的服务商,但要核实其监管资质、资金流向、结算模式和数据存储要求。
2. 保存并验证客户银行资料
客户资料至少需要包含:
customer_id
account_holder_name
account_number
ifsc
bank_name
verification_status
问题中的 “NEFT code” 通常是指 IFSC,例如 HDFC0001234。实际参数名称应以银行 API 文档为准。
只验证 IFSC 格式还不够。正式付款前,还应通过银行提供的账户验证功能、微额验证或其他合规方式,核对账号和收款人信息。验证通过后保存验证状态,避免后续付款继续使用未经核验的数据。
3. 在服务端创建付款指令
前端只提交 customer_id、金额和业务订单号。其余工作由后端完成:
- 验证调用者权限;
- 查询客户银行资料;
- 确认客户资料已经验证;
- 校验金额、币种和付款规则;
- 创建唯一的幂等键;
- 调用银行付款 API;
- 保存银行返回的交易编号和初始状态;
- 通过 webhook 或查询接口更新最终结果。
银行 API 凭证不能直接保存在浏览器或移动端。
示例代码
下面的 Node.js 示例只用于说明调用结构。URL、字段名、签名方法和状态值都是占位内容,必须按照所选银行或服务商的真实规范替换。
import crypto from "node:crypto";
async function payCustomer({ customerId, amountPaise, orderId }) {
const customer = await db.customers.findById(customerId);
if (!customer) {
throw new Error("Customer not found");
}
if (customer.verificationStatus !== "verified") {
throw new Error("Beneficiary bank account is not verified");
}
if (!Number.isInteger(amountPaise) || amountPaise <= 0) {
throw new Error("Invalid amount");
}
const idempotencyKey = crypto
.createHash("sha256")
.update(`neft:${orderId}`)
.digest("hex");
const existingPayment = await db.payments.findByIdempotencyKey(
idempotencyKey
);
if (existingPayment) {
return existingPayment;
}
const payment = await db.payments.create({
customerId,
orderId,
amountPaise,
idempotencyKey,
status: "created"
});
const requestBody = {
reference_id: payment.id,
transfer_mode: "NEFT",
amount: (amountPaise / 100).toFixed(2),
currency: "INR",
beneficiary: {
name: customer.accountHolderName,
account_number: customer.accountNumber,
ifsc: customer.ifsc
}
};
const response = await fetch(
"https://api.example-bank.in/v1/transfers",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.BANK_API_TOKEN}`,
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey
},
body: JSON.stringify(requestBody)
}
);
const result = await response.json();
if (!response.ok) {
await db.payments.update(payment.id, {
status: "submission_failed",
errorCode: result.code
});
throw new Error(`Bank rejected transfer: ${result.code ?? "UNKNOWN"}`);
}
return db.payments.update(payment.id, {
status: "submitted",
bankReference: result.transfer_id
});
}
这不是任何银行的官方 SDK 示例。部分银行要求对请求体进行 HMAC 签名、使用客户端证书或加密敏感字段,遇到这些要求时,应严格按照银行文档实现。
正确处理异步状态
API 返回成功,通常只说明银行已经接收请求,并不表示客户已经收到资金。NEFT 付款可能经历以下状态:
created → submitted → processing → successful
└──→ failed
└──→ returned
应用需要保存银行交易编号,并通过 webhook 或状态查询接口确认最终结果。
Webhook 处理程序必须验证签名,同时能正确处理重复通知:
app.post("/webhooks/bank", async (req, res) => {
if (!verifyBankSignature(req)) {
return res.status(401).send("Invalid signature");
}
const event = req.body;
await db.transaction(async (tx) => {
const alreadyProcessed = await tx.webhookEvents.exists(event.event_id);
if (alreadyProcessed) {
return;
}
await tx.webhookEvents.insert(event.event_id);
await tx.payments.updateByBankReference(event.transfer_id, {
status: mapBankStatus(event.status)
});
});
res.sendStatus(200);
});
发生网络超时后,不要马上创建一笔新转账。应先使用原来的 reference_id 或幂等键查询状态,否则可能造成重复付款。
批量支付给所有客户
批量付款不能只是遍历所有客户,再无限并发调用接口。更稳妥的流程是先创建付款批次,然后将每笔付款放入队列:
创建付款批次
↓
检查余额和总金额
↓
冻结批次中的客户与金额快照
↓
逐笔或按银行批量格式提交
↓
接收状态回调
↓
对账并处理失败、退回和重试
创建批次前,需要确认每位客户获得相应金额的依据。客户资料中有银行账号,并不代表系统可以自动向其付款。
如果银行支持 batch payout API,可以优先使用批量接口。如果只支持单笔接口,则必须遵守并发数和速率限制。只有已经确认未被受理的交易才能重试。交易状态不明确时,应先查询状态。
安全与合规注意事项
- API token、客户端私钥和证书只能存放在服务端的密钥管理系统中。
- 银行账号属于敏感数据,需要加密存储,并限制日志、客服及运营人员的访问权限。
- 日志不得记录完整账号、token、签名或未脱敏的请求体。
- 修改收款账户后需要重新验证,也可以设置冷静期或人工复核。
- 对大额交易、频率异常的交易及新收款账户设置风险控制。
- 保存业务订单号、内部付款编号、银行交易编号和状态变更记录,以便审计和对账。
- 根据业务性质确认 KYC、AML、税务、退款和客户授权要求。
- 不要假设所有 API 都能全天实时到账。具体处理时间、节假日规则和服务窗口,应以开户银行的当前规则为准。
NEFT 并不适用于所有付款场景。对于小额且要求即时到账的付款,可以询问银行是否支持 IMPS 或 UPI。大额交易则可能需要考虑 RTGS。选择哪种方式,要结合金额、到账时效、手续费、限额和银行 API 的实际能力。
自定义应用可以实现这套功能,但重点不是寻找一个通用的 “NEFT API token”,而是取得银行或合规服务商的企业付款接入资格,并处理好收款人验证、幂等控制、异步状态、风险审核和对账。
备注:内容仅供参考。
