XnPay API 文档
快速、安全、可靠的支付解决方案
- RESTful API 设计,简单易用
- 支持 PHP、Python、Golang 等多种语言
- 完整的支付流程:支付、查询、代付等
- 实时回调通知
- MD5 和 SHA256 签名验证
基本规则
生产环境:
https://api.xnpurl.com/xnpurl-apiapplication/json支付接口
请求参数
| 参数名 | 说明 | 类型 | 必填 | 例子 |
|---|---|---|---|---|
| merchantCode | 商户号 | String | Y | test |
| orderNumber | 用户订单号 | String | Y | 1604384758793 |
| amount | 金额 | Integer | Y | 40000 |
| phone | 电话 | String | Y | 08123456789 |
| String | Y | test@test.com | ||
| userName | 名称 | String | Y | John Doe |
| walletNumber | 钱包账号 | String | N | 08821900000 (DANA必填,格式08********;OVO收银台必传真实号码,否则不需要此参数) |
| channelCode | 渠道编码 | String | Y | M1(若为CASH,会使用收银台支付;其他编码请见渠道编码对照表) |
| returnUrl | 返回地址 | String | N | http://test/return |
| callbackUrl | 回调地址 | String | Y | http://test/callback |
| sign | 签名 | String | Y | MD5(...) |
签名规则
MD5(amount + callbackUrl + channelCode + merchantCode + orderNumber + md5_key)
响应参数
| 参数名 | 说明 | 类型 | 例子 |
|---|---|---|---|
| code | 返回码 | String | 000 |
| message | 返回消息 | String | success |
| orderNumber | 订单号 | String | O3915CB3C93E445C9 |
| accountNumber | 银行账号 | String | TEST0001 (VA才有) |
| paymentUrl | 支付地址 | String | http://xxx.xxx/ |
| qrcode | 二维码 | String | QRIS支付会返回二维码源码 |
| merchantCode | 商户号 | String | test |
请求示例
{
"merchantCode": "test",
"orderNumber": "1604384758793",
"amount": 40000,
"phone": "08123456789",
"email": "test@test.com",
"userName": "John Doe",
"channelCode": "M1",
"returnUrl": "http://test/return",
"callbackUrl": "http://test/callback",
"sign": "a1b2c3d4e5f6..."
}响应示例
{
"code": "000",
"message": "success",
"orderNumber": "O3915CB3C93E445C9",
"paymentUrl": "http://xxx.xxx/",
"qrcode": "data:image/png;base64,..."
}package com.customer.demo;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import java.util.HashMap;
import java.util.Map;
public class ZkpayPaymentDemo {
public static void main(String[] args) {
String url = "https://api.xnpurl.com/xnpurl-api/payment";
String merchantCode = "test";
String key = "Gjon5exBp34mkNUU0r4wk2delkbclF4i";
String orderNumber = System.currentTimeMillis() + "";
Integer amount = 40000;
String phone = "08123456789";
String email = "test@test.com";
String userName = "John Doe";
String channelCode = "M1";
String returnUrl = "http://test/return";
String callbackUrl = "http://test/callback";
Digester md5 = new Digester(DigestAlgorithm.MD5);
String signOrigin = amount + callbackUrl + channelCode + merchantCode + orderNumber + key;
String sign = md5.digestHex(signOrigin);
System.out.println(sign);
Map<String, Object> param = new HashMap<>();
param.put("merchantCode", merchantCode);
param.put("orderNumber", orderNumber);
param.put("amount", amount);
param.put("phone", phone);
param.put("email", email);
param.put("userName", userName);
param.put("channelCode", channelCode);
param.put("returnUrl", returnUrl);
param.put("callbackUrl", callbackUrl);
param.put("sign", sign);
String sendParam = JSON.toJSONString(param);
System.out.println("request==> " + sendParam);
String result = HttpUtil.post(url, sendParam, 10000);
System.out.println("response==> " + result);
}
}支付查询
请求参数
| 参数名 | 说明 | 类型 | 必填 | 例子 |
|---|---|---|---|---|
| merchantCode | 商户号 | String | Y | test |
| orderNumber | 用户订单号 | String | Y | 1604384758793 |
| sign | 签名 | String | Y | MD5(...) |
签名规则
MD5(merchantCode + orderNumber + md5_key)
响应参数
| 参数名 | 说明 | 类型 | 例子 |
|---|---|---|---|
| code | 返回码 | String | 000 |
| message | 返回消息 | String | complete |
| userOrderNumber | 用户订单号 | String | 1604384968942 |
| orderNumber | 平台订单号 | String | test16043849702603 |
| amount | 支付金额 | Integer | 40000 |
| merchantCode | 商户号 | String | test |
| phone | 电话 | String | 已隐藏,显示00 |
| String | 已隐藏,显示00 | ||
| userName | 名称 | String | John Doe |
| channelCode | 渠道编码 | String | M1 |
| status | 支付状态 | int | 0 待支付,1 支付成功,2 订单失败 |
| createTime | 订单发起时间 | Date | 2020-11-03 13:29:30 |
| payTime | 支付时间 | Date | 2020-11-03 13:39:30 支付成功时返回 |
请求示例
{
"merchantCode": "test",
"orderNumber": "1604384758793",
"sign": "a1b2c3d4e5f6..."
}响应示例
{
"code": "000",
"status": 1,
"amount": 40000
}import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import java.util.HashMap;
import java.util.Map;
public class CheckPaymentDemo {
public static void main(String[] args) {
String url = "https://api.xnpurl.com/xnpurl-api/checkPayment";
String merchantCode = "test";
String key = "Gjon5exBp34mkNUU0r4wk2delkbclF4i";
String orderNumber = "1604384758793";
Digester md5 = new Digester(DigestAlgorithm.MD5);
String signOrigin = merchantCode + orderNumber + key;
String sign = md5.digestHex(signOrigin);
Map<String, Object> param = new HashMap<>();
param.put("merchantCode", merchantCode);
param.put("orderNumber", orderNumber);
param.put("sign", sign);
String sendParam = JSON.toJSONString(param);
String result = HttpUtil.post(url, sendParam, 10000);
System.out.println("response==> " + result);
}
}代付接口
请求参数
| 参数名 | 说明 | 类型 | 必填 | 例子 |
|---|---|---|---|---|
| merchantCode | 商户号 | String | Y | test |
| orderNumber | 用户订单号 | String | Y | 1604384758793 |
| amount | 金额 | Integer | Y | 40000 |
| bankAccount | 银行账号 | String | Y | 100100100 |
| bankCode | 银行编码 | String | Y | PERMATA |
| phone | 电话 | String | Y | 08123456789 |
| String | Y | test@test.com | ||
| userName | 对方名称 | String | Y | John Doe |
| channelCode | 渠道编码 | String | Y | ALL |
| returnUrl | 返回地址 | String | N | http://test/return |
| callbackUrl | 回调地址 | String | Y | http://test/callback |
| sign | 签名 | String | Y | SHA256(...) |
响应参数
| 参数名 | 说明 | 类型 | 例子 |
|---|---|---|---|
| code | 返回码 | String | 000 |
| message | 返回消息 | String | success |
| amount | 支付金额 | Integer | 40000 |
| merchantCode | 商户号 | String | test |
签名规则
SHA256(amount + bankAccount + bankCode + callbackUrl + channelCode + merchantCode + orderNumber + sha256_key)
PS
channelCode 可用通道:ALL 所有通道可用,ID IDN US ZH 不同国家,无特殊说明请使用ALL
请求示例
{
"merchantCode": "test",
"orderNumber": "1604384758793",
"amount": 50000,
"bankAccount": "1234567890",
"bankCode": "BCA",
"phone": "08123456789",
"email": "test@test.com",
"userName": "John Doe",
"channelCode": "ALL",
"returnUrl": "http://test/return",
"callbackUrl": "http://test/callback",
"sign": "a1b2c3d4e5f6..."
}响应示例
{
"code": "000",
"message": "success",
"orderNumber": "1604384758793"
}import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import java.util.HashMap;
import java.util.Map;
public class DisbursementDemo {
public static void main(String[] args) {
String url = "https://api.xnpurl.com/xnpurl-api/disbursement";
String merchantCode = "test";
String key = "Gjon5exBp34mkNUU0r4wk2delkbclF4i";
String orderNumber = "1604384758793";
Integer amount = 50000;
String bankAccount = "1234567890";
String bankCode = "BCA";
String callbackUrl = "http://test/callback";
String channelCode = "B1";
Digester sha256 = new Digester(DigestAlgorithm.SHA256);
String signOrigin = amount + bankAccount + bankCode + callbackUrl + channelCode + merchantCode + orderNumber + key;
String sign = sha256.digestHex(signOrigin);
Map<String, Object> param = new HashMap<>();
param.put("merchantCode", merchantCode);
param.put("orderNumber", orderNumber);
param.put("amount", amount);
param.put("bankAccount", bankAccount);
param.put("bankCode", bankCode);
param.put("sign", sign);
String sendParam = JSON.toJSONString(param);
String result = HttpUtil.post(url, sendParam, 10000);
System.out.println("response==> " + result);
}
}代付查询
请求参数
| 参数名 | 说明 | 类型 | 必填 | 例子 |
|---|---|---|---|---|
| merchantCode | 商户号 | String | Y | test |
| orderNumber | 用户订单号 | String | Y | 1604384758793 |
| sign | 签名 | String | Y | SHA256(...) |
响应参数
| 参数名 | 说明 | 类型 | 例子 |
|---|---|---|---|
| code | 返回码 | String | 000 |
| message | 返回消息 | String | complete |
| userOrderNumber | 用户订单号 | String | 1604384968942 |
| orderNumber | 平台订单号 | String | test16043849702603 |
| amount | 支付金额 | Integer | 40000 |
| merchantCode | 商户号 | String | test |
| phone | 电话 | String | 已隐藏,显示00 |
| String | 已隐藏,显示00 | ||
| userName | 对方名称 | String | John Doe |
| bankCode | 银行编码 | String | PERMATA |
| bankAccount | 银行账号 | String | 100100100 |
| channelCode | 渠道编码 | String | M1 |
| status | 支付状态 | int | 1 (0 待支付,1 代付成功,2 代付失败) |
| createTime | 订单发起时间 | Date | 2020-11-03 13:29:30 |
| payTime | 支付时间 | Date | 2020-11-03 13:39:30 支付成功时返回 |
签名规则
SHA256(merchantCode + orderNumber + sha256_key)
请求示例
{
"merchantCode": "test",
"orderNumber": "1604384758793",
"sign": "a1b2c3d4e5f6..."
}响应示例
{
"code": "000",
"status": 1,
"amount": 50000
}import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import java.util.HashMap;
import java.util.Map;
public class CheckDisbursementDemo {
public static void main(String[] args) {
String url = "https://api.xnpurl.com/xnpurl-api/checkDisbursement";
String merchantCode = "test";
String key = "Gjon5exBp34mkNUU0r4wk2delkbclF4i";
String orderNumber = "1604384758793";
Digester sha256 = new Digester(DigestAlgorithm.SHA256);
String signOrigin = merchantCode + orderNumber + key;
String sign = sha256.digestHex(signOrigin);
Map<String, Object> param = new HashMap<>();
param.put("merchantCode", merchantCode);
param.put("orderNumber", orderNumber);
param.put("sign", sign);
String sendParam = JSON.toJSONString(param);
String result = HttpUtil.post(url, sendParam, 10000);
System.out.println("response==> " + result);
}
}可用渠道查询
请求参数
| 参数名 | 说明 | 类型 | 必填 | 例子 |
|---|---|---|---|---|
| merchantCode | 商户号 | String | Y | test |
| timestamp | 时间戳 | String | Y | 1604384758793 |
| sign | 签名 | String | Y | MD5(merchantCode + timestamp + key) |
响应参数
| 参数名 | 说明 | 类型 | 例子 |
|---|---|---|---|
| code | 返回码 | String | 000 |
| message | 返回消息 | String | query success |
| channelCodeList | 渠道集合 | LIST | |
| - channelCode | 渠道代码 | String | BT |
| - channelType | 渠道类型 | Integer | 0 支付渠道 1 代付渠道 |
| - channelRate | 渠道费率 | Double | 7.0 |
| - channelFee | 渠道服务费 | Integer | 200 |
签名规则
MD5(merchantCode + timestamp + key)
请求示例
{
"merchantCode": "test",
"timestamp": 1604384758793,
"sign": "a1b2c3d4e5f6..."
}响应示例
{
"code": "000",
"channels": [
{
"channelCode": "M1",
"channelName": "QRIS",
"minAmount": 1000,
"maxAmount": 10000000
}
]
}余额查询
请求参数
| 参数名 | 说明 | 类型 | 必填 | 例子 |
|---|---|---|---|---|
| merchantCode | 商户号 | String | Y | test |
| timestamp | 时间戳 | String | Y | 1604384758793 |
| sign | 签名 | String | Y | SHA256(merchantCode + timestamp + sha256_key) |
响应参数
| 参数名 | 说明 | 类型 | 例子 |
|---|---|---|---|
| code | 返回码 | String | 000 |
| message | 返回消息 | String | balance query success |
| merchantCode | 商户号 | String | 1604384968942 |
| merchantBlance | 商户余额 | Integer | 540000 |
| merchantFrozenAmount | 冻结金额 | Integer | 40000 |
| canUseAmount | 可用金额 | Integer | 500000 |
| settlementList | 待结算金额列表 | LIST | |
| - settlementDate | 结算日期 | String | 2020-12-28 |
| - settlementAmount | 待结算金额 | Integer | 44500 |
签名规则
SHA256(merchantCode + timestamp + sha256_key)
请求示例
{
"merchantCode": "test",
"timestamp": 1604384758793,
"sign": "a1b2c3d4e5f6..."
}响应示例
{
"code": "000",
"balance": 1000000
}异步回调
支付完成后,系统会向您配置的 callbackUrl 发送 POST 请求
回调参数
| 参数名 | 说明 | 类型 | 示例 |
|---|---|---|---|
| code | 返回码 | String | 000 |
| message | 返回消息 | String | complete |
| orderNumber | 用户订单号 | String | 1604384968942 |
| amount | 支付金额 | Integer | 40000 |
| merchantCode | 商户号 | String | test |
| phone | 电话(已隐藏) | String | 00 |
| Email(已隐藏) | String | 00 | |
| userName | 名称 | String | John Doe |
| channelCode | 渠道编码 | String | M1 |
| status | 支付状态:0待支付,1成功 | int | 1 |
| createTime | 订单发起时间(时间戳) | Date | 1617695193459 |
| payTime | 支付时间(时间戳,成功时返回) | Date | 1617695193459 |
| sign | 签名 | String | MD5(amount + channelCode + email + merchantCode + orderNumber + phone + userName + md5_key) |
签名规则
MD5(amount + channelCode + email + merchantCode + orderNumber + phone + userName + md5_key)
回调示例
{
"code": "000",
"message": "complete",
"orderNumber": "1604384968942",
"amount": 40000,
"merchantCode": "test",
"phone": "00",
"email": "00",
"userName": "John Doe",
"channelCode": "M1",
"status": 1,
"createTime": 1617695193459,
"payTime": 1617695193459,
"sign": "a1b2c3d4e5f6..."
}应答:请返回状态值 200 确认收到回调
代付完成后,系统会向您配置的 callbackUrl 发送 POST 请求
回调参数
| 参数名 | 说明 | 类型 | 示例 |
|---|---|---|---|
| code | 返回码 | String | 000 |
| message | 返回消息 | String | complete |
| orderNumber | 用户订单号 | String | 1604384968942 |
| amount | 代付金额 | Integer | 40000 |
| merchantCode | 商户号 | String | test |
| phone | 电话(已隐藏) | String | 00 |
| Email(已隐藏) | String | 00 | |
| userName | 对方名称 | String | John Doe |
| bankCode | 银行编码 | String | PERMATA |
| bankAccount | 银行账号 | String | 100100100 |
| channelCode | 渠道编码 | String | ALL |
| status | 代付状态:1成功,2失败 | int | 1 |
| createTime | 订单发起时间(时间戳) | Date | 1617695193459 |
| payTime | 支付时间(时间戳,成功时返回) | Date | 1617695193459 |
| sign | 签名 | String | SHA256(amount + bankAccount + bankCode + channelCode + email + merchantCode + orderNumber + phone + userName + sha256_key) |
签名规则
SHA256(amount + bankAccount + bankCode + channelCode + email + merchantCode + orderNumber + phone + userName + sha256_key)
回调示例
{
"code": "000",
"message": "complete",
"orderNumber": "1604384968942",
"amount": 40000,
"merchantCode": "test",
"phone": "00",
"email": "00",
"userName": "John Doe",
"bankCode": "PERMATA",
"bankAccount": "100100100",
"channelCode": "ALL",
"status": 1,
"createTime": 1617695193459,
"payTime": 1617695193459,
"sign": "a1b2c3d4e5f6..."
}应答:请返回状态值 200 确认收到回调
支付渠道编码对照表
| channel_code | channel_name | 类型 |
|---|---|---|
| QRIS | QRIS | 收款 |
| VC | Credit Card (Visa / Master) | 收款 |
| BK | BCA KlikPay | 收款 |
| BCA | BCA Virtual Account | 收款 |
| BBC | BCA BC | 收款 |
| M1 | Mandiri Virtual Account | 收款 |
| ME | Mandiri eCash | 收款 |
| MP | Mandiri PC | 收款 |
| BT | Permata Bank Virtual Account | 收款 |
| PN | Permata Net | 收款 |
| A1 | ATM Bersama | 收款 |
| B1 | CIMB Niaga Virtual Account | 收款 |
| I1 | BNI Virtual Account | 收款 |
| VA | Maybank Virtual Account | 收款 |
| M2U | Maybank2U | 收款 |
| FT | Ritel | 收款 |
| OV | OVO | 收款 |
| LA | LINKAJA | 收款 |
| DANA | DANA | 收款 |
| SP | Shopee Pay | 收款 |
| SA | Shopee Pay Apps | 收款 |
| AG | Bank Artha Graha | 收款 |
| S1 | Sahabat Sampoerna | 收款 |
| NI | Bank Negara Indonesia | 收款 |
| RI | Bank Rakyat Indonesia | 收款 |
| RIE | BRI ePay | 收款 |
| IN | INDOMARET | 收款 |
| AL | ALFAMART | 收款 |
| DOB | Danamon Online Banking | 收款 |
| DVA | Danamon Virtual Account | 收款 |
| AI | Alto iDebit | 收款 |
| JIB | Jenius IB | 收款 |
| JA | JAKONE | 收款 |
| OC | Octo Clicks | 收款 |
| SK | Sakuku | 收款 |
| ALF | Alfagroup | 收款 |
| KR | Kredivo | 收款 |
| BL | BTNONLINE | 收款 |
| SVA | Sinarmas Virtual Account | 收款 |
| CASH | 收银台支付 | 收款 |
| ID_ALL | 印尼代付全渠道 | 代付 |
| channel_code | channel_name | 类型 |
|---|---|---|
| PK_JAZZ | JAZZ钱包 | 收款 |
| PK_EASY | EASY钱包 | 收款 |
| PK_ALL | 巴基斯坦代付全渠道 | 代付 |
| channel_code | channel_name | 类型 |
|---|---|---|
| BR_BRL | 二维码支付 (QR Code) | 收款 |
| BR_ALL | PIX代付渠道 | 代付 |
银行编码对照表
🇮🇩 印度尼西亚 (Indonesia)
| bank_code | bank_name |
|---|---|
| BCA | Bank BCA |
| BRI | Bank BRI |
| MANDIRI | BANK MANDIRI |
| BNI | BANK BNI 46 |
| CIMB | BANK CIMB NIAGA |
| PERMATA | BANK PERMATA |
| BJB | Bank BJB |
| DANAMON | BANK DANAMON INDONESIA |
| BTN | Bank BTN |
| MAYBANK | BANK MAYBANK INDONESIA |
| SINARMAS | BANK SINARMAS |
| PANIN | BANK PANIN |
| BNI_SYR | BANK BNI SYARIAH |
| MANDIRI_SYR | BANK SYARIAH MANDIRI |
| DKI | BPD DKI JAKARTA |
| MEGA | BANK MEGA |
| BSI | BSI (Bank Syariah Indonesia) |
| BTPN | Bank BTPN |
| BRI_SYR | BANK BRI SYARIAH |
| MUAMALAT | BANK MUAMALAT INDONESIA |
| OCBC | BANK OCBC NISP |
| OVO | OVO |
| SHOPEEPAY | SHOPEEPAY |
| DANA | DANA |
| GOPAY | GOPAY |
| LINKAJA | LINKAJA |
🇵🇰 巴基斯坦 (Pakistan)
| bank_code | bank_name |
|---|---|
| PK_EASY | EASY钱包 (EASY Wallet) |
| PK_JAZZ | JAZZ钱包 (JAZZ Wallet) |
🇧🇷 巴西 (Brazil)
| bank_code | bank_name |
|---|---|
| BR_CPF | CPF号码 (CPF Number) |
| BR_PHONE | 手机号 (Phone Number) |
| BR_EMAIL | 邮箱 (Email) |