NexaPay支付API集成文档 (v 1.3)
1. API 环境与端点
访问凭证
NexaPay线下提供,区分为UAT和生产两套环境, 开通需要联系商户专员获取, 具体信息包括:
- api_key用作区分开发者接入身份标识
- secret_key用作双方通讯的密钥, 主要用于信息签名和验签
基础 URL

身份验证
必要请求头
-
api_key: 用来验证开发者身份标识符
-
Content-Type: application/json; charset=UTF-8
-
signature: 数字签名,采用HMC-SHA256算法, 用于确保安全通信,具体见后面的代码示例
2. 接口列表
2.1 DirectPay支付
接口地址:/api/v1/directPay
2.1.1. 场景
商户拥有独立收银系统,直接向 Nexapay端发送支付请求字段。
2.1.2 工作流程步骤
2.1.2.1.1 买家发起支付请求
买家在商户平台提交支付请求,选择支付方式(银行卡、电子钱包等),填写交易金额及相关信息,并确认支付。
2.1.2.1.2 商户服务器调用 PSP/Nexapay Pay API
商户服务器收集买家支付信息,并通过 API 将支付请求发送至 PSP/Nexapay 进行处理。
2.1.2.1.3 Nexapay 处理请求并返回响应
Nexapay 接收支付请求后,进行交易处理,并将支付结果(成功、失败、处理中)返回至商户服务器。
2.1.2.1.4 商户服务器向买家返回支付结果
商户服务器根据 Nexapay 返回的支付结果,向买家展示交易状态:
- 支付成功:页面提示“支付成功”,并展示交易详情。
- 支付失败:提示失败原因,并提供重试或更换支付方式的选项。
- 支付处理中:提示“支付处理中”,引导用户稍后查询订单状态。
2.1.2.1.5 获取支付结果
- 被动通知模式:Nexapay 主动向 PSP/商户服务器推送支付结果,并支持失败重试机制(默认最多 3 次)。
- 主动查询模式:商户可在订单有效期内,主动向 Nexapay 查询支付状态,以获取最新的交易结果。
2.1.3 整体交互流程

2.1.4 请求

2.1.5 响应

2.1.6 示例
接口地址:/api/v1/directPay
请求
curl --location --request POST 'http://118.31.222.186/api/v1/directPay' \
--header 'api_key: 3258e9eaec8bdc65b84e8bbfd387c076' \
--header 'Content-Type: application/json' \
--header 'signature: xN/ewpHtq4NLkzTKZufv+2Wna1JHeH3ljydG099q5KQ=' \
--data '{
"amount": "100",
"currency": "BRL",
"payCurrent": "BRL",
"merchantId": "225",
"subMerchantId": "225",
"payer": {
"type": 2,
"name": "test",
"email": "1xample@example.com",
"phoneNumber": "+5511987654321",
"document": "12.345.678/0001-90"
},
"orderId": "1863911682520730001",
"requestId": "1863911682520730002",
"orderName": "Sample Order",
"goodsName": "Sample Goods",
"notifyUrl": "https://example.com/notify"
}'
响应
{
"code": "0",
"msg": "成功",
"data": {
"payStatus": "P",
"merchantId": "225",
"subMerchantId": "225",
"orderId": "1863911682520730006",
"requestId": "1863911681733920735",
"txId": "202412110210110100000000018",
"payAmount": "100.89",
"currency": "BRL",
"payCurrency": "BRL",
"payLoad": {
"qrCode": "00020126910014BR.GOV.BCB.PIX2569api-pix-h.bancobs2.com.br/spi/v2/4034530b-7a61-4032-a0fa-20b28d56cbd15204000053039865406100.895802BR5907Nexapay6014Belo Horizonte61083038040362070503***63040CC9",
"expire": "600",
"createDate": "1733921082562"
},
"chargeFees": [
{
"feeType": "PAYER_FEE",
"feeAmount": "0.50",
"feeCurrency": "BRL"
},
{
"feeType": "IOF",
"feeAmount": "0.39",
"feeCurrency": "BRL"
}
]
},
"succ": true
}
2.2 收银台支付
接口地址:/api/v1/directPay/order/create
2.2.1 场景
商户使用我方收银系统,直接完成支付。
2.2.2 工作流程步骤
2.2.2.1 买家发起支付请求
买家在商户平台提交支付请求,选择支付方式(银行卡、电子钱包等),填写支付金额及交易信息,并确认支付。
2.2.2.2 商户服务器调用 PSP/Nexapay Pay API
商户服务器收集买家支付信息,并通过 API 将支付请求转发至 PSP/Nexapay 进行处理。
2.2.2.3 返回收银台地址
Nexapay 处理支付请求后,返回Nexapay 收银台地址至商户服务器。
2.2.2.4 收银台跳转
商户系统引导买家跳转至 Nexapay 收银台,完成支付操作。
2.2.2.5 支付成功跳转
支付成功后,系统自动回跳至商户页面,并展示支付结果及相关订单信息。
2.2.2.6 获取支付结果
- 被动通知模式:Nexapay 主动向 PSP/商户服务器推送支付结果,并支持失败重试机制(默认最多 3 次)。
- 主动查询模式:商户可在订单有效期内,主动向 Nexapay 查询支付状态,以获取最新交易结果(可选)。
2.2.3 整体交互流程

2.2.4 请求

2.2.5 响应

2.2.6 示例
请求:
curl --location --request POST 'http://118.31.222.186/api/v1/directPay/order/create' \
--header 'api_key: 3258e9eaec8bdc65b84e8bbfd387c076' \
--header 'Content-Type: application/json' \
--header 'signature: xN/ewpHtq4NLkzTKZufv+2Wna1JHeH3ljydG099q5KQ=' \
--data '{
"amount": "9200",
"currency": "USD",
"merchantId": "1840690697213079001",
"subMerchantId": "1840690697213079002",
"payer": {
"type": 1,
"name": "test",
"email": "test@qq.com",
"phoneNumber": "+5511987654321",
"document": "12345678900"
},
"orderId": "186391168252074000H",
"requestId": "184069069721307000I",
"orderName": "Sample Order",
"goodsName": "Sample Goods",
"notifyUrl": "http://example.com/notifyUrl",
"callbackUrl": "http://example.com/callbackUrl"
}'
响应
{
"code": "0",
"msg": "成功",
"data": {
"cashierPayUrl": "http://www.nexapay.com.cn/product/checkout/ac93e9ee-e600-4b0b-ada0-c44e05f206f7?md5=f1212836c4bed479a500784a5d7f7f91×tamp=1738737032342&signature=%2Fz5RQ4TxWXtx5J7qRnt8CCokFZ%2Bvlu%2B4aYIbG0ajM%2Fs%3D",
"txId": "202502050210110100000000001",
"orderId": "186391168252074000H"
},
"succ": true
}
2.3 支付结果通知
- 签名验证:商户端仍需验证回调数据的签名以确保数据安全。(商户的签名结果和nexapay返回的签名进行比较)
- 配置回调 URL:由商户端在支付订单创建需求中指定,具体见获取二维码中notifyUrl。
- 通知机制: 针对银行已返回支付成功的订单会定时推送商户方, 直到签收成功。200状态码即视为成功。
2.3.1 响应参数

示例
curl --location --request POST 'http://*.*.*.*/notify' \
--header 'Content-Type: application/json' \
--header 'signature: xN/ewpHtq4NLkzTKZufv+2Wna1JHeH3ljydG099q5KQ=' \
--data '{
{
"notifyType": "PAYMENT_RESULT",
"merchantId": "189897777807097711",
"subMerchantId": "189897777807097712",
"orderId": "189897777807097712",
"txId": "189897777807097713",
"requestId": "189897777807097714",
"payStatus": "T",
"payAmount": "100.8900000000000000",
"payCurrency": "BRL",
"payTime": "2024-10-01 11:37:47",
"chargeFees": [
{
"feeType": "PAYER_FEE",
"feeAmount": "0.50",
"feeCurrency": "BRL"
},
{
"feeType": "IOF",
"feeAmount": "0.39",
"feeCurrency": "BRL"
}
]
}'
2.4 支付结果查询
接口地址:/api/v1/directPay/query
2.4.1 请求参数

2.4.2 响应参数

2.4.3 示例
请求
curl --location --request POST 'http://118.31.222.186/api/v1/directPay/query' \
--header 'api_key: 3258e9eaec8bdc65b84e8bbfd387c076' \
--header 'Content-Type: application/json' \
--header 'signature: xN/ewpHtq4NLkzTKZufv+2Wna1JHeH3ljydG099q5KQ=' \
--data '{
"orderId": "1863911682520739003",
"txId": "202412080210110100000000010"
}
响应
{
"code": "0",
"msg": "成功",
"data": {
"orderId": "1863911682520739003",
"requestId": "1863911681733715402",
"txId": "202412090210110100000000001",
"payStatus": "S",
"merchantId": "225",
"subMerchantId": "225",
"payAmount": "100.8900000000000000",
"payCurrency": "BRL",
"payTime": "2024-12-09 11:37:47",
"chargeFees": [
{
"feeType": "PAYER_FEE",
"feeAmount": "0.50",
"feeCurrency": "BRL"
},
{
"feeType": "IOF",
"feeAmount": "0.39",
"feeCurrency": "BRL"
}
]
},
"succ": true
}
附录

支付状态代码

费用类型

常见返回代码及描述

备注
签名生成细节
- 将 secret_key作为密钥,与参数拼接后计算哈希值。
- 拼接参数字符串:将 params 按字典顺序排序并拼接。
- 用 secret_key作为密钥计算 HMAC-SHA-256:使用 secret_key来生成哈希,类似于 HMAC(哈希消息认证码)的方式。以下是Java代码示例
- Json工具类由商户侧自行实现,请根据Accsic码 排序后,压缩,以下示例仅供参考
Java
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.TreeMap;
@Slf4j
public class HMACSHA256Util {
public static void main(String[] args) throws Exception {
String secretKey = "secret_key";
String reqJson = "{\"amount\":\"73800\",\"currency\":\"BRL\",\"goodsName\":\"锂电池\",\"merchantId\":\"1840690697213079001\",\"notifyUrl\":\"https://example.com/notify\",\"orderId\":\"1863816181848834001\",\"orderName\":\"展示名字\",\"payer\":{\"document\":\"12345678900\",\"email\":\"s.jycv@qq.com\",\"name\":\"Jack\",\"phoneNumber\":\"+8612345678901\",\"type\":1},\"requestId\":\"1863816181848834001\",\"subMerchantId\":\"1840690697213079002\"}\n";
System.out.println("排序前待签报文:" + reqJson);
String sign = sign(reqJson, secretKey);
System.out.println("签值:" + sign);
boolean verify = verify(reqJson, secretKey, sign);
System.out.println("验签结果:" + verify);
}
public static String sign(String reqJson, String secretKey) throws NoSuchAlgorithmException, InvalidKeyException {
// 解析 JSON 字符串为 JSONObject
JSONObject jsonObject = JSON.parseObject(reqJson);
// 对 JSONObject 进行排序
TreeMap sortedParameters = sortJSONObject(jsonObject);
// 将排序后的 TreeMap 转换为 JSON 字符串
String jsonString = JSON.toJSONString(sortedParameters);
// 生成 HMAC-SHA256 签名
Mac hmacSHA256 = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
hmacSHA256.init(secretKeySpec);
log.info("排序后待签报文:{}", jsonString);
byte[] hash = hmacSHA256.doFinal(jsonString.getBytes(StandardCharsets.UTF_8));
String sign = DatatypeConverter.printBase64Binary(hash);
log.info("签名:{}", sign);
return sign;
}
// 验证签名的方法
public static boolean verify(String reqJson, String secretKey, String providedSignature) throws Exception {
// 生成签名
String generatedSignature = sign(reqJson, secretKey);
// 比较生成的签名和提供的签名
return generatedSignature.equals(providedSignature);
}
public static TreeMap sortJSONObject(JSONObject jsonObject) {
if (jsonObject == null) {
return null;
}
TreeMap sortedMap = new TreeMap<>();
for (String key : jsonObject.keySet()) {
Object value = jsonObject.get(key);
if (value instanceof JSONObject) {
sortedMap.put(key, sortJSONObject((JSONObject) value));
} else {
sortedMap.put(key, value);
}
}
return sortedMap;
}
}
Python
import hmac
import hashlib
import base64
import json
def generate_hmac_sha256_signature(secret_key, data):
# 创建 HMAC-SHA256 对象
hasher = hmac.new(secret_key.encode(), data.encode(), digestmod=hashlib.sha256)
# 获取签名的二进制结果
hash_bytes = hasher.digest()
# 将签名转换为 Base64 编码
signature = base64.b64encode(hash_bytes).decode()
return signature
if __name__ == "__main__":
secret_key = "e10adc3949ba59abbe56e057f20f883e"
signature_json = {
"amount": "73800",
"currency": "BRL",
"requestId": "1863816181848834001",
"merchantId": "1840690697213079559",
"subMerchantId": "1840690697213079560",
"payer": {
"type": 1,
"name": "Jack",
"email": "s.jycv@qq.com",
"phoneNumber": "+8612345678901",
"document": "12345678900"
},
"orderId": "1863816181848834001",
"orderName": "展示名字",
"goodsName": "锂电池",
"notifyUrl": "https://example.com/notify"
}
signature_str = json.dumps(signature_json, sort_keys=True, ensure_ascii=False, separators=(',', ':'))
# signature_str = signature_str.replace(" ", "")
print("signature_str:",signature_str)
# 生成签名
signature = generate_hmac_sha256_signature(secret_key, signature_str)
print("signature:",signature)
PHP
交易限制条款
- 最小交易金额:1.00 BRL。
- 退款:可在原始交易日期起 90 天内申请退款,退款将退回至原支付账户
- 其它限制条款具体见双方合同约定
测试/UAT 指导
- 测试环境:使用 Nexapay 提供的 UAT 环境进行测试。
- 测试用例:
- 成功支付:使用有效数据模拟支付成功场景。
- 签名失败:提供无效签名测试系统错误处理。
- 无效货币:使用非 BRL 货币代码测试系统验证。