如何在 WordPress 和 ASP.NET 网站集成印度支付方式?
结论
WordPress 和 ASP.NET 都能接入印度信用卡、借记卡和 NetBanking。比较省事且安全的做法,是选择一家印度支付聚合服务商,通过托管结账页或官方 SDK 完成支付,无需分别对接银行和卡组织。
需要特别注意的是,不能默认某个 WordPress 插件同时支持 Credit Card、Debit Card、NetBanking 和 Airtel Money。前三项是印度支付网关常见的支付方式,Airtel Money 是否可用,则可能受服务商、商户类型、账户地区和当前合作政策影响。签约前应要求支付服务商书面确认,最终以商户后台实际开通的渠道为准。
选择支付服务商
可以咨询在印度提供商户收款服务的支付网关,如 Razorpay、Cashfree Payments、PayU 或 Paytm Payment Gateway。选择时需要确认:
- 是否支持印度发行的 Credit Card 和 Debit Card;
- 是否覆盖所需银行的 NetBanking;
- Airtel Money 是以钱包、Airtel Payments Bank,还是其他支付渠道的形式提供;
- 是否有适用于 WooCommerce 的官方插件;
- 是否提供 ASP.NET SDK 或通用 REST API;
- 是否支持 Webhook、退款、订单查询和支付签名验证;
- 结算周期、手续费、最低交易额和退款费用;
- 开户是否需要印度公司、印度银行账户、PAN、GSTIN 等材料;
- 是否支持你的业务类别、交易币种和目标客户所在地区。
不要只看插件页面上展示的支付方式图标。即使某种支付方式出现在结账界面,也不代表商户账户已经获批使用。
WordPress 集成方案
如果网站使用 WooCommerce,建议优先选择支付服务商提供或明确认可的 WooCommerce 插件。
通常需要完成以下步骤:
- 注册支付服务商的商户账户并完成 KYC。
- 在商户后台申请需要使用的支付渠道。
- 获取测试环境凭据,如
Key ID、Key Secret或Client ID。 - 在 WordPress 后台安装对应的 WooCommerce 支付插件。
- 进入 WooCommerce → 设置 → 付款,启用该网关。
- 填写测试凭据并配置 Webhook URL。
- 分别测试支付成功、失败、取消、超时和退款。
- 确认测试结果无误后,再切换到生产凭据。
如果网站没有使用 WooCommerce,可以通过服务商的 WordPress 插件、支付链接或自定义插件接入。不要直接修改主题的 functions.php 来保存支付密钥,否则容易引发升级冲突,也会增加密钥泄露的风险。
WordPress 自定义 Webhook 示例
下面的代码只演示 WordPress 接收 Webhook 的基本结构。事件名称、签名算法和请求头必须按照所选支付服务商的官方文档实现。
<?php
add_action('rest_api_init', function () {
register_rest_route('payments/v1', '/webhook', [
'methods' => 'POST',
'callback' => 'handle_payment_webhook',
'permission_callback' => '__return_true',
]);
});
function handle_payment_webhook(WP_REST_Request $request)
{
$rawBody = $request->get_body();
$signature = $request->get_header('x-payment-signature');
if (!verify_gateway_signature($rawBody, $signature)) {
return new WP_REST_Response(
['error' => 'Invalid signature'],
401
);
}
$event = json_decode($rawBody, true);
if (!is_array($event)) {
return new WP_REST_Response(
['error' => 'Invalid payload'],
400
);
}
// 根据支付服务商的事件结构读取订单号和支付状态。
// 更新 WooCommerce 订单前,还应查询并核对金额、币种和商户订单号。
return new WP_REST_Response(['received' => true], 200);
}
function verify_gateway_signature(string $payload, string $signature): bool
{
$secret = PAYMENT_WEBHOOK_SECRET;
// 这里只是常见的 HMAC-SHA256 示例。
// 实际算法、编码格式和请求头名称必须以支付服务商文档为准。
$expected = hash_hmac('sha256', $payload, $secret);
return hash_equals($expected, $signature);
}
生产环境中的密钥应存放在服务器环境变量、WordPress 配置或专用密钥管理系统中,不要写入可公开访问的插件文件。
ASP.NET 集成方案
ASP.NET 网站一般通过支付服务商的 .NET SDK 或 REST API 接入。推荐的模式是由服务器创建订单,浏览器打开托管结账页,再由服务器验证支付结果。
典型流程如下:
- ASP.NET 服务端根据本地订单创建支付订单;
- 服务端将支付订单编号和公开凭据返回给浏览器;
- 浏览器打开服务商的托管结账页;
- 用户选择卡、NetBanking 或已经开通的钱包;
- 支付完成后,浏览器将支付结果提交给服务端;
- 服务端验证签名;
- 服务端通过订单查询接口或 Webhook 确认最终状态;
- 核对金额、币种和订单号一致后,更新本地订单。
ASP.NET Core 创建支付订单的结构示例
以下代码展示了一种推荐的分层方式。IPaymentGateway 并非某家服务商提供的官方接口,需要根据实际使用的 SDK 或 REST API 实现。
public sealed record CreatePaymentRequest(
string OrderId,
long AmountInPaise,
string Currency
);
public sealed record PaymentOrderResult(
string GatewayOrderId,
string PublicKey,
long AmountInPaise,
string Currency
);
public interface IPaymentGateway
{
Task<PaymentOrderResult> CreateOrderAsync(
CreatePaymentRequest request,
CancellationToken cancellationToken
);
bool VerifySignature(
string gatewayOrderId,
string paymentId,
string signature
);
}
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/payments")]
public sealed class PaymentsController : ControllerBase
{
private readonly IPaymentGateway _paymentGateway;
public PaymentsController(IPaymentGateway paymentGateway)
{
_paymentGateway = paymentGateway;
}
[HttpPost("orders")]
public async Task<ActionResult<PaymentOrderResult>> CreateOrder(
[FromBody] CreatePaymentRequest request,
CancellationToken cancellationToken)
{
if (request.AmountInPaise <= 0)
{
return BadRequest("Amount must be greater than zero.");
}
if (!string.Equals(request.Currency, "INR",
StringComparison.OrdinalIgnoreCase))
{
return BadRequest("Unsupported currency.");
}
// 生产环境应从数据库读取订单金额,
// 不应直接信任浏览器提交的 AmountInPaise。
var result = await _paymentGateway.CreateOrderAsync(
request,
cancellationToken
);
return Ok(result);
}
}
印度支付 API 经常使用最小货币单位表示金额。例如,₹499.00 通常会表示为 49900 paise,具体仍应以所选服务商的 API 说明为准。
ASP.NET Core 支付结果验证示例
public sealed record VerifyPaymentRequest(
string GatewayOrderId,
string PaymentId,
string Signature
);
[HttpPost("verify")]
public IActionResult VerifyPayment(
[FromBody] VerifyPaymentRequest request)
{
var valid = _paymentGateway.VerifySignature(
request.GatewayOrderId,
request.PaymentId,
request.Signature
);
if (!valid)
{
return Unauthorized(new
{
verified = false,
message = "Invalid payment signature."
});
}
// 验签成功不一定等于资金已经最终结算。
// 还应核对本地订单、金额、币种,并结合查询接口或 Webhook 确认状态。
return Ok(new { verified = true });
}
密钥应通过配置系统读取:
{
"PaymentGateway": {
"PublicKey": "set-through-environment-variables",
"SecretKey": "set-through-environment-variables",
"WebhookSecret": "set-through-environment-variables"
}
}
不要将生产密钥直接提交到 appsettings.json、Git 仓库或前端 JavaScript。只有服务商明确标记为公开的 Key 才能发送给浏览器。
Airtel Money 需要单独确认
Airtel Money 是这项需求中最容易引起误解的部分。不同支付服务商可能会:
- 将其归类为 Wallet;
- 只支持 Airtel Payments Bank 的部分支付流程;
- 仅向符合条件的商户开放;
- 调整或停止某种旧版钱包接口;
- 在 API 中保留渠道名称,但当前商户账户无法启用。
购买插件或开始开发前,应向服务商确认:
我的印度商户账户能否在生产环境接受 Airtel Money 付款?它在 API 和结账页中的准确渠道名称是什么?WooCommerce 插件和 REST API 是否都支持该渠道?
如果没有服务商能同时提供所有渠道,可以使用一个主支付网关处理卡和 NetBanking,再为 Airtel 相关支付增加第二个网关。但这种方案会增加对账、退款、Webhook 和订单状态管理的复杂度。
测试与上线注意事项
上线前至少要测试以下场景:
- Credit Card 和 Debit Card 支付成功及失败;
- 3-D Secure、OTP 或其他身份验证流程;
- NetBanking 用户中途取消;
- 支付成功,但浏览器没有返回网站;
- Webhook 重复发送或乱序到达;
- 金额、币种或订单号不一致;
- 全额退款和部分退款;
- 测试凭据误用于生产环境;
- 同一个支付通知被重复处理。
订单状态不能只依据前端跳转结果判断。用户可能在支付成功后直接关闭页面,网络也可能在跳转过程中中断。应主要依据通过验签的 Webhook 和服务端订单查询结果,并对 Webhook 做幂等处理,防止重复发货。
使用托管结账页通常能减少网站直接接触银行卡数据的范围,但不代表网站会自动满足所有合规要求。仍需确认 PCI DSS、印度监管要求、隐私政策、税务规定和支付服务商的商户条款。具体义务取决于业务模式、公司所在地和实际支付流程。
备注:内容仅供参考。
