支持全印度主流支付方式,UPI / 银行转账 / 电子钱包全覆盖
Google Pay、PhonePe、Paytm 等主流 UPI 应用全面支持,支付转化率高。
覆盖印度主要银行 IMPS/NEFT/RTGS,大额代收稳定可靠。
支付成功后 T+0 实时到账商户余额,无需等待人工审核。
安全高效的资金代付方案,支持批量代付和自动代付
覆盖 UPI VPA 和银行 IFSC 两大模式,任意 Bank 任意转入。
商户提交代付申请后系统自动匹配最优上游通道,fifo 秒级处理。
提交即校验商户余额,防止恶意透支,双重签名保障资金安全。
TRC20 / ERC20 双网络支持,秒级兑换,汇率透明
对接多个流动性池,实时获取最优汇率,买卖价差极低。
TRC20 网络 3-5 秒上链确认,ERC20 2-5 分钟,资金即时可用。
热钱包保持小额流转,冷钱包多签托管,平台级资金安全架构。
真实印度公司银行账户租赁,合规经营、风控完备
HDFC、ICICI、SBI 等主流银行真实对公账户,开户快速(1-3 工作日),支持 PAN / GSTIN 绑定。
KYC 审核 + 交易监控 + 反洗钱合规。每户独立 netbanking 登录,月租灵活,长期稳定。
HMAC-SHA256 签名 · JSON 通信 · 代收/代付 RESTful API
版本:v2.0(TP8 架构)
生成日期:2026-06-06
签名方式:HMAC-SHA256(旧版 MD5 已停用)
---
1. 接入概览
2. 鉴权与签名
3. 代收下单
4. 代付下单
5. 代收回调
6. 代付回调
7. 错误码
8. 签名示例代码
9. 测试环境
---
| 项目 | 说明 |
| 接口地址 | https:// |
| 协议 | HTTPS,POST(除特别说明) |
| 编码 | UTF-8 |
| 数据格式 | 请求 & 响应 统一为 application/json(已于 2026-06 切走 form-urlencoded) |
| 数字精度 | 所有金额字段以字符串形式传递(如 "500.0000"),避免 PHP json_decode 的 32/64 位精度丢失 |
| 签名算法 | HMAC-SHA256,十六进制小写,作用于 JSON body 中的全部字段 |
| 幂等性 | 所有下单接口支持幂等:相同商户订单号重复提交返回原订单,duplicate=true |
重要: 商户回调地址在 商户后台 → API 设置 中配置,下单时不再传入 pay_notifyurl。---
每个商户有一个 API memberid(公开ID),等于平台内部 ID + 10000。
在商户后台"API 设置"页面可查看。每笔请求必须携带此 ID。
所有请求和回调均使用同一套签名算法。
步骤:
1. 取请求的全部参数(Key-Value 对)
2. 移除 sign 字段本身
3. 移除 value 为空字符串 "" 或 null 的字段
4. 将剩余字段按 Key 的 ASCII 升序 排列
5. 拼接成 key1=value1&key2=value2&... 形式的字符串(称为 canonical string)
6. 计算 HMAC-SHA256(canonical_string, hmac_secret),取十六进制小写结果作为 sign
sign = lowercase( hex( hmac_sha256( canonical_string, hmac_secret ) ) )
canonical string 示例:
原始参数(无顺序要求):
pay_memberid=220964988
pay_orderid=ORDER-20260606-001
pay_amount=500.00
pay_bankcode=413
attach=user123
sign=(本次要计算的,不参与签名)
按 key ASCII 排序后(忽略 sign):
attach=user123&pay_amount=500.00&pay_bankcode=413&pay_memberid=220964988&pay_orderid=ORDER-20260606-001
然后对上述字符串计算 HMAC-SHA256,使用商户的 hmac_secret(64位十六进制字符串)作为密钥。
注意: value 中的数值类型不转换,原样拼接(如500.00就是500.00,不要转成500)。
收到平台回调后,同样按上述算法计算签名,与回调中的 sign 字段对比,完全相等则验签通过。
---
| 项目 | 说明 |
| 请求地址 | POST /api/deposit/create |
| Content-Type | application/json |
| 请求体 | 一个 JSON 对象,字段见下表 |
| 参数 | 类型 | 必填 | 说明 |
pay_memberid | string | ✅ | 商户 API ID(后台"API 设置"可查) |
pay_orderid | string | ✅ | 商户自定义订单号,同一商户下唯一,建议格式 ORDER-YYYYMMDD-序号 |
pay_amount | string | ✅ | 代收金额,字符串形式(如 "500.00"),单位 INR,必须 > 0 |
pay_bankcode | string | ✅ | 支付渠道代码,如 413(由平台分配,见渠道列表) |
pay_applydate | string | ❌ | 申请时间,格式 YmdHis,如 20260606120000;缺省使用服务器当前时间 |
attach | string | ❌ | 自定义附加信息,原样在回调中返回,最长 255 字符 |
sign | string | ✅ | HMAC-SHA256 签名,见第 2 节 |
{
"status": "success",
"memberid": "220964988",
"order_no": "20260606120000a1b2c3",
"amount": "500.0000",
"duplicate": false,
"gateway_ok": true,
"redirect_url": "https://pay.upstream.com/checkout/xxxxx",
"gateway_msg": "",
"sign": "3ff6a28f..."
}
| 字段 | 类型 | 说明 |
status | string | success / fail |
memberid | string | 商户 API ID |
order_no | string | 平台系统订单号(格式:YmdHis + 6位随机十六进制,共 20 位),回调中作为 transaction_id 返回 |
amount | string | 实际创建金额,4 位小数字符串 |
duplicate | bool | true 表示该 pay_orderid 已存在,返回的是原订单信息,请勿重复创建 |
gateway_ok | bool | 上游网关接单是否成功 |
redirect_url | string | 支付跳转地址,gateway_ok=true 时有效,请将用户引导至此地址完成支付 |
gateway_msg | string | 网关错误信息(gateway_ok=false 时有参考价值) |
sign | string | 平台对响应的签名,建议验签确认数据未被篡改 |
POST /api/deposit/create HTTP/1.1
Content-Type: application/json
Content-Length: 234
{
"pay_memberid": "220964988",
"pay_orderid": "ORDER-20260606-001",
"pay_amount": "500.00",
"pay_bankcode": "413",
"pay_applydate": "20260606120000",
"attach": "user123",
"sign": "3ff6a28fbd40285b737d344acf677247209aa093cce2860cd0a7f2bb73a132b8"
}
---
| 项目 | 说明 |
| 请求地址 | POST /api/payout/create |
| Content-Type | application/json |
| 请求体 | 一个 JSON 对象,字段见下表 |
| 参数 | 类型 | 必填 | 说明 |
pay_memberid | string | ✅ | 商户 API ID |
pay_orderid | string | ✅ | 商户自定义订单号,唯一 |
pay_amount | string | ✅ | 代付金额,字符串形式(如 "1000.00"),单位 INR,必须 > 0 |
paymode | string | ✅ | 付款方式,二选一:bank(银行转账)/ upi(UPI 支付) |
bank_account | string | ✅ | 收款账号(银行账号或 UPI ID) |
bank_name | string | ✅ | 银行名称(UPI 时填收款人 VPA 关联的银行名),如 HDFC Bank |
bank_holder | string | ✅ | 收款人姓名(与银行/UPI 开户名一致) |
ifscode | string | 视情况 | 当 paymode=bank:必填,11 位字符串,第 5 位必须为 0(标准 IFSC 格式 AAAA0XXXXXX,例:SBIN0001234);当 paymode=upi:可填任意值(如 UPI VPA),可留空 |
sign | string | ✅ | HMAC-SHA256 签名 |
字段命名变更(2026-06):旧文档的ifsc字段已迁移到pay_wttklist.ifscode;新增的paymode区分bank和upi两种支付通道。
{
"status": "success",
"memberid": "220964988",
"order_no": "PO20260606120000a1b2c3",
"amount": "1000.0000",
"paymode": "bank",
"duplicate": false,
"gateway_ok": true,
"gateway_msg": "",
"sign": "7a4c..."
}
| 字段 | 类型 | 说明 |
status | string | success / fail |
memberid | string | 商户 API ID |
order_no | string | 平台系统订单号(格式:PO + YmdHis + 6位随机十六进制),回调中作为 transaction_id 返回 |
amount | string | 实际代付金额,4 位小数字符串 |
paymode | string | 回显请求中的 paymode |
duplicate | bool | 重复提交时为 true |
gateway_ok | bool | 上游网关是否接单成功;部分渠道为异步,此处 false 不代表最终失败 |
gateway_msg | string | 网关错误信息 |
sign | string | 平台对响应的签名 |
银行转账(paymode=bank):
POST /api/payout/create HTTP/1.1
Content-Type: application/json
Content-Length: 197
{
"pay_memberid": "220964988",
"pay_orderid": "PAYOUT-20260606-001",
"pay_amount": "1000.00",
"paymode": "bank",
"bank_account": "9876543210",
"bank_name": "SBI",
"bank_holder": "Raj Kumar",
"ifscode": "SBIN0001234",
"sign": "..."
}
UPI 支付(paymode=upi):
POST /api/payout/create HTTP/1.1
Content-Type: application/json
Content-Length: 170
{
"pay_memberid": "220964988",
"pay_orderid": "PAYOUT-20260606-002",
"pay_amount": "500.00",
"paymode": "upi",
"bank_account": "merchant@upi",
"bank_name": "HDFC",
"bank_holder": "Merchant",
"ifscode": "",
"sign": "..."
}
签名错误响应:
{ "status": "fail", "msg": "sign error" }
参数校验失败:
{ "status": "fail", "msg": "ifscode must be 11 chars with 5th char = 0 (e.g. SBIN0001234)" }
或
{ "status": "fail", "msg": "paymode must be \"bank\" or \"upi\"" }
---
上游网关确认支付成功后,平台异步将结果 POST 到商户在后台配置的 代收回调地址(deposit_callback_url)。
application/json)| 字段 | 类型 | 说明 |
memberid | string | 商户 API ID |
orderid | string | 商户订单号(即下单时传入的 pay_orderid) |
transaction_id | string | 平台系统订单号(即下单响应中的 order_no) |
amount | string | 支付金额,字符串 形式,如 "500.0000" |
datetime | string | 支付成功时间,格式 YmdHis |
returncode | string | "00" = 成功 |
attach | string | 下单时传入的 attach 字段原样返回 |
sign | string | HMAC-SHA256 签名(算法同第 2 节) |
商户服务器处理完成后,必须返回纯文本字符串 ok(不区分大小写,忽略前后空白),HTTP 状态码 200。
HTTP/1.1 200 OK
Content-Type: text/plain
ok
若未收到 ok,平台按以下间隔自动重试,最多 5 次:| 第 N 次 | 等待时间 |
| 第 1 次失败后 | 1 分钟 |
| 第 2 次失败后 | 5 分钟 |
| 第 3 次失败后 | 30 分钟 |
| 第 4 次失败后 | 2 小时 |
| 第 5 次失败后 | 12 小时 |
5 次全部失败后不再重试,可在管理后台 Callbacks 页面查看失败记录并手动处理。
POST https://your-server.com/deposit/notify HTTP/1.1
Content-Type: application/json
Content-Length: 197
{
"memberid": "220964988",
"orderid": "ORDER-20260606-001",
"transaction_id":"20260606120000a1b2c3",
"amount": "500.0000",
"datetime": "20260606121530",
"returncode": "00",
"attach": "user123",
"sign": "3ff6a28f..."
}
---
上游网关反馈代付结果(成功或失败)后,平台异步 POST 到商户的 代付回调地址(payout_callback_url)。
application/json)| 字段 | 类型 | 说明 |
memberid | string | 商户 API ID |
orderid | string | 商户订单号(即下单时传入的 pay_orderid) |
transaction_id | string | 平台系统订单号(即下单响应中的 order_no,以 PO 开头) |
amount | string | 代付金额,字符串形式,如 "1000.0000" |
status | string | "success" = 成功;"failed" = 失败 |
datetime | string | 回调时间,格式 YmdHis |
returncode | string | "00" = 成功;"01" = 失败 |
sign | string | HMAC-SHA256 签名 |
同代收回调,返回 ok 确认收到。重试策略相同(1m / 5m / 30m / 2h / 12h,最多 5 次)。
---
| HTTP 状态码 | status | msg | 原因 |
| 400 | fail | invalid pay_memberid | pay_memberid 不合法(< 10001) |
| 400 | fail | merchant not found | 该 memberid 对应的商户不存在 |
| 403 | fail | merchant inactive | 商户被停用 |
| 400 | fail | sign error | 签名验证失败 |
| 400 | fail | invalid pay_memberid | 请求体不是 application/json、JSON 解析失败、或缺少 pay_memberid |
msg | 原因 |
pay_orderid required | 缺少商户订单号 |
pay_amount must be > 0 | 金额不合法 |
pay_bankcode required | 缺少渠道代码(代收接口) |
bank_account, bank_name, bank_holder required | 缺少收款人信息(代付接口) |
create failed | 创建订单失败(内部错误) |
---
function hmac_sign(array $params, string $secret): string {
// 1. 移除 sign 字段
unset($params['sign']);
// 2. 移除空值
$params = array_filter($params, fn($v) => $v !== '' && $v !== null);
// 3. ASCII 升序排列
ksort($params, SORT_STRING);
// 4. 拼接 canonical string
$canonical = implode('&', array_map(
fn($k, $v) => $k . '=' . $v,
array_keys($params), array_values($params)
));
// 5. 计算 HMAC-SHA256
return hash_hmac('sha256', $canonical, $secret);
}
// 使用示例
$params = [
'pay_memberid' => '220964988',
'pay_orderid' => 'ORDER-20260606-001',
'pay_amount' => '500.00',
'pay_bankcode' => '413',
'attach' => 'user123',
];
$params['sign'] = hmac_sign($params, 'your_hmac_secret_here');
// 发起请求
$ch = curl_init('https://your-domain.com/api/deposit/create');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
import hmac, hashlib, requests
def hmac_sign(params: dict, secret: str) -> str:
p = {k: v for k, v in params.items() if k != 'sign' and v not in ('', None)}
canonical = '&'.join(f"{k}={v}" for k, v in sorted(p.items()))
return hmac.new(secret.encode(), canonical.encode(), hashlib.sha256).hexdigest()
params = {
'pay_memberid': '220964988',
'pay_orderid': 'ORDER-20260606-001',
'pay_amount': '500.00',
'pay_bankcode': '413',
'attach': 'user123',
}
params['sign'] = hmac_sign(params, 'your_hmac_secret_here')
resp = requests.post(
'https://your-domain.com/api/deposit/create',
json=params, # requests 会自动设置 Content-Type: application/json
)
print(resp.json())
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;
public static String hmacSign(Map<String, String> params, String secret) throws Exception {
params.remove("sign");
// 移除空值
params.entrySet().removeIf(e -> e.getValue() == null || e.getValue().isEmpty());
// ASCII 升序
TreeMap<String, String> sorted = new TreeMap<>(params);
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> e : sorted.entrySet()) {
if (sb.length() > 0) sb.append('&');
sb.append(e.getKey()).append('=').append(e.getValue());
}
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
byte[] raw = mac.doFinal(sb.toString().getBytes("UTF-8"));
StringBuilder hex = new StringBuilder();
for (byte b : raw) hex.append(String.format("%02x", b));
return hex.toString();
}
function verify_callback(array $body, string $secret): bool {
$given = $body['sign'] ?? '';
return hash_equals(hmac_sign($body, $secret), strtolower($given));
}
// 接收回调:直接读原始 POST body 并 json_decode
$raw = file_get_contents('php://input');
$body = json_decode($raw, true);
if (!is_array($body) || !verify_callback($body, 'your_hmac_secret_here')) {
http_response_code(400);
exit('sign error');
}
// 处理业务逻辑(金额字段都是字符串,按需用 (float) 转)
if ($body['returncode'] === '00') {
update_order($body['orderid'], 'paid', (float) $body['amount']);
}
echo 'ok'; // 必须返回 ok
---
| 项目 | 说明 |
| 本地地址 | http://localhost:8000 |
| 启动命令 | php think run(在 thinkphp8/ 目录下) |
| 队列 Worker | php think queue:work database --queue default --tries 6 |
⚠️ 仅限本地开发环境使用,切勿用于生产。
| 项目 | 值 |
| 商户用户名 | DemoPay |
| 商户后台密码 | DemoPay@2026(首次登录需重置) |
API memberid(pay_memberid) | 220964988 |
| HMAC secret | 在商户后台 API 设置 页面查看 |
平台提供一个调试端点,输入参数后返回 canonical string 和 sign,方便排查签名问题:
GET/POST /api/diag/sign?pay_memberid=220964988&pay_orderid=TEST-001&pay_amount=100.00&...
响应示例:
{
"canonical": "pay_amount=100.00&pay_memberid=220964988&pay_orderid=TEST-001",
"sign": "计算出的签名"
}
1. 启动服务器和队列 Worker
2. 调用 POST /api/deposit/create 创建订单,记录响应中的 order_no 和 redirect_url
3. 模拟上游回调:POST /api/notify/show/deposit(见 Mock 接口)
4. 观察商户的 deposit_callback_url 是否收到回调(returncode=00)
5. 回调日志在管理后台 Callbacks 页可查看
---
| 名称 | 方法 | URL |
| 代收下单 | POST | /api/deposit/create |
| 代付下单 | POST | /api/payout/create |
| 签名调试 | GET/POST | /api/diag/sign |
| 缓存调试 | GET/POST | /api/diag/cache |
旧版 URL(兼容保留,实际请求仍走新逻辑):
- /Pay_Show_notifyurl.html — Show 渠道代收上游回调- /Payment_Show_dfnotify.html — Show 渠道代付上游回调