This guide describes how to integrate Alipay Web Payments for both Hong Kong and overseas merchants.
AlipayHK does not support the native Alipay checkout page.
For AlipayHK, merchants typically request a QR code / payment URL and embed it in the merchant page (e.g. as a QR code image or via an iframe).
Overview
Alipay Web Payments allow customers to complete a purchase by scanning a QR code (or opening a hosted payment URL). After payment confirmation, funds are deducted from the customer’s wallet and the result is returned to the merchant system.
- Mainland China users pay in CNY; QFPay settles to merchants in the configured settlement currency.
- Hong Kong users pay in HKD.
If return_url is provided, the customer is redirected back to the merchant website after payment.
HTTP Request
Endpoint
POST /trade/v1/payment
Supported Pay Types
| PayType | Description |
|---|
| 801101 | Alipay Web Payment (Settle By Alipay) |
| 801514 | Alipay Web Payment (Settle By QFPay) |
Request Parameters
| Field | Type | Required | Description |
|---|
txamt | Int(11) | Yes | Amount in cents. Suggested > 200 to reduce risk control triggers. |
txcurrcd | String(3) | Yes | Currency (e.g. HKD, CNY). See Currencies. |
pay_type | String(6) | Yes | PayType (see table above). |
out_trade_no | String(128) | Yes | Unique merchant order ID. |
txdtm | String(20) | Yes | Timestamp YYYY-MM-DD HH:mm:ss. |
expired_time | String(3) | No | QR expiry (minutes). 5–120. (MPM only) |
goods_name | String(64) | No | Product name (≤20 chars). Use UTF-8 if Chinese. |
mchid | String(16) | No | Required if provided by QFPay for your store setup. |
udid | String(40) | No | Device ID for reporting. |
return_url | String(512) | No | Redirect URL after successful payment. |
Optional Parameters
| Payment Tag | pay_tag | No | String(16) | Default: ALIPAYHK For Alipay Mainland use: ALIPAYCN |
|---|
Response Parameters
| Field | Type | Description |
|---|
respcd | String(4) | Return code. 0000 = success; 1143/1145 = retry needed; others = failed. |
resperr | String(128) | Error details (if any). |
respmsg | String(128) | General response message. |
syssn | String(40) | QFPay transaction ID. |
out_trade_no | String(128) | Merchant order ID. |
txamt | Int(11) | Amount (cents). |
txdtm | String(20) | Request timestamp. |
sysdtm | String(20) | Server timestamp (used for settlement cutoff). |
pay_type | String(6) | PayType used. |
pay_url | String(512) | Payment URL (render as QR code or embed in iframe). |
Code Examples
Use the language tabs below. Replace the placeholders with your own credentials and values.
# coding=utf-8
import hashlib
import requests
import datetime
environment = "https://test-openapi-hk.qfapi.com"
app_code = "YOUR_APP_CODE"
client_key = "YOUR_CLIENT_KEY"
def make_req_sign(data, key):
keys = sorted(list(data.keys()))
parts = []
for k in keys:
parts.append(f"{k}={data[k]}")
sign_str = ("&".join(parts) + key).encode("utf-8")
return hashlib.md5(sign_str).hexdigest().upper()
current_time = datetime.datetime.now().replace(microsecond=0).strftime("%Y-%m-%d %H:%M:%S")
data = {
"txamt": "10",
"txcurrcd": "HKD",
"pay_type": "801101",
"out_trade_no": "01234567890123",
"txdtm": current_time,
# "mchid": "ZaMVg*****" # include only if provided by QFPay
}
headers = {
"X-QF-APPCODE": app_code,
"X-QF-SIGN": make_req_sign(data, client_key),
}
r = requests.post(environment + "/trade/v1/payment", data=data, headers=headers)
print(r.json())
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class TestMain {
public static void main(String[] args) {
String appcode = "YOUR_APP_CODE";
String key = "YOUR_CLIENT_KEY";
String pay_type = "801101";
String out_trade_no = "01234567890123";
String txdtm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
Map<String, String> params = new HashMap<>();
params.put("pay_type", pay_type);
params.put("out_trade_no", out_trade_no);
params.put("txdtm", txdtm);
params.put("txamt", "10");
params.put("txcurrcd", "HKD");
// params.put("mchid", "ZaMVg*****"); // include only if provided by QFPay
String data = QFPayUtils.getDataString(params);
String md5 = QFPayUtils.getMd5Value(data + key);
String url = "https://test-openapi-hk.qfapi.com";
String resp = Requests.sendPostRequest(url + "/trade/v1/payment", data, appcode, md5);
System.out.println(resp);
}
}
const crypto = require("crypto");
const request = require("request");
const environment = "https://test-openapi-hk.qfapi.com";
const app_code = "YOUR_APP_CODE";
const client_key = "YOUR_CLIENT_KEY";
const txdtm = new Date().toISOString().replace("T", " ").replace(/\..+/, "");
const out_trade_no = String(Math.round(Math.random() * 1000000000));
const payload = {
txamt: "10",
txcurrcd: "HKD",
pay_type: "801101",
out_trade_no,
txdtm
// mchid: "ZaMVg*****" // include only if provided by QFPay
};
const ordered = Object.keys(payload).sort().map(k => `${k}=${payload[k]}`).join("&");
const signString = ordered + client_key;
const sign = crypto.createHash("md5").update(signString).digest("hex").toUpperCase();
request({
uri: environment + "/trade/v1/payment",
headers: {
"X-QF-APPCODE": app_code,
"X-QF-SIGN": sign
},
method: "POST",
form: payload
}, function (error, response, body) {
console.log(body);
});
<?php
function randStr($length) {
$str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$out = '';
for ($i = 0; $i < $length; $i++) {
$out .= $str[rand(0, strlen($str) - 1)];
}
return $out;
}
$url = 'https://test-openapi-hk.qfapi.com';
$api = '/trade/v1/payment';
$app_code = 'YOUR_APP_CODE';
$app_key = 'YOUR_CLIENT_KEY';
$fields = array(
'pay_type' => '801101',
'out_trade_no' => randStr(20),
'txcurrcd' => 'HKD',
'txamt' => '2200',
'txdtm' => date("Y-m-d H:i:s")
// 'mchid' => 'ZaMVg*****' // include only if provided by QFPay
);
ksort($fields);
$pairs = array();
foreach($fields as $k => $v) { $pairs[] = $k . '=' . $v; }
$fields_string = implode('&', $pairs);
$sign = strtoupper(md5($fields_string . $app_key));
$header = array(
'X-QF-APPCODE: ' . $app_code,
'X-QF-SIGN: ' . $sign
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url . $api);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
$output = curl_exec($ch);
curl_close($ch);
echo $output;
?>
Sample Response
{
"sysdtm": "2020-04-13 10:30:34",
"paydtm": "2020-04-13 10:30:34",
"txcurrcd": "HKD",
"respmsg": "",
"pay_type": "801101",
"udid": "qiantai2",
"txdtm": "2020-04-13 10:30:34",
"txamt": "300",
"resperr": "success",
"out_trade_no": "4K35N374II7UJJ8RGIAE45O2CVHGHFF0",
"syssn": "20200413000300020087033882",
"respcd": "0000",
"pay_url": "https://globalmapi.alipay.com/gateway.do?...",
"chnlsn": ""
}
Notes
Render the QR code or iframe using pay_url.
Do not reuse out_trade_no across payments or refunds.
If respcd is 1143 or 1145, retry or query the transaction result using /trade/v1/query.