中东支付网关API快速接入教程
1. 准备工作
在开始接入中东支付网关前,请确保您已完成以下准备:
- 商户账户:已在目标支付平台(如PayTabs、Telr、PayFort等)注册并开通商户账户
- API凭证:获取了Merchant ID和API Key/Secret
- HTTPS支持:您的网站必须支持HTTPS加密连接
- IP白名单:将您的服务器IP添加到支付平台的允许列表中(如需)
2. API基础信息
常用中东支付网关端点
沙箱环境: https://api-sandbox.paytabs.com/v3/
生产环境: https://api.paytabs.com/v3/
常见接口:
POST /payment/request # 创建支付请求
GET /payment/{trans_id}/query # 查询交易状态
POST /payment/{trans_id}/refund # 退款请求
HTTP头信息要求
Authorization: Bearer your_api_key_here
Content-Type: application/json
3. PHP示例代码 – 创建付款请求
<?php
$apiKey = 'YOUR_API_KEY';
$merchantId = 'YOUR_MERCHANT_ID';
$payload = [
"profile_id" => $merchantId,
"tran_type" => "sale",
"tran_class" => "ecom",
"cart_description" => "Order #12345",
"cart_id" => "12345",
"cart_currency" => "AED", // AED, SAR等中东常用货币代码
"cart_amount" => 100.00,
// callback_url用于接收异步通知,return_url用于用户返回商家页面
// (注意这两个URL必须是HTTPS且已备案)
];
// ...省略其他必填字段...
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.paytabs.com/v3/payment/request');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch,CURLOPT_HTTPHEADER,[
'Authorization:Bearer '.$apiKey,
'Content-Type:application/json'
]);
$response = curl_exec($ch);
if(curl_errno($ch)) {
echo 'Error:' . curl_error($ch);}
else{
print_r(json_decode ($response ,true));}
?>
Python示例代码 – Webhook验证签名(Python Flask)
from flask import Flask , request ,jsonify
import hashlib ,hmac
app=Flask(__name__)
SECRET_KEY='your_payment_gateway_secret'
@app.route('/webhook',methods=['POST'])
def webhook():
data=request.json
signature_received=data.get('signature')
del data['signature']
message=str(data).encode('utf8')
key=bytes(SECRET_KEY,'utf8')
digest=hmac.new(key ,
msg=message ,
digestmod=
hashlib.sha256 ).hexdigest()
if hmac.compare_digest(digest,signature_received):
process_payment(data)#处理业务逻辑
return jsonify({'status':'success'}),200
else:
return jsonify({'error':'Invalid signature'}),
401
def process_payment(payload):
order_id=
payload['reference_no']
amount=
float(payload['amount'])
#更新订单状态为已付款...
pass
if __name__=='__main__':
app.run(port=5000)
Java示例代码 -发起付款请求
中东支付网关API快速接入教程(续)
4. Java示例代码 – 发起付款请求
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.json.JSONObject;
public class MiddleEastPaymentGateway {
private static final String API_URL = "https://api.paytabs.com/v3/payment/request";
private static final String API_KEY = "your_api_key_here";
public static void main(String[] args) {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost postRequest = new HttpPost(API_URL);
// 设置请求头
postRequest.setHeader("Authorization", "Bearer " + API_KEY);
postRequest.setHeader("Content-Type", "application/json");
// 构建请求体
JSONObject paymentData = new JSONObject();
paymentData.put("profile_id", "YOUR_MERCHANT_ID");
paymentData.put("tran_type", "sale");
paymentData.put("tran_class", "ecom");
paymentData.put("cart_id", UUID.randomUUID().toString());
paymentData.put("cart_currency", "AED"); // UAE Dirham
paymentData.put(
"customer_details",
new JSONObject()
.put(
"name",
"John Doe")
.put(
"email",
"[email protected]")
.put(
"phone",
"+971501234567")//阿联酋号码格式示例
);
StringEntity requestEntity =
new StringEntity(paymentData.toString());
postRequest.setEntity(requestEntity);
try (
CloseableHttpResponse response=
httpClient.execute(postRequest)
){
int statusCode=response.getStatusLine().getStatusCode();
if(statusCode==200||statusCode==201){
System.out.println(IOUtils.toString(response.getEntity().getContent(),StandardCharsets.UTF_8));
}else{
System.err.println(IOUtils.toString(response.getE ntity().getContent(),StandardCharsets.UTF_8));
}
}catch(Exception e){e.printStackTrace();}
}catch(Exception ex){ex.printStackTrace();}
}
5.Node.js示例-处理异步通知
const express=require('express');
const crypto=require('crypto');
const app=express();
app.use(express.json());
const WEBHOOK_SECRET='your_secret_key';
app.post('/payment/webhook',async(req,res)=>{
try{
//验证签名
const receivedSignature=
req.headers['x-paytabs-signature'];
const payloadString=
JSON.stringify(req.body);
const expectedSignature=crypto.createHmac('sha256',
WEBHOOK_SECRET).update(payloadString).digest('hex');
if(receivedSignature!==expectedSignature){
return res.status(401).send({error:'Invalid signature'});
}
/*成功验证后处理业务逻辑*/
switch(req.body.payment_result.response_status){
case'A':
console.log(`订单${req.body.cart_id}支付成功`);
await updateOrderStatus(req.body.cart_id,'paid');break;case'V':console.log(`订单${req.body.cart_id}已过期`);break;default:console.warn(`未知状态:${req.body.payment_result.response_status}`);}
res.status(200).end();
}catch(err){console.error(err);res.status500.send({error:'Internal server error'});}});
async function updateOrderStatus(orderId,status){
/*实现您的订单状态更新逻辑*/}
app.listen3000()=>{console.logWebhook listener running on port3000)});
6.CURL命令测试查询交易状态
curl-X GET \
-H Authorization:Bearer YOUR_API_KEY \
-H Content-Type:application/json \ https://api-sandbox.paytabs.com/v3/payment/TRANS123456789/query
响应示例:
{
tran_ref : TRN12345 ,
cart id : ORD1001 ,
tran type : sale ,
amount :150.00,
currency:AED,
payment result:{
response message:Authorised,
response code:00}}
7.SwaggerUI集成建议
大多数中东支付网关提供Swagger文档,建议:
1.下载官方提供的swagger.json文件2导入到Postman或Swagger Editor中3生成对应语言的SDK代码片段4直接用于项目开发
例如PayFort的OpenAPI文档通常位于:https://docs.payfort.com/api
8常见错误代码及解决方案
错误码 | 含义 | 解决方法 |
---|---|---|
40078 | 无效货币 | 确保使用支持的货币如AED/SAR/KWD等 |
50066 | IP未授权 | 在商户后台添加服务器IP白名单 |
40102 | 签名错误 | 检查HMAC-SHA256算法实现是否正确 |
30134 | 重复订单号 | 更换新的唯一cart_id值 |
特别提示:沙特地区需额外注意:
- VAT税率字段必须正确传递(通常15%)
- customer_name需包含first name和last name两个字段
中东支付网关API深度集成指南(续)
9. 高级功能实现
9.1 Token化支付(信用卡存储)
# Python示例 - 创建token
import requests
def create_payment_token(card_details):
url = "https://api.paytabs.com/v3/token/create"
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
payload = {
"profile_id": MERCHANT_ID,
"customer_email": card_details['email'],
'payment_info': {
'card_number': card_details['card_number'],
'expiry_month': card_details['exp_month'],
'expiry_year': card_details['exp_year'],
'cvv': card_details['cvv']
}
}
response = requests.post(url, json=payload, headers=headers)
return response.json()['token']
# 使用token发起免密支付
def charge_with_token(token, amount):
url = "https://api.paytabs.com/v3/payment/request"
9.2 Apple Pay/Google Pay集成
// JavaScript前端处理Apple Pay请求示例
async function initiateApplePay() {
const paymentRequest = {
countryCode: 'AE',
currencyCode:
'AED',
merchantCapabilities: ['supports3DS'],
supportedNetworks: ['visa',
'masterCard',
'mada'], // mada是沙特本地卡组织
total: { label:'订单总额',amount:'100.00'}
};
const session=new ApplePaySession(1,paymentRequest);
session.onvalidatemerchant=(event)=>{
fetch('/validate-merchant',{
method:'POST',
body:
JSON.stringify({validationUrl:
event.validationUrl})
}).then(...);
};
}
10.SDK最佳实践
官方SDK推荐:
自定义封装建议:
// Java通用支付客户端封装示例
public abstract class MiddleEastPaymentClient {
protected final String apiKey;
protected final String merchantId;
public MiddleEastPaymentClient(String apiKey,String merchantId){
this.apiKey=Objects.requireNonNull(apiKey);
this.merchantId=Objects.
requireNonNull(merchantId);}
public abstract PaymentResponse initiatePayment(PaymentRequest request)throws PaymentException;
protected HttpHeaders buildAuthHeaders(){
HttpHeaders headers=new HttpHeaders();
headers.set("Authorization","Bearer "+apiKey);
headers.setContentType(
MediaType.
APPLICATION_JSON);
return headers;}
// ...其他通用方法...
}
11.PCI DSS合规要点
中东地区对支付安全要求严格,必须注意:
1.敏感数据加密
- PAN号码必须使用AES-256加密存储
- CVV不能存储,只能即时验证
2.日志脱敏处理
// PHP日志过滤示例
function sanitizeLog(array $data):array{
$sensitiveKeys=['card_num','cvv','password'];
foreach($sensitiveKeys as $key){
if(isset($data[$key])){
$data[$key]=str_repeat('*'strlen($data[$key]));
}}
return $data;}
3.定期安全审计
- Saudi SAMA框架要求每季度进行渗透测试
- UAE需通过ADHICS认证
12.本地化特殊需求
国家 | 特有要求 |
---|---|
沙特 | 必需支持mada卡&STCPay |
阿联酋 | 需显示NOL交通卡选项 |
巴林 | BenefitPay二维码强制接入 |
阿拉伯语错误消息对照表:
"Invalid CVV":"رمز التحقق غير صحيح",
"Expired Card":"انتهت صلاحية البطاقة",
"Insufficient Funds":"رصيد غير كاف"
13.Webhook调试技巧
使用ngrok进行本地测试:
ngrok http3000--region=me #使用中东服务器获得更稳定连接
curl-X POST\
-H Content-Type:application/json\
-d@test_payload.json\ https://your-subdomain.me.
ngrok.io/webhook
# test_payload.json应包含完整的模拟通知数据+签名头(x-signature)
如需继续了解特定国家或功能的深入实现细节,请告知具体方向。