3. 统一下单接口
商户通过该接口创建支付订单,获取支付链接或二维码。
3.1 请求参数
参数名 |
类型 |
必填 |
说明 |
mchid |
string |
是 |
商户ID |
out_trade_no |
string |
是 |
商户订单号,唯一 |
amount |
decimal |
是 |
支付金额,单位:元 |
currency |
string |
是 |
币种,例如:INR |
subject |
string |
是 |
订单标题 |
body |
string |
是 |
商品描述 |
channel |
string |
是 |
支付渠道,例如:lakshine |
client_ip |
string |
是 |
客户端IP |
notify_url |
string |
是 |
异步通知地址 |
return_url |
string |
是 |
同步跳转地址 |
extparam |
object |
否 |
扩展参数(可选),透传返回 |
注意:签名验证通过请求头进行,不在请求参数中传递。请参考签名算法章节了解详细的签名生成方法。
3.2 响应参数
参数名 |
类型 |
说明 |
result_code |
string |
固定为 OK |
result_msg |
string |
请求结果:SUCCESS /FAIL |
charge |
object |
支付信息 |
charge.channel |
string |
支付渠道 |
charge.out_trade_no |
string |
商户订单号 |
charge.client_ip |
string |
客户端IP |
charge.amount |
string |
订单金额 |
charge.currency |
string |
币种 |
charge.subject |
string |
订单标题 |
charge.body |
string |
商品描述 |
charge.extparam |
object |
扩展参数(请求透传) |
charge.credential |
object |
支付凭证(不同渠道字段不同) |
charge.credential.card_number |
string |
卡号/UPI地址 |
charge.credential.card_realname |
string |
卡真实姓名 |
charge.credential.card_type_name |
string |
卡类型名称 |
charge.credential.pay_amount |
string |
支付金额 |
charge.credential.usdt_amount |
string |
USDT金额 |
charge.credential.order_id |
string |
订单ID |
3.3 请求示例
POST /pay/unifiedorder HTTP/1.1
Host: api.lakshine.com
X-Ca-Auth: your_api_key
X-Ca-Signature: base64_encoded_signature
X-Ca-Noncestr: abc123def456
X-Ca-Timestamp: 1704412800000
X-Ca-Resturl: https://api.lakshine.com/pay/unifiedorder
Content-Type: application/x-www-form-urlencoded
Accept: application/json
mchid=123456789&out_trade_no=TEST202501050001&amount=1000¤cy=INR&subject=商品购买&body=购买说明&channel=lakshine&client_ip=127.0.0.1¬ify_url=https://your-domain.com/notify&return_url=https://your-domain.com/return
3.4 响应示例
{
"result_code": "OK",
"result_msg": "SUCCESS",
"charge": {
"channel": "lakshine",
"out_trade_no": "TEST202501050001",
"client_ip": "127.0.0.1",
"amount": "1000",
"currency": "INR",
"subject": "商品购买",
"body": "购买说明",
"extparam": {},
"credential": {
"card_number": "aaaaa@upi",
"card_realname": "Gfeee4",
"card_type_name": "UPI",
"pay_amount": "999.27",
"usdt_amount": "10.6305",
"order_id": "123"
}
}
}
8. 异步通知
支付成功后,平台会向商户配置的notify_url发送异步通知。
6.1 通知参数
异步通知采用JSON格式,包含以下字段:
参数名 |
类型 |
说明 |
result_code |
string |
结果代码,固定为"OK" |
result_msg |
string |
结果消息,固定为"SUCCESS" |
charge |
object |
订单详情对象 |
6.1.1 charge对象字段
参数名 |
类型 |
说明 |
puid |
int |
用户ID |
out_trade_no |
string |
商户订单号 |
subject |
string |
商品标题 |
body |
string |
商品描述 |
channel |
string |
支付渠道 |
extra |
string |
扩展参数(JSON字符串) |
amount |
string |
支付金额 |
income |
string |
收入金额 |
user_in |
string |
用户收入 |
agent_in |
string |
代理收入 |
platform_in |
string |
平台收入 |
currency |
string |
货币类型 |
client_ip |
string |
客户端IP |
return_url |
string |
同步跳转地址 |
notify_url |
string |
异步通知地址 |
user_confirm_status |
int |
用户确认状态 |
user_pay_no |
string |
用户支付单号 |
6.2 签名验证
异步通知的签名验证通过请求头进行,与API请求的签名算法相同。
6.2.1 请求头参数
请求头 |
说明 |
示例 |
X-Ca-Signature |
RSA签名结果 |
base64_encoded_signature |
X-Ca-Noncestr |
32位随机字符串 |
BF147C6111BB4F2EC5B4AD1DF14D9110 |
X-Ca-Timestamp |
时间戳(毫秒) |
1754807077046 |
Content-Type |
内容类型 |
application/json |
6.2.2 签名验证步骤
- 获取请求头中的签名相关参数(X-Ca-Signature、X-Ca-Noncestr、X-Ca-Timestamp)
- 从请求体中提取charge对象数据
- 构建待签名数据:随机字符串 + 时间戳 + charge对象JSON字符串
- 对构建的数据进行Base64编码
- 使用RSA公钥验证签名(SHA1算法)
- 验证通过后处理业务逻辑
注意:异步通知不需要X-Ca-Auth认证,只需要验证签名即可。签名验证使用平台提供的RSA公钥。
注意:异步通知的签名验证与API请求略有不同,只对charge对象进行签名,而不是整个请求体。
6.3 通知示例
POST /notify HTTP/1.1
Host: your-domain.com
Content-Type: application/json
X-Ca-Signature: base64_encoded_signature
X-Ca-Noncestr: BF147C6111BB4F2EC5B4AD1DF14D9110
X-Ca-Timestamp: 1754807077046
{
"result_code": "OK",
"result_msg": "SUCCESS",
"charge": {
"puid": 0,
"out_trade_no": "TEST20250731204928",
"subject": "测试商品",
"body": "测试商品描述",
"channel": "lakshine",
"extra": "{\"test\": true}",
"amount": "1000.000",
"income": "1000.000",
"user_in": "990.000",
"agent_in": "0.000",
"platform_in": "10.000",
"currency": "INR",
"client_ip": "127.0.0.1",
"return_url": "http://127.0.0.1:8080/index/index/index.html",
"notify_url": "http://127.0.0.1:8080/api/notify/index.html",
"user_confirm_status": 0,
"user_pay_no": ""
}
}
注意:商户收到异步通知后,必须验证签名,并返回JSON格式的成功响应表示接收成功。
6.3.1 响应格式
商户处理异步通知后,需要返回以下格式的响应:
// 成功响应
{"result_code":"OK","result_msg":"SUCCESS"}
// 失败响应
{"result_code":"FAIL","result_msg":"SIGN_ERROR"}
10. 接入示例
8.1 PHP示例
<?php
// 统一下单示例
class LakShinePay {
private $privateKey;
private $apiKey;
private $gatewayUrl;
public function __construct($privateKey, $apiKey, $gatewayUrl) {
$this->privateKey = $privateKey;
$this->apiKey = $apiKey;
$this->gatewayUrl = $gatewayUrl;
}
// 生成随机字符串
private function generateNonceStr($length = 32) {
return strtoupper(md5(uniqid(mt_rand(), true)));
}
// 生成时间戳
private function generateTimestamp() {
return time() * 1000; // 毫秒时间戳
}
// RSA签名
private function rsaSign($data) {
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" .
chunk_split($this->privateKey, 64, "\n") .
"-----END RSA PRIVATE KEY-----\n";
$privateKeyResource = openssl_pkey_get_private($privateKey);
if (!$privateKeyResource) {
throw new Exception('私钥格式错误或无效');
}
$signature = '';
if (!openssl_sign($data, $signature, $privateKeyResource, OPENSSL_ALGO_SHA1)) {
throw new Exception('签名生成失败');
}
openssl_free_key($privateKeyResource);
return base64_encode($signature);
}
// 生成签名
private function generateSignature($uri, $queryString, $nonceStr, $timestamp, $requestBody) {
// 构建待签名数据
$signData = utf8_encode($uri) . "\n" .
utf8_encode($queryString) . "\n" .
utf8_encode($nonceStr) . "\n" .
utf8_encode($timestamp) . "\n" .
utf8_encode($requestBody);
// Base64编码
$base64Data = base64_encode($signData);
// RSA签名
return $this->rsaSign($base64Data);
}
// 统一下单
public function unifiedOrder($params) {
$uri = '/pay/unifiedorder';
$queryString = '';
$nonceStr = $this->generateNonceStr();
$timestamp = $this->generateTimestamp();
$requestBody = http_build_query($params);
// 生成签名
$signature = $this->generateSignature($uri, $queryString, $nonceStr, $timestamp, $requestBody);
// 构建请求头
$headers = [
'X-Ca-Auth: ' . $this->apiKey,
'X-Ca-Signature: ' . $signature,
'X-Ca-Noncestr: ' . $nonceStr,
'X-Ca-Timestamp: ' . $timestamp,
'X-Ca-Resturl: ' . $this->gatewayUrl . $uri,
'Content-Type: application/x-www-form-urlencoded',
'Accept: application/json'
];
// 发送请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->gatewayUrl . $uri);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return json_decode($response, true);
}
// 订单查询
public function orderQuery($params) {
$uri = '/pay/orderquery';
$queryString = '';
$nonceStr = $this->generateNonceStr();
$timestamp = $this->generateTimestamp();
$requestBody = http_build_query($params);
// 生成签名
$signature = $this->generateSignature($uri, $queryString, $nonceStr, $timestamp, $requestBody);
// 构建请求头
$headers = [
'X-Ca-Auth: ' . $this->apiKey,
'X-Ca-Signature: ' . $signature,
'X-Ca-Noncestr: ' . $nonceStr,
'X-Ca-Timestamp: ' . $timestamp,
'X-Ca-Resturl: ' . $this->gatewayUrl . $uri,
'Content-Type: application/x-www-form-urlencoded',
'Accept: application/json'
];
// 发送请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->gatewayUrl . $uri);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return json_decode($response, true);
}
// 支付确认
public function confirmPay($params) {
$uri = '/pay/confirmpay';
$requestBody = json_encode($params);
// 构建请求头(该接口不需要签名验证)
$headers = [
'Content-Type: application/json',
'Accept: application/json'
];
// 发送请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->gatewayUrl . $uri);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return json_decode($response, true);
}
// 订单超时查询
public function getOrderTimeout($tradeNo) {
$uri = '/pay/getordertimeout';
$url = $this->gatewayUrl . $uri . '?trade_no=' . urlencode($tradeNo);
// 构建请求头(该接口不需要签名验证)
$headers = [
'Accept: application/json'
];
// 发送请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return json_decode($response, true);
}
}
// 使用示例
$pay = new LakShinePay(
'YOUR_PRIVATE_KEY_HERE', // 商户RSA私钥
'YOUR_API_KEY_HERE', // 商户API Key
'https://api.lakshine.com' // 网关地址
);
$params = [
'mchid' => '123456789',
'out_trade_no' => 'TEST' . date('YmdHis') . rand(1000, 9999),
'amount' => '1000',
'currency' => 'INR',
'subject' => '商品购买',
'body' => '购买说明',
'channel' => 'lakshine',
'client_ip' => '127.0.0.1',
'notify_url' => 'https://your-domain.com/notify',
'return_url' => 'https://your-domain.com/return'
];
$result = $pay->unifiedOrder($params);
if ($result['result_code'] === 'OK' && $result['result_msg'] === 'SUCCESS') {
echo "下单成功,订单信息:" . json_encode($result['charge']);
} else {
echo "下单失败:" . $result['result_msg'];
}
// 订单查询示例
$queryParams = [
'mchid' => '123456789',
'out_trade_no' => 'TEST202501050001',
'channel' => 'lakshine'
];
$queryResult = $pay->orderQuery($queryParams);
if ($queryResult['result_code'] === 'OK' && $queryResult['result_msg'] === 'SUCCESS') {
echo "订单状态:" . $queryResult['charge']['status'];
} else {
echo "查询失败:" . $queryResult['result_msg'];
}
// 支付确认示例
$confirmParams = [
'trade_no' => 'LS202501050001',
'pay_no' => '123456789012'
];
$confirmResult = $pay->confirmPay($confirmParams);
if ($confirmResult['result_code'] === 'OK' && $confirmResult['result_msg'] === 'SUCCESS') {
echo "支付确认成功:" . $confirmResult['message'];
} else {
echo "支付确认失败:" . $confirmResult['result_msg'];
}
// 订单超时查询示例
$timeoutResult = $pay->getOrderTimeout('LS202501050001');
if ($timeoutResult['result_code'] === 'OK' && $timeoutResult['result_msg'] === 'SUCCESS') {
if ($timeoutResult['timeout']) {
echo "订单已超时:" . $timeoutResult['message'];
} else {
echo "订单未超时";
}
} else {
echo "查询失败:" . $timeoutResult['result_msg'];
}
?>
8.2 JavaScript前端示例
// 支付确认接口调用
function confirmPayment(tradeNo, payNo) {
fetch('/pay/confirmpay', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
trade_no: tradeNo,
pay_no: payNo
})
})
.then(response => response.json())
.then(data => {
if (data.result_code === 'OK' && data.result_msg === 'SUCCESS') {
alert('支付确认成功:' + data.message);
// 跳转到成功页面
window.location.href = '/success.html';
} else {
alert('支付确认失败:' + data.result_msg);
}
})
.catch(error => {
console.error('请求失败:', error);
alert('网络错误,请重试');
});
}
// 订单超时查询接口调用
function checkOrderTimeout(tradeNo) {
fetch('/pay/getordertimeout?trade_no=' + encodeURIComponent(tradeNo), {
method: 'GET'
})
.then(response => response.json())
.then(data => {
if (data.result_code === 'OK' && data.result_msg === 'SUCCESS') {
if (data.timeout) {
alert('订单已超时:' + data.message);
// 跳转到超时页面
window.location.href = '/timeout.html';
} else {
console.log('订单未超时,继续等待...');
}
} else {
console.error('查询失败:' + data.result_msg);
}
})
.catch(error => {
console.error('请求失败:', error);
});
}
// 使用示例
// 提交支付凭证
document.getElementById('confirmBtn').addEventListener('click', function() {
const tradeNo = document.getElementById('tradeNo').value;
const payNo = document.getElementById('payNo').value;
if (!tradeNo || !payNo) {
alert('请填写完整信息');
return;
}
confirmPayment(tradeNo, payNo);
});
// 定时检查订单超时状态
const tradeNo = 'LS202501050001';
setInterval(() => {
checkOrderTimeout(tradeNo);
}, 30000); // 每30秒检查一次
8.3 异步通知处理示例
<?php
// 接收异步通知
$input = file_get_contents('php://input');
$notifyData = json_decode($input, true);
// 获取请求头中的签名信息(异步通知不需要X-Ca-Auth认证)
$headers = getallheaders();
$signature = $headers['X-Ca-Signature'] ?? '';
$nonceStr = $headers['X-Ca-Noncestr'] ?? '';
$timestamp = $headers['X-Ca-Timestamp'] ?? '';
// 验证签名
function verifyNotifySignature($nonceStr, $timestamp, $chargeData, $signature, $publicKey) {
// 构建待签名数据:nonce + timestamp + charge_json
$signData = utf8_encode($nonceStr) . "\n" .
utf8_encode($timestamp) . "\n" .
utf8_encode(json_encode($chargeData));
// Base64编码
$base64Data = base64_encode($signData);
// 使用平台公钥验证签名
$publicKey = "-----BEGIN PUBLIC KEY-----\n" .
chunk_split($publicKey, 64, "\n") .
"-----END PUBLIC KEY-----\n";
$publicKeyResource = openssl_pkey_get_public($publicKey);
if (!$publicKeyResource) {
return false;
}
$result = openssl_verify($base64Data, base64_decode($signature), $publicKeyResource, OPENSSL_ALGO_SHA1);
openssl_free_key($publicKeyResource);
return $result === 1;
}
// 平台公钥(需要从平台获取)
$platformPublicKey = 'YOUR_PLATFORM_PUBLIC_KEY_HERE';
// 提取charge数据
$chargeData = $notifyData['charge'] ?? [];
if (verifyNotifySignature($nonceStr, $timestamp, $chargeData, $signature, $platformPublicKey)) {
// 签名验证通过,处理业务逻辑
if ($notifyData['result_code'] === 'OK' && $notifyData['result_msg'] === 'SUCCESS') {
// 支付成功,更新订单状态
updateOrderStatus($chargeData['out_trade_no'], 'paid', $chargeData);
// 记录日志
error_log("支付成功通知: " . json_encode($notifyData));
}
echo '{"result_code":"OK","result_msg":"SUCCESS"}'; // 返回成功标识
} else {
// 签名验证失败
error_log("签名验证失败: " . json_encode($notifyData));
echo '{"result_code":"FAIL","result_msg":"SIGN_ERROR"}';
}
function updateOrderStatus($orderNo, $status, $chargeData) {
// 更新订单状态的业务逻辑
// 这里需要根据您的数据库结构来实现
$pdo = new PDO("mysql:host=localhost;dbname=your_db", "username", "password");
$stmt = $pdo->prepare("UPDATE orders SET status = ?, amount = ?, currency = ? WHERE order_no = ?");
$stmt->execute([$status, $chargeData['amount'], $chargeData['currency'], $orderNo]);
}
?>