NAV Navbar
Text Python Java Node.js PHP

Introduction

Welcome to the official QF Pay open API documentation. To get started, please review the Developer Instructions below.

There are language bindings available in Python, Java, Node.js and PHP! You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right corner.

If you would like to quickly test the payment function in Postman we provide a collection that includes a pre-request script to generate the signature, download the file from here.

Developer Instructions

In order to use the QF Pay open API, you must have active API credentials, including an app_code and client_key. In case of technical issues please contact technical.support@qfpay.com.

There are seperate environments available for application testing and development as well as production.

Please note that transactions conducted in the sandbox environment will not have settlement. Therefore, make sure to test with small amounts and process refunds using the API refund endpoint or Merchant APP on the same day as the original transaction day.

Each merchant will be provided with a set of app code and key with or without mchid. Merchants with multiple branches will usually be supplied with app code, key and mchid. The hashed mchid is used to identify shops and outlets. Otherwise, only app code and key will be given.

Encoding Description

All return parameters from API are in UTF-8 code unless otherwise noted.

Environments

API Environments

The table below depicts base URLs for each country/ region. There is a general sandbox available to everybody, and country/ region specifiy test environments.

Environment Name Test URL Prod. URL
Sandbox (Only for credit card simulations) https://openapi-int.qfapi.com
Live Test https://openapi-test.qfpay.com
China Mainland https://openapi-test.qfpay.com https://openapi.qfpay.com
Hong Kong https://test-openapi-hk.qfapi.com https://openapi-hk.qfapi.com
Japan https://openapi-jp.qfapi.com
Thailand https://test-openapi-th.qfapi.com https://openapi-th.qfapi.com
Dubai https://test-openapi-db.qfapi.com https://openapi-db.qfapi.com
Singapore, Malaysia, Canada, Philippines https://test-openapi-sg.qfapi.com https://openapi-sg.qfapi.com
Indonesia https://test-openapi-id.qfapi.com https://openapi-id.qfapi.com
Europe https://test-openapi-eur.qfapi.com https://openapi-eur.qfapi.com

Signature Generation

For code instructions select Python, Java, Node.js or PHP with the tabs above.
# Create signature
def make_req_sign(data, key):
    keys = list(data.keys())
    keys.sort()
    p = []
    for k in keys: 
        v = data[k]
        p.append('%s=%s'%(k,v))
    unsign_str = ('&'.join(p) + key).encode("utf-8")
    s = hashlib.md5(unsign_str).hexdigest()
    return s.upper()


# Body payload
txamt = '10' # In USD,EUR,etc. Cent
txcurrcd = 'EUR'
pay_type = '800101' # Alipay CPM = 800108 , MPM = 800101
auth_code='283854702356157409' #CPM only
out_trade_no = random_string
txdtm = current_time
goods_name = 'test1'   
auth_code = '280438849930815813'
key = client_key
mchid = 'ZaMVg*****' # ID is provided during merchant onboarding


#data ={'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'goods_name': goods_name, 'udid': udid, 'auth_code': auth_code, 'mchid': mchid}
data ={'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'goods_name': goods_name, 'mchid': mchid}


r = requests.post(environment+"/trade/v1/payment",data=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, key)})

print(make_req_sign(data, key))

/* 
This class is the utility for QFPay Payment API. 
Note:This is just an example.
getMd5Value:
After do the string manipulation, like:abc=value&bad=value&bcd=valueKey
This method generates MD5 signature using hexadecimal format.
getDataString:
This method pass in with the map, and generate the string like:abc=value&bad=value&bcd=value.
*/
public class QFPayUtils {

    public static String getMd5Value(String input) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
            byte[] array = md.digest(input.getBytes( "UTF-8" ));
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < array.length; i++) {
                sb.append( String.format( "%02x", array[i]));
            }
            return sb.toString().toUpperCase();
        } catch ( NoSuchAlgorithmException | UnsupportedEncodingException e) {
            return null;
        }
    }

    public static <T> String getDataString(Map resultMap) {
        Map<String, String> map = new TreeMap<String, String>(
                new Comparator<String>() {
                    public int compare(String obj1, String obj2) {
                        return obj1.compareTo(obj2);
                    }
                });

        Iterator<Map.Entry<String, String>> it = resultMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> entry = it.next();
            map.put(entry.getKey(), entry.getValue());
        }

        StringBuilder sb = new StringBuilder();
        it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> entry = it.next();
            sb.append(entry.getKey()+"="+entry.getValue()+"&");
        }
        return sb.deleteCharAt(sb.length() - 1).toString();
    }


}
// Enter Client Credentials
const environment = 'https://openapi-test.qfpay.com'
const app_code = 'D5589D2A1F2E42A9A60C37**********'
const client_key = '0E32A59A8B454940A2FF39*********'

// Generate Timestamp
var dateTime = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
console.log(dateTime)

// Body Payload
const key = client_key
var tradenumber = String(Math.round(Math.random() * 1000000000))
console.log(tradenumber)

var payload = {
'txamt': '10', // In USD,EUR,etc. Cent
'txcurrcd': 'EUR',
'pay_type': '800101', // Alipay CPM = 800108 , MPM = 800101
'out_trade_no': tradenumber,
'txdtm': dateTime,
'mchid': 'ZaMVg*****'
};

// Signature Generation
const ordered = {};
Object.keys(payload).sort().forEach(function(key) {
  ordered[key] = payload[key] });
console.log(ordered)

var str = [];
for (var p in ordered)
if (ordered.hasOwnProperty(p)) {
str.push((p) + "=" + (ordered[p]));
}
var string = str.join("&")+client_key;
console.log(string)

const crypto = require('crypto')
var hashed = crypto.createHash('md5').update(string).digest('hex')
console.log(hashed)
<?php
ob_start();
  function GetRandStr($length){
  $str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $len=strlen($str)-1;
  $randstr='';
  for($i=0;$i<$length;$i++){
  $num=mt_rand(0,$len);
  $randstr .= $str[$num];
  }
  return $randstr;
  }
     $url = 'https://test-openapi-eur.qfapi.com';
     $api_type = '/trade/v1/payment';
     $pay_type = '800101';
     //$mchid = "MNxMp11FV35qQN"; //Only agents must provide this parameter
     $app_code = 'FF2FF74F2F2E42769A4A73*********'; //API credentials are provided by QFPay
     $app_key = '7BE791E0FD2E48E6926043B*********'; //API credentials are provided by QFPay
     $now_time = date("Y-m-d H:i:s"); //Get the current date-time  

     $fields_string = '';
     $fields = array(
       //'mchid' => urlencode($mchid),
     'pay_type' => urlencode($pay_type),
       'out_trade_no' => urlencode(GetRandStr(20)),
     'txcurrcd' => urlencode('EUR'),
       'txamt' => urlencode(2200),
       'txdtm' => $now_time
    );
    ksort($fields); //Sort parameters in ascending order from A to Z
    print_r($fields);

    foreach($fields as $key=>$value) { 
    $fields_string .= $key.'='.$value.'&' ;
  }
  $fields_string = substr($fields_string , 0 , strlen($fields_string) - 1);

  $sign = strtoupper(md5($fields_string . $app_key));

  ob_end_flush();
?>

The above command returns JSON structured like this:

{
"B3B251B202801388BE4AC8E5537B81B1"
}

Step 1: Sort all parameters in ascending order according to parameter names

Parameter list: abc=value1 bcd=value2 bad=value3 Sort result: abc=value1 bad=value3 bcd=value2

Step 2: Connect all parameters with ‘&’,and get the string to be signed

abc=value1&bad=value3&bcd=value2

Step 3: Combine the string with client_key from QFPay.

abc=value1&bad=value3&bcd=value2Key

Step 4: Sign the string from step 3 with MD5 or SHA256. We recommend to use SHA256.

MD5(abc=value1&bad=value3&bcd=value2Key) HASH(“SHA256”, abc=value1&bad=value3&bcd=value2Key)

Step 5: Request API with the signature

Save the signature in the http header field X-QF-SIGN unless otherwise specified in this document.

Request Description

Field Description
Character UTF-8
Method POST/ GET (Depends on individual API function)
Content-type application/x-www-form-urlencoded

Required Parameter Settings in HTTP Header to Request the API

Field Mandatory Description
X-QF-APPCODE Yes App code assigned to the merchant
X-QF-SIGN Yes Signature generated according to the signature formulation method described above
X-QF-SIGNTYPE No Signature algorithm used to generate the signature. If SHA256 is used, the developer must pass the value as SHA256. The default value is MD5 in case this field is not passed to the API.

Payments

Payment Codes

PayType Table

Code Description
800008 Consumer Present QR Code Mode (CPM) for WeChat, Alipay, UNIONPAY Quick Pass
800101 Alipay Merchant Presented QR Code Payment in store (MPM) (Overseas Merchants)
800108 Alipay Consumer Presented QR Code Payment (CPM) (Overseas & HK Merchants)
801101 Alipay Online WEB (in browser Chrome etc.) Payment (Overseas Merchants) **
801107 Alipay Online WAP (in mobile browser Chrome etc.) Payment (Overseas Merchants)
801110 Alipay in-APP Payments (Overseas Merchants)
800107 Alipay Service Window H5 Payment (in Alipay APP H5 payments)
801501 Alipay Merchant Presented QR Code (MPM) Payment (HK Merchants)
801510 Alipay In-App Payment (HK Merchants)
801512 Alipay Online WAP Payment (HK Merchants)
801514 Alipay Online WEB Payment (HK Merchants)
800201 WeChat Merchant Presented QR Code Payment (MPM) (Overseas & HK Merchants)
800208 WeChat Consumer Presented QR Code Payment (CPM) (Overseas & HK Merchants)
800207 WeChat JSAPI Payment - WeChat Official Account Payment (in Wechat App)(Overseas & HK Merchants)
800212 WeChat H5 Payment (In mobile browser)
800210 WeChat in-APP Payment (Overseas & HK Merchants)
800213 WeChat Mini-Program Payment (Overseas & HK Merchants)
801008 WeChat Pay HK Consumer Presented QR Code Payment (CPM) (Direct Settlement, HK Merchants)
801010 WeChat Pay HK In-App Payment (Direct Settlement, HK Merchants)
805801 PayMe Merchant Presented QR Code Payment in store (MPM) (HK Merchants)
805808 PayMe Consumer Presented QR Code Payment (CPM) (HK Merchants)
805814 PayMe Online WEB (in browser Chrome etc.) Payment (HK Merchants)
805812 PayMe Online WAP (in mobile browser Chrome etc.) Payment (HK Merchants)
800701 UNIONPAY Quick Pass Merchant Presented QR Code Payment (MPM)
800708 UNIONPAY Quick Pass Consumer Presented QR Code Payment (CPM)
800712 UNIONPAY WAP Payment (HK Merchants)
800714 UNIONPAY PC-Web Payment (HK Merchants)
800710 UNIONPAY In-App Payment (HK Merchants)
801208 LINEPAY dynamic QRC Payment - Consumer Present Mode (CPM) (TH Merchants)
801301 LINEPAY Online Payment (TH Merchants)
801408 AIRPAY dynamic QRC Payment - Consumer Present Mode (CPM) (TH Merchants)
801701 NETSPAY Merchant Presented QR Code Payment (MPM)
801801 Alipay Pre-Authorization dynamic QRC Payment - Consumer Present Mode (CPM)
801808 Alipay Pre-Authorization dynamic QRC Payment - Merchant Present Mode (MPM)
801810 Alipay Pre-Authorization in-APP Payment
801814 Alipay Pre-Authorization Online Payment
801908 Origami Consumer Presented QR Code Payment (CPM)
802001 FPS Merchant Presented QR Code Payment (MPM) (HK Merchants)***
802201 AIRPAY Online Payment (TH Merchants)
802301 PayNow Merchant Presented QR Code Payment (MPM) (SG Merchants)***
802901 PromptPay dynamic QRC Payment - Merchant Present Mode (MPM) (TH Merchants)***
803001 eWallet dynamic QRC Payment - Merchant Present Mode (MPM)
803008 eWallet dynamic QRC Payment - Consumer Present Mode (CPM)
803101 VIA dynamic QRC Payment - Merchant Present Mode (MPM) (JP and HK Merchants)
803108 VIA dynamic QRC Payment - Consumer Present Mode (CPM) (JP and HK Merchants)
803208 Touch 'n Go (TNG) dynamic QRC Payment - Consumer Present Mode (CPM) (MY Merchants)
803214 Touch 'n Go (TNG) Online Payment (MY Merchants)**
803301 Razer dynamic QRC Payment - Merchant Present Mode (MPM) (MY Merchants)
803308 Razer dynamic QRC Payment - Consumer Present Mode (CPM) (MY Merchants)
803314 Razer Online Payment ** (MY Merchants)
803701 Octopus dynamic QRC Payment - Merchant Present Mode (MPM) (HK Merchants)
803801 Dash dynamic QRC Payment - Merchant Present Mode (MPM) (SG Merchants)
803808 Dash dynamic QRC Payment - Consumer Present Mode (CPM) (SG Merchants)
804001 Boost dynamic QRC Payment - Merchant Present Mode (MPM) (MY Merchants)
804008 Boost dynamic QRC Payment - Consumer Present Mode (CPM) (MY Merchants)
804014 Boost Online Payment (MY Merchants)**
804101 Maybank dynamic QRC Payment - Merchant Present Mode (MPM) (MY Merchants)
804108 Maybank dynamic QRC Payment - Consumer Present Mode (CPM) (MY Merchants)
804114 Maybank Online Payment (MY Merchants)**
804201 GrabPay dynamic QRC Payment - Merchant Present Mode (MPM) (MY and SG Merchants)
804208 GrabPay dynamic QRC Payment - Consumer Present Mode (CPM) (MY Merchants)
804214 GrabPay Online Payment (MY Merchant)** (SG Merchants)*
805208 TrueMoney dynamic QRC Payment - Consumer Present Mode (CPM) (TH Merchants)
805401 ThaiQR dynamic QRC Payment - Merchant Present Mode (MPM) (SG and MY Merchants)***
805508 Credit Card: first_data Quick Payment Mode (HK Merchant)
805514 Credit Card: first_data Security Verification Payment Mode (HK Merchants)
802801 Visa / Mastercard Online Payments
802808 Visa / Mastercard Offline Payments
805601 GoPay dynamic QRC Payment - Merchant Present Mode (MPM)***
805612 GoPay WAP Payment***
806527 ApplePay Online Payments
806708 UnionPay Card Offline Payments
806808 American Express Card Offline Payments

Currencies

The below listed currencies are currently available in our payment network. Please consult technical.support@qfpay.com to verify that your API credentials and selected pay_type support your desired currency.

Code Description
AED Arab Emirates Dirham
CNY Chinese Yuan
EUR Euro
HKD Hong Kong Dollar
IDR Indonesian Rupiah
JPY Japanese Yen
MMK Myanmar Kyat
MYR Malaysian Ringgit
SGD Singapore Dollar
THB Thai Baht
USD United States Dollar
CAD Canadian Dollar
AUD Australian Dollar

API Endpoint for Payments

Request Header:

{
  Content-Type: application/x-www-form-urlencoded;
  X-QF-APPCODE: D5589D2A1F2E42A9A60C37**********
  X-QF-SIGN: 6FB43AC29175B4602FF95F8332028F19
}

Request Body:

{
  mchid=ZaMVg*****&out_trade_no=01234567890123&pay_type=800101&txamt=10&txcurrcd=EUR&txdtm=2019-12-25 14:21:28
}

#coding=utf8
import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, hashlib
import requests
import datetime
import string

# Enter Client Credentials
environment = 'https://openapi-test.qfpay.com'
app_code = 'D5589D2A1F2E42A9A60C37*********'
client_key = '0E32A59A8B454940A2FF39**********'


# Create parameter values for data payload
current_time = datetime.datetime.now().replace(microsecond=0)                                

print(current_time)

# Create signature
def make_req_sign(data, key):
    keys = list(data.keys())
    keys.sort()
    p = []
    for k in keys: 
        v = data[k]
        p.append('%s=%s'%(k,v))
    unsign_str = ('&'.join(p) + key).encode("utf-8")
    s = hashlib.md5(unsign_str).hexdigest()
    return s.upper()


# Body payload
txamt = '10' #In USD,EUR,etc. Cent
txcurrcd = 'EUR'
pay_type = '800101' # Alipay CPM = 800108 , MPM = 800101
auth_code='283854702356157409' #CPM only
out_trade_no = '01234567890123'
txdtm = current_time
goods_name = 'test1'   
auth_code = '280438849930815813'
mchid = 'ZaMVg*****'
notify_url = 'https://xxx.com/notify/success'
key = client_key


#data ={'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'goods_name': goods_name, 'udid': udid, 'auth_code': auth_code, 'mchid': mchid, 'notify_url': notify_url}
data ={'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'mchid': mchid}

r = requests.post(environment+"/trade/v1/payment",data=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, key)})

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="D5589D2A1F2E42A9A60C37*********";
        String key="0E32A59A8B454940A2FF39*********";
        String mchid="ZaMVg*****";

        String pay_type="800101";
        String out_trade_no= "01234567890123";
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date=df.format(new Date());
        String txdtm=date;
        String txamt="10";
        String txcurrcd="EUR";

        Map<String, String> unsortMap = new HashMap<>();
        unsortMap.put("mchid", mchid);
        unsortMap.put("pay_type", pay_type);
        unsortMap.put("out_trade_no", out_trade_no);
        unsortMap.put("txdtm", txdtm);
        unsortMap.put("txamt", txamt);
        unsortMap.put("txcurrcd", txcurrcd);
        //unsortMap.put("product_name", product_name);
        //unsortMap.put("valid_time", "300");

        String data=QFPayUtils.getDataString(unsortMap);
        System.out.println("Data:\n"+data+key);
        String md5Sum=QFPayUtils.getMd5Value(data+key);
        System.out.println("Md5 Value:\n"+md5Sum);

        String url="https://openapi-test.qfpay.com";
        String resp= Requests.sendPostRequest(url+"/trade/v1/payment", data, appcode,key);
        System.out.println(resp);
    }
}
// Enter Client Credentials
const environment = 'https://openapi-test.qfpay.com'
const app_code = 'D5589D2A1F2E42A9A60C37*********'
const client_key = '0E32A59A8B454940A2FF39*********'

// Generate Timestamp
var dateTime = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
console.log(dateTime)

// Body Payload
const key = client_key
var tradenumber = String(Math.round(Math.random() * 1000000000))
console.log(tradenumber)

var payload = {
'txamt': '10', // In USD,EUR,etc. Cent
'txcurrcd': 'EUR',
'pay_type': '800101', // Alipay CPM = 800108 , MPM = 800101
'out_trade_no': tradenumber,
'txdtm': dateTime,
'mchid': 'ZaMVg*****'
};

// Signature Generation
const ordered = {};
Object.keys(payload).sort().forEach(function(key) {
  ordered[key] = payload[key] });
console.log(ordered)

var str = [];
for (var p in ordered)
if (ordered.hasOwnProperty(p)) {
str.push((p) + "=" + (ordered[p]));
}
var string = str.join("&")+client_key;
console.log(string)

const crypto = require('crypto')
var hashed = crypto.createHash('md5').update(string).digest('hex')
console.log(hashed)


// API Request
var request = require("request");
request({
  uri: environment+"/trade/v1/payment",
  headers: {
    'X-QF-APPCODE': app_code,
    'X-QF-SIGN': hashed
  },
  method: "POST",
  form: payload,
  }, 
  function(error, response, body) {
  console.log(body);
});
<?php
ob_start();
  function GetRandStr($length){
  $str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $len=strlen($str)-1;
  $randstr='';
  for($i=0;$i<$length;$i++){
  $num=mt_rand(0,$len);
  $randstr .= $str[$num];
  }
  return $randstr;
  }

     $url = 'https://test-openapi-eur.qfapi.com';
     $api_type = '/trade/v1/payment';
     $pay_type = '800101';
     //$mchid = "MNxMp11FV35qQN"; //Only agents must provide this parameter
     $app_code = 'FF2FF74F2F2E42769A4A73*********'; //API credentials are provided by QFPay
     $app_key = '7BE791E0FD2E48E6926043B*********'; //API credentials are provided by QFPay
     $now_time = date("Y-m-d H:i:s"); //Get current date-time

     $fields_string = '';
     $fields = array(
        //'mchid' => urlencode($mchid),
      'pay_type' => urlencode($pay_type),
        'out_trade_no' => urlencode(GetRandStr(20)),
      'txcurrcd' => urlencode('EUR'),
        'txamt' => urlencode(2200),
        'txdtm' => $now_time
    );
    ksort($fields); //Ascending dictionary sorting A-Z
    print_r($fields);

    foreach($fields as $key=>$value) { 
    $fields_string .= $key.'='.$value.'&' ;
  }
  $fields_string = substr($fields_string , 0 , strlen($fields_string) - 1);

  $sign = strtoupper(md5($fields_string . $app_key));

  //// Header ////
  $header = array();
  $header[] = 'X-QF-APPCODE: ' . $app_code;
  $header[] = 'X-QF-SIGN: ' . $sign;

  //Post Data
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url . $api_type);
  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);    

  $final_data = json_decode($output, true);
  print_r($final_data);

ob_end_flush();
?>

The above command returns JSON structured like this:

{
    "txdtm": "2019-12-25 14:21:28",
    "qrcode": "https://qr.alipay.com/bax01781r3pu4fjaqazt4091",
    "pay_type": "800101",
    "resperr": "success",
    "out_trade_no": "01234567890123",
    "syssn": "20191225000200020060996533",
    "sysdtm": "2019-12-25 14:22:37",
    "paydtm": "2019-12-25 14:22:37",
    "txcurrcd": "EUR",
    "respmsg": "",
    "cardcd": "",
    "udid": "qiantai2",
    "txamt": "10",
    "respcd": "0000",
    "chnlsn": ""
}

If you would like to quickly test the payment function in Postman we provide a collection that includes a pre-request script to generate the signature, download the file from here: Payment Request in Postman

HTTP Request

POST ../trade/v1/payment

Listed below are the most common parameters for the payment endpoint. Please refer to the payment scenario applicable to you for additional parameters.

Public Payment Request Parameters

Parameter name Parameter code Mandatory Type Description
Payment amount txamt Yes Int(11) Amount of the transaction. Unit in cents (i.e. 100 = $1)
Currency txcurrcd Yes String(3) Transaction currency. View the Currencies table for a complete list of available currencies
Payment type pay_type Yes String(6) Please refer to the section Payment Codes for a complete list of payment types
API Order Number out_trade_no Yes String(128) External transaction number / Merchant platform transaction number: This parameter must be unique for each payment and refund request under the same merchant account in the system.
Request transaction time txdtm Yes String(20) Transaction time format:
YYYY-MM-DD hh:mm:ss
Authorization Code auth_code Yes
(CPM only)
String(128) Specifies the authorization code for scanning a barcode/QR Code. The auth_code returned is unique in each authorization. Each auth_code can be used only once and will automatically expire in one day. For testing CPM with Alipay and WeChat Pay the auth_code can be extracted with any QRC reader or manually found in the consumer wallet below the barcode.
Order expiration time expired_time No
(MPM only)
String(3) QRC expiration time in unit minutes. The default expiration time is 30 minutes. The parameter can manually be adjusted to a minimum of 5 minutes, and up to a maximum of 120 minutes.
Available for:
800201 - WeChat scan code
800101 - Alipay scan code
801512 - Alipay Hong Kong WAP payment
801501 - Alipay Hong Kong scan code
801107 - Alipay overseas WAP payment
801101 - Alipay overseas scan code
801010 - WeChat Hong Kong APP
801510 - Alipay Hong Kong APP
Product name identification goods_name No String(64) Goods Name / Marking: Cannot exceed 20 alphanumeric or contain special characters. Cannot be empty for app payment. Parameter needs to be UTF-8 encoded if it is written in Chinese characters.
QF Pay merchant number mchid No String(16) May or may not be given to merchant. If MCHID is given, it is mandatory to provide the MCHID .On the contrary, if MCHID is not provided, merchants shall not pass in the MCHID parameter in the API request.
Time zone txzone No String(5) Transaction Time zone: Record of the transaction in local time, default time zone is Beijing time UTC+8 (+0800).
Device ID udid No String(40) Unique transaction device ID. Is displayed on the merchant portal.
Asynchronous Notification URL notify_url No String(256) Asynchronous notification URL

Public Payment Response Parameters

Parameter name Parameter code Type Description
Payment type pay_type String(6) Please refer to the section Payment Codes for a complete list of payment types
System transaction time sysdtm String(20) Format:YYYY-MM-DD hh:mm:ss
This parameter value is used as the cut-off time for settlements.
Request transaction time txdtm String(20) Format:YYYY-MM-DD hh:mm:ss
Response message resperr String(128)
Payment amount txamt Int(11)
Other message information respmsg String(128)
External transaction number out_trade_no String(128) External transaction number
QFPay transaction number syssn String(40)
Wallet/Channel transaction number chnlsn String
Return code respcd String(4) 0000 = Request successful.
1143/1145 = merchants are required to continue to query the transaction result.
All other return codes indicate transaction failure. Please refer to the page Transaction Status Codes for a complete list of response codes.

Transaction Status Codes

Return code Description
0000 Transaction successful
1100 System under maintenance (1100)
1101 Reversal error (1101)
1102 Duplicate request (1102)
1103 Request format error (1103)
1104 Request parameter error (1104)
1105 Device not activated (1105)
1106 Invalid device (1106)
1107 Device not allowed (1107)
1108 Signature error (1108)
1125 Transaction has been refunded already (1125)
1136 The transaction does not exist or is not operational (1136)
1142 Order already closed (1142)
1143 The order has not been paid for, the password is currently being entered (1143)
1145 Please wait while processing (1145)
1147 Wechat pay transaction error (1147)
1150 Your billing method is T0 and does not support canceling transactions. (1150)
1155 Refund request denied (1155)
1181 Order expired (1181)
1201 Insufficient balance, please use a different payment method (1201)
1202 Incorrect or expired payment code, please show the correct payment code or refresh the payment code and retry (1202)
1203 Merchant account error, confirm that the payment account is configured correctly (1203)
1204 Bank error, confirm that the payment wallet is functionable (1204)
1205 The transaction failed. Please try again later (1205)
1212 Please use the UnionPay overseas payment code (1212)
1241 The store does not exist or the status is incorrect. Do not conduct payments (1241)
1242 The store has not been configured correctly, unable to conduct payments (1242)
1243 The store has been disabled. Do not conduct payments, contact the owner to confirm (1243)
1250 The transaction is forbidden. For more information please contact QFPay Customer Service Team (1250)
1251 The store has not been configured correctly, we are currently working to fix this problem (1251)
1252 System error when making the order request (1252)
1254 A problem occured. We are currently resolving the issue (1254)
1260 The order has already been paid for, please confirm the transaction result before conducting more transactions (1260)
1261 The order has not been paid for, please confirm the transaction result before conducting more transactions (1261)
1262 The order has been refunded, please confirm the order status before conducting more transactions (1262)
1263 The order has been cancelled, please confirm the order status before conducting more transactions (1263)
1264 The order has been closed, please confirm the order status before conducting more transactions (1264)
1265 The transaction cannot be refunded. Refunds for transactions between 11:30pm to 0:30am and special promotions cannot be processed. (1265)
1266 The transaction amount is wrong, please confirm the order status (1266)
1267 The order information does not match, please confirm the order status (1267)
1268 The order does not exist, please confirm the order status (1268)
1269 Today's unsettled transaction amount is insufficient. Refunds cannot be processed. Please confirm that the balance is sufficient (1269)
1270 This currency does not support partial refunds (1270)
1271 The selected transaction does not support partial refunds (1271)
1272 The refund amount is greater than the maximum amount that can be refunded for the original transaction (1272)
1294 The transaction may be non-compliant and has been prohibited by the bank (1294)
1295 The connection is slow, waiting for a network response (1295)
1296 The connection is slow, waiting for a network response. Please try again later or use other payment methods (1296)
1297 The banking system is busy. Please try again later or use other payment methods (1297)
1298 The connection is slow, waiting for a network response. In case you have already paid, do not repeat the payment. Please confirm the result later (1298)
2005 The customer payment code is incorrect or has expired, please refresh and restart the transaction process (2005)
2011 Transaction serial number repeats (2011)

Merchant Present Mode (MPM)


MPM process-flow

MPM API Request

Request Header:

{
  Content-Type: application/x-www-form-urlencoded; 
  charset=UTF-8,
  Content-Length: 218,
  Chunked: false, 
  X-QF-APPCODE: A6A49A66B4C********94EA95032,
  X-QF-SIGN: 3b020a6349646684ebeeb0ec2cd3d1fb
}

Request Body:

{
  expired_time=10&goods_name=qfpay&limit_pay=no_credit&mchid=R1zQrTdJnn&out_trade_no=Native20190722145741431794b8d1&pay_type=800201&txamt=20&txcurrcd=HKD&txdtm=2019-07-22 14:57:42&udid=AA
}
#coding=utf8
import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, hashlib
import requests
from hashids import Hashids
import datetime
import string
import random

# Enter Client Credentials
environment = 'https://openapi-eur.qfapi.com'
app_code = 'FADB8A87E0674012979F5443AA81ECF1'
client_key = 'F644B1389AD24C25BEFE8BE10C31C878'


# Create parameter values for data payload
current_time = datetime.datetime.now().replace(microsecond=0)                                
random_string = ''.join(random.choices(string.ascii_uppercase + string.digits, k=32))

print(current_time)

# Create signature
def make_req_sign(data, key):
    keys = list(data.keys())
    keys.sort()
    p = []
    for k in keys: 
        v = data[k]
        p.append('%s=%s'%(k,v))
    unsign_str = ('&'.join(p) + key).encode("utf-8")
    print(unsign_str)
    s = hashlib.md5(unsign_str).hexdigest()
    return s.upper()

# Body payload
txamt = '1' #In USD,EUR,etc. Cent
txcurrcd = 'EUR'
pay_type = '800101' # Alipay MPM = 800101, WeChat Pay MPM = 800201
#auth_code = '287255838063025836' # CPM only
out_trade_no = random_string
txdtm = current_time
goods_name = 'Food'   
mchid = 'lkbqahlRYj' #Hashids("qfpay").encode(2546286, 2532824) #(Agent ID, Merchant ID)
key = client_key
notify_url = 'https://xxx.com/notify/success'

#data = {'txamt': txamt, 'txcurrcd': txcurrcd, 'auth_code': auth_code, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'goods_name': goods_name, 'udid': udid, 'mchid': mchid}
data = {'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm}

r = requests.post(environment+"/trade/v1/payment",data=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, key)})

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="D5589D2A1F2E42A9A60C37*********";
        String key="0E32A59A8B454940A2FF39*********";
        String mchid="ZaMVg*****";

        String pay_type="800101";
        String out_trade_no= "01234567890123";
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date=df.format(new Date());
        String txdtm=date;
        String txamt="10";
        String txcurrcd="EUR";

        Map<String, String> unsortMap = new HashMap<>();
        unsortMap.put("mchid", mchid);
        unsortMap.put("pay_type", pay_type);
        unsortMap.put("out_trade_no", out_trade_no);
        unsortMap.put("txdtm", txdtm);
        unsortMap.put("txamt", txamt);
        unsortMap.put("txcurrcd", txcurrcd);
        //unsortMap.put("product_name", product_name);
        //unsortMap.put("valid_time", "300");

        String data=QFPayUtils.getDataString(unsortMap);
        System.out.println("Data:\n"+data+key);
        String md5Sum=QFPayUtils.getMd5Value(data+key);
        System.out.println("Md5 Value:\n"+md5Sum);

        String url="https://openapi-test.qfpay.com";
        String resp= Requests.sendPostRequest(url+"/trade/v1/payment", data, appcode,key);
        System.out.println(resp);
    }
}
// Enter Client Credentials
const environment = 'https://openapi-test.qfpay.com'
const app_code = 'D5589D2A1F2E42A9A60C37*********'
const client_key = '0E32A59A8B454940A2FF39*********'

// Generate Timestamp
var dateTime = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
console.log(dateTime)

// Body Payload
const key = client_key
var tradenumber = String(Math.round(Math.random() * 1000000000))
console.log(tradenumber)

var payload = {
'txamt': '10', // In USD,EUR,etc. Cent
'txcurrcd': 'EUR',
'pay_type': '800101', // Alipay MPM = 800101, WeChat Pay MPM = 800201
'out_trade_no': tradenumber,
'txdtm': dateTime,
'mchid': 'ZaMVg*****'
};

// Signature Generation
const ordered = {};
Object.keys(payload).sort().forEach(function(key) {
  ordered[key] = payload[key] });
console.log(ordered)

var str = [];
for (var p in ordered)
if (ordered.hasOwnProperty(p)) {
str.push((p) + "=" + (ordered[p]));
}
var string = str.join("&")+client_key;
console.log(string)

const crypto = require('crypto')
var hashed = crypto.createHash('md5').update(string).digest('hex')
console.log(hashed)


// API Request
var request = require("request");
request({
  uri: environment+"/trade/v1/payment",
  headers: {
    'X-QF-APPCODE': app_code,
    'X-QF-SIGN': hashed
  },
  method: "POST",
  form: payload,
  }, 
  function(error, response, body) {
  console.log(body);
});
<?php
ob_start();
  function GetRandStr($length){
  $str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $len=strlen($str)-1;
  $randstr='';
  for($i=0;$i<$length;$i++){
  $num=mt_rand(0,$len);
  $randstr .= $str[$num];
  }
  return $randstr;
  }

     $url = 'https://test-openapi-eur.qfapi.com';
     $api_type = '/trade/v1/payment';
     $pay_type = '800101'; //Alipay MPM = 800101, WeChat Pay MPM = 800201
     //$mchid = "MNxMp11FV35qQN"; //Only agents must provide this parameter
     $app_code = 'FF2FF74F2F2E42769A4A73*********'; //API credentials are provided by QFPay
     $app_key = '7BE791E0FD2E48E6926043B*********'; //API credentials are provided by QFPay
     $now_time = date("Y-m-d H:i:s"); //Get current date-time

     $fields_string = '';
     $fields = array(
      //'mchid' => urlencode($mchid),
      'pay_type' => urlencode($pay_type),
      'out_trade_no' => urlencode(GetRandStr(20)),
      'txcurrcd' => urlencode('EUR'),
      'txamt' => urlencode(2200),
      'txdtm' => $now_time
    );
    ksort($fields); //Ascending dictionary sorting A-Z 
    print_r($fields);

    foreach($fields as $key=>$value) { 
  $fields_string .= $key.'='.$value.'&' ;
  }
  $fields_string = substr($fields_string , 0 , strlen($fields_string) - 1);

  $sign = strtoupper(md5($fields_string . $app_key));

  //// Header ////
  $header = array();
  $header[] = 'X-QF-APPCODE: ' . $app_code;
  $header[] = 'X-QF-SIGN: ' . $sign;

  //Post Data
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url . $api_type);
  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);    

  $final_data = json_decode($output, true);
  print_r($final_data);

ob_end_flush();
?>

The above command returns JSON structured like this:

{
  "surcharge_fee": 0, 
  "qrcode": "https://qr.alipay.com/bax03190uxd47wbekffy6033", 
  "pay_type": "800101", 
  "surcharge_rate": 0, 
  "resperr": "success", 
  "txdtm": "2020-04-23 11:09:24", 
  "out_trade_no": "364ZK6BAJGYHMU3TUX0X7MGIGQL4O8KI", 
  "syssn": "20200423066200020000976054", 
  "sysdtm": "2020-04-23 11:09:27", 
  "txcurrcd": "EUR", 
  "respmsg": "", 
  "chnlsn2": "", 
  "cardcd": "", 
  "udid": "qiantai2", 
  "txamt": "1", 
  "respcd": "0000", 
  "chnlsn": ""
}

POST ../trade/v1/payment

The merchant generates a dynamic QR code based on the Alipay / WeChat Pay protocol and presents it to the customer. The user opens their Alipay / WeChat Pay wallet and scans the displayed QRC in order to complete payment. This szenario applies to offline as well as online payments, for instance on websites.

Request Parameters

Parameter name Parameter code Mandatory Parameter type Description
Public payment parameter
Payment mark pay_tag No String(16) The default value is: ALIPAYHK
Alipay Continental version: ALIPAYCN
801103 - Alipay overseas online refund (QF_BUSICD_ALIPAY_ONLINE_REFUND)
801104 - Alipay overseas online inquiry (QF_BUSICD_ALIPAY_ONLINE_QUERY)
801110 - Alipay overseas online APP payment (QF_BUSICD_ALIPAY_ONLINE_APP)
801501 - Alipay Hong Kong pc scan code
801512 - Alipay Hong Kong WAP payment
801510 - Alipay Hong Kong APP payment
Order expiration time expired_time No
(MPM only)
String(3) QRC expiration time in unit minutes. The default expiration time is 30 minutes. The parameter can manually be adjusted to a minimum of 5 minutes, and up to a maximum of 120 minutes.
Available for:
800201 - WeChat scan code
800101 - Alipay scan code
801512 - Alipay Hong Kong WAP payment
801501 - Alipay Hong Kong scan code
801107 - Alipay overseas WAP payment
801101 - Alipay overseas scan code
801010 - WeChat Hong Kong APP
801510 - Alipay Hong Kong APP
Designated payment method limit_pay No String The parameter value is specified as no_credit, and credit card payment is prohibited. This setting only applies to mainland China.

Response Parameters

Parameter code Secondary parameter code Parameter type Parameter name Description
QR Code String(512) QR code link
Public payment parameter

Consumer Present Mode (CPM)

CPM process-flow

CPM API Request

Request Header:

{
  Content-Type: application/x-www-form-urlencoded; 
  charset=UTF-8,
  Content-Length: 218,
  Chunked: false
  X-QF-APPCODE:A6A49A66B4C********94EA95032
  X-QF-SIGN:3b020a6349646684ebeeb0ec2cd3d1fb
}

Request Body:

{
  auth_code=13485790*******88557&goods_name=qfpay&mchid=R1zQrTdJnn&out_trade_no=Native201907221520536a25477909&pay_type=800208&txamt=10&txcurrcd=HKD&txdtm=2019-07-22 15:20:54&udid=AA
}
#coding=utf8
import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, hashlib
import requests
import datetime
import string

# Enter Client Credentials
environment = 'https://openapi-test.qfpay.com'
app_code = 'D5589D2A1F2E42A9A60C37*********'
client_key = '0E32A59A8B454940A2FF39**********'


# Create parameter values for data payload
current_time = datetime.datetime.now().replace(microsecond=0)                                

print(current_time)

# Create signature
def make_req_sign(data, key):
    keys = list(data.keys())
    keys.sort()
    p = []
    for k in keys: 
        v = data[k]
        p.append('%s=%s'%(k,v))
    unsign_str = ('&'.join(p) + key).encode("utf-8")
    s = hashlib.md5(unsign_str).hexdigest()
    return s.upper()


# Body payload
txamt = '10' #In USD,EUR,etc. Cent
txcurrcd = 'EUR'
pay_type = '800108' # Alipay CPM = 800108 , WeChat Pay CPM = 800208
auth_code = '280438849930815813' # Mandatory for CPM
out_trade_no = '01234567890123'
txdtm = current_time
goods_name = 'test1'   
mchid = 'ZaMVg*****'
notify_url = 'https://xxx.com/notify/success'
key = client_key


#data ={'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'goods_name': goods_name, 'udid': udid, 'auth_code': auth_code, 'mchid': mchid, 'notify_url': notify_url}
data ={'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'mchid': mchid, 'auth_code': auth_code}

r = requests.post(environment+"/trade/v1/payment",data=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, key)})

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="D5589D2A1F2E42A9A60C37*********";
        String key="0E32A59A8B454940A2FF39*********";
        String mchid="ZaMVg*****";

        String pay_type="800108";
        String auth_code="280438849930815813";
        String out_trade_no= "01234567890123";
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date=df.format(new Date());
        String txdtm=date;
        String txamt="10";
        String txcurrcd="EUR";

        Map<String, String> unsortMap = new HashMap<>();
        unsortMap.put("mchid", mchid);
        unsortMap.put("pay_type", pay_type);
        unsortMap.put("auth_code", auth_code);
        unsortMap.put("out_trade_no", out_trade_no);
        unsortMap.put("txdtm", txdtm);
        unsortMap.put("txamt", txamt);
        unsortMap.put("txcurrcd", txcurrcd);
        //unsortMap.put("product_name", product_name);
        //unsortMap.put("valid_time", "300");

        String data=QFPayUtils.getDataString(unsortMap);
        System.out.println("Data:\n"+data+key);
        String md5Sum=QFPayUtils.getMd5Value(data+key);
        System.out.println("Md5 Value:\n"+md5Sum);

        String url="https://openapi-test.qfpay.com";
        String resp= Requests.sendPostRequest(url+"/trade/v1/payment", data, appcode,key);
        System.out.println(resp);
    }
}
// Enter Client Credentials
const environment = 'https://openapi-test.qfpay.com'
const app_code = 'D5589D2A1F2E42A9A60C37*********'
const client_key = '0E32A59A8B454940A2FF39*********'

// Generate Timestamp
var dateTime = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
console.log(dateTime)

// Body Payload
const key = client_key
var tradenumber = String(Math.round(Math.random() * 1000000000))
console.log(tradenumber)

var payload = {
'txamt': '10', // In USD,EUR,etc. Cent
'txcurrcd': 'EUR',
'pay_type': '800108', // Alipay CPM = 800108, WeChat Pay CPM = 800208
'auth_code': '280438849930815813',
'out_trade_no': tradenumber,
'txdtm': dateTime,
'mchid': 'ZaMVg*****'
};

// Signature Generation
const ordered = {};
Object.keys(payload).sort().forEach(function(key) {
  ordered[key] = payload[key] });
console.log(ordered)

var str = [];
for (var p in ordered)
if (ordered.hasOwnProperty(p)) {
str.push((p) + "=" + (ordered[p]));
}
var string = str.join("&")+client_key;
console.log(string)

const crypto = require('crypto')
var hashed = crypto.createHash('md5').update(string).digest('hex')
console.log(hashed)


// API Request
var request = require("request");
request({
  uri: environment+"/trade/v1/payment",
  headers: {
    'X-QF-APPCODE': app_code,
    'X-QF-SIGN': hashed
  },
  method: "POST",
  form: payload,
  }, 
  function(error, response, body) {
  console.log(body);
});
<?php
ob_start();
  function GetRandStr($length){
  $str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $len=strlen($str)-1;
  $randstr='';
  for($i=0;$i<$length;$i++){
  $num=mt_rand(0,$len);
  $randstr .= $str[$num];
  }
  return $randstr;
  }

     $url = 'https://test-openapi-eur.qfapi.com';
     $api_type = '/trade/v1/payment';
     $pay_type = '800108'; //Alipay CPM = 800108, WeChat Pay CPM = 800208
     $auth_code = '280438849930815813';
     //$mchid = "MNxMp11FV35qQN"; //Only agents must provide this parameter
     $app_code = 'FF2FF74F2F2E42769A4A73*********'; //API credentials are provided by QFPay
     $app_key = '7BE791E0FD2E48E6926043B*********'; //API credentials are provided by QFPay
     $now_time = date("Y-m-d H:i:s"); //Get current date-time

     $fields_string = '';
     $fields = array(
      //'mchid' => urlencode($mchid),
      'pay_type' => urlencode($pay_type),
      'auth_code' => urlencode($auth_code),
      'out_trade_no' => urlencode(GetRandStr(20)),
      'txcurrcd' => urlencode('EUR'),
      'txamt' => urlencode(2200),
      'txdtm' => $now_time
    );
    ksort($fields); //Ascending dictionary sorting A-Z 
    print_r($fields);

    foreach($fields as $key=>$value) { 
  $fields_string .= $key.'='.$value.'&' ;
  }
  $fields_string = substr($fields_string , 0 , strlen($fields_string) - 1);

  $sign = strtoupper(md5($fields_string . $app_key));

  //// Header ////
  $header = array();
  $header[] = 'X-QF-APPCODE: ' . $app_code;
  $header[] = 'X-QF-SIGN: ' . $sign;

  //Post Data
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url . $api_type);
  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);    

  $final_data = json_decode($output, true);
  print_r($final_data);

ob_end_flush();
?>

The above command returns JSON structured like this:

{
  "pay_type": "800108", 
  "sysdtm": "2019-07-22 15:20:54",  
  "paydtm": "2019-07-22 15:20:56",  
  "txdtm": "2019-07-22 15:20:54", 
  "udid": "AA", 
  "txcurrcd": "EUR",  
  "txamt": 10, 
  "resperr": "交易成功", 
  "respmsg": "OK", 
  "out_trade_no": "201907221520536a25477909", 
  "syssn": "20190722000300020081074842", 
  "respcd": "0000", 
  "chnlsn": "4200000384201907223585006133"
}

POST ../trade/v1/payment

The customer generates a dynamic QR code in their QR code wallet and presents it to the cashier for scanning. This szenario applies to offline payments only. If the response codes 1143/1145 are returned, the transaction is being processed or the customer is required to input the wallet password. Merchants have to query the transaction result for a final assessment of the transaction status.

Request Parameters

Parameter name Parameter code Mandatory Parameter type Description
Public payment parameters
Authorization Code auth_code Yes
(CPM only)
String(128) Specifies the authorization code for scanning a barcode/QR Code. The auth_code returned is unique in each authorization. Each auth_code can only be used once and will automatically expire. For testing CPM with Alipay and WeChat Pay the auth_code can be extracted by any QRC reader or manually found in the consumer wallet below the barcode.

Response Parameters

Parameter name Parameter code Mandatory Parameter type Description
Public payment parameters

Transaction Notes

Merchant can use this interface to add remarks to a transaction. This remarks value will be displayed in the Merchant Management System (MMS) and on the transaction report.

API Endpoint for Transaction Notes

Request Header:

{
  Content-Type: application/x-www-form-urlencoded;
  X-QF-APPCODE: D5589D2A1F2E42A9A60C37**********
  X-QF-SIGN: 6FB43AC29175B4602FF95F8332028F19
}

Request Body:

{
  code=A6A49A6******DFE94EA95032&note=add_note&syssn=20190722000200020081075691
}

The above command returns JSON structured like this:

{
  "resperr": "Success",
  "respcd": 0000,
  "respmsg": "",
  "data":
{
  "syssn": "20190722000200020081084545"
}
}

HTTP Request

POST ../trade/v1/add_note

Request Parameters

Parameter name Parameter code Mandatory Parameter type Description
Merchant app code code Yes String(32) Provided by QF Pay
Transaction number syssn Yes String(40) QFPay transaction number, returned by the system once payment is completed
Remarks note Yes String(200) Remarks value

Response Parameters

Parameter code Parameter type Parameter name Description
resperr String(128) Transaction result description
respmsg String(128) Error message
respcd String(4) Return code 0000 = Interface call succeeded
syssn String(40) Error message Transaction number returned by the system when payment is completed

Transaction Enquiry

API Endpoint for Transaction Enquiry

HTTP Request

POST ../trade/v1/query

Request Header:

{
  Content-Type: application/x-www-form-urlencoded;
  X-QF-APPCODE: D5589D2A1F2E42A9A60C37**********
  X-QF-SIGN: 6FB43AC29175B4602FF95F8332028F19
}

Request Body:

{
  mchid=ZaMVg*****&syssn=20191227000200020061752831&start_time=2019-12-27 00:00:00&end_time=2019-12-27 23:59:59
}
import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, hashlib
import requests
from hashids import Hashids
import datetime
import string
import random

# Enter Client Credentials
environment = 'https://openapi-test.qfpay.com'
app_code = 'D5589D2A1F2E42A9A60C37**********'
client_key = '0E32A59A8B454940A2FF39**********'

# Create parameter values for data payload
current_time = datetime.datetime.now().replace(microsecond=0)         
random_string = ''.join(random.choices(string.ascii_uppercase + string.digits, k=32))                       


# Create signature
def make_req_sign(data, key):
    keys = list(data.keys())
    keys.sort()
    p = []
    for k in keys: 
        v = data[k]
        p.append('%s=%s'%(k,v))
    unsign_str = ('&'.join(p) + key).encode("utf-8")
    s = hashlib.md5(unsign_str).hexdigest()
    return s.upper()


# Body payload
mchid = 'ZaMVg*****' #(Agent ID, Merchant ID)
syssn = '20191227000200020061752831' #Search by transaction number only
out_trade_no = '2019122722001411461404119764' #Search by out_trade_no only
start_time = '2019-12-27 00:00:00'
end_time = '2019-12-27 23:59:59'
key = client_key


#data ={'mchid': mchid, 'syssn': syssn, 'out_trade_no': out_trade_no, 'start_time': start_time, 'end_time': end_time}
data ={'mchid': mchid, 'syssn': syssn}

r = requests.post(environment+"/trade/v1/query",data=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, key)})

print(make_req_sign(data, key))  
print(r.json())
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


public class Enquiry {
    public static void main(String args[]){
        String appcode="D5589D2A1F2E42A9A60C37**********";
        String key="0E32A59A8B454940A2FF39*********";
        String mchid="ZaMVg*****"; // Only Agents must provide the mchid

        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date=df.format(new Date());
        String txdtm=date;

        String syssn="20191227000300020061662295";
        String start_time = "2019-12-27 00:00:00";
        String end_time = "2019-12-27 23:59:59";

        Map<String, String> unsortMap = new HashMap<>();
        unsortMap.put("mchid", mchid);
        unsortMap.put("syssn", syssn);

        String data=QFPayUtils.getDataString(unsortMap);
        System.out.println("Data:\n"+data+key);
        String md5Sum=QFPayUtils.getMd5Value(data+key);
        System.out.println("Md5 Value:\n"+md5Sum);

        String url="https://openapi-test.qfpay.com";
        String resp= Requests.sendPostRequest(url+"/trade/v1/query", data, appcode,key);
        System.out.println(resp);
    }
}
// Enter Client Credentials
const environment = 'https://openapi-test.qfpay.com'
const app_code = 'D5589D2A1F2E42A9A60C37**********'
const client_key = '0E32A59A8B454940A2FF39**********'

// Generate Timestamp
var dateTime = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
console.log(dateTime)

// Body Payload
const key = client_key
var tradenumber = String(Math.round(Math.random() * 1000000000))
console.log(tradenumber)

var payload = {
'syssn': '20191231000300020063521806',
'start_time': '2019-12-27 00:00:00',
'end_time': '2019-12-31 23:59:59',
'mchid': 'ZaMVg*****'
};

// Signature Generation
const ordered = {};
Object.keys(payload).sort().forEach(function(key) {
  ordered[key] = payload[key] });
console.log(ordered)

var str = [];
for (var p in ordered)
if (ordered.hasOwnProperty(p)) {
str.push((p) + "=" + (ordered[p]));
}
var string = str.join("&")+client_key;
console.log(string)

const crypto = require('crypto')
var hashed = crypto.createHash('md5').update(string).digest('hex')
console.log(hashed)


// API Request
var request = require("request");
request({
  uri: environment+"/trade/v1/query",
  headers: {
    'X-QF-APPCODE': app_code,
    'X-QF-SIGN': hashed
  },
  method: "POST",
  form: payload,
  }, 
  function(error, response, body) {
  console.log(body);
});
<?php
ob_start();
  function GetRandStr($length){
  $str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $len=strlen($str)-1;
  $randstr='';
  for($i=0;$i<$length;$i++){
  $num=mt_rand(0,$len);
  $randstr .= $str[$num];
  }
  return $randstr;
  }

     $url = 'https://test-openapi-eur.qfapi.com';
     $api_type = '/trade/v1/query';
     $syssn = '20200311066100020000977841';
     //$out_trade_no = 'zCvo0IqTg0SaQkGnHd6w';
     //$mchid = "MNxMp11FV35qQN"; //Only agents must provide this parameter
     $app_code = 'FF2FF74F2F2E42769A4A73*********'; //API credentials provided by QFPay
     $app_key = '7BE791E0FD2E48E6926043B*********'; //API credentials provided by QFPay
     $now_time = date("Y-m-d H:i:s"); //Get the current date-time  

     $fields_string = '';
     $fields = array(
      //'mchid' => urlencode($mchid),
    'syssn' => urlencode($syssn),
    //'out_trade_no' => urlencode($out_trade_no),
    //'start_time' = '2020-03-01 00:00:00',
    //'end_time' = '2020-03-04 23:59:59'
    );
    ksort($fields); //Sort parameters in ascending order from A to Z
    print_r($fields);

    foreach($fields as $key=>$value) { 
    $fields_string .= $key.'='.$value.'&' ;
  }
  $fields_string = substr($fields_string , 0 , strlen($fields_string) - 1); 

  $sign = strtoupper(md5($fields_string . $app_key));

  //// Header ////
  $header = array();
  $header[] = 'X-QF-APPCODE: ' . $app_code;
  $header[] = 'X-QF-SIGN: ' . $sign;

  //Post Data
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url . $api_type);
  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);    

  $final_data = json_decode($output, true);
  print_r($final_data);

ob_end_flush();
?>

The above command returns JSON structured like this:

{
"respmsg": "", 
"resperr": "请求成功", 
"respcd": 0000, 
"data": 
[{
"cardtp": "5", 
"cancel": "0", 
"pay_type": "800101", 
"order_type": "payment", 
"clisn": "038424", 
"txdtm": "2019-12-27 10:39:39", 
"goods_detail": "", 
"out_trade_no": "CHZ7D61JN1ANJF2R2K1I7TXP2JTCEWBL", 
"syssn": "20191227000200020061752831", 
"sysdtm": "2019-12-27 10:40:24", 
"paydtm": "2019-12-27 10:42:18", 
"goods_name": "", 
"txcurrcd": "EUR", 
"chnlsn2": "", 
"udid": "qiantai2", 
"userid": "2605489", 
"txamt": "10", 
"chnlsn": "2019122722001411461404119764", 
"respcd": "0000", 
"goods_info": "", 
"errmsg": "success"
}], 
"page": "1", 
"page_size": "10"
}

After making a payment, refund or cancellation request, the merchant can use the query interface to obtain the transaction status.

The merchant can use the query interface to enquire transaction status of one or multiple transactions. In case the interface does not return syssn in time, use out_trade_no as a condition to query the transaction status.

If merchants would like to query transactions in a month, they can provide start_time and end_time then records will be filtered according to the system transaction time sysdtm. The interval must be within one calendar month. Otherwise, it is recommended to include the syssn parameter as a query condition.

When the query transaction is a refund then an additional parameter origssn will be returned. The origssn shows the QFPay transaction number of the original transaction that has been refunded.

Request Parameters

Parameter name Parameter code Mandatory Parameter type Description
Merchant number mchid For Agents String(16) If MCHID is given, it is mandatory to provide the mchid.On the contrary, if mchid is not provided, merchants shall not pass the mchid field in the API request.
QFPay transaction number syssn No String(128) Multiple entries are seperated by commas
API order number out_trade_no No String(128) External transaction number / Merchant platform transaction number, multiple entries are seperated by commas
Payment type pay_type No String(6) Multiple entries are seperated by commas
Transaction return code respcd No String(4) Returns all orders with return code status by default
Starting time start_time No String(20) It is ignored when syssn or out_trade_number is provided. The default date time is the start of current month. Cross-month queries must add the time query parameters start_time and end_time.
Format: YYYY-MM-DD hh:mm:ss
End Time end_time No String(20) It is ignored when syssn or out_trade_number is provided. The default date time is the end of current month. Cross-month queries must add the time query parameters start_time and end_time.
Format: YYYY-MM-DD hh:mm:ss
Time zone txzone No String(5) Used to record the local order time. The default is Beijing time UTC+8 (+0800)
Number of pages page No Int(8) Default value is 1
Number of items displayed per page page_size No Int(8) By default 10 transactions will be displayed. The maximum page_size value is 100

Response Parameters

Parameter name Parameter code Parameter type Description
Page number page Int(8)
Request result description resperr String(128)
Display number of items per page page_size Int(8)
Request result code respcd String(4) 0000 - Interface call succeeded
Query result data Object JSON format
QFPay transaction number syssn String(40)
API order number out_trade_no String(128) External transaction number / Merchant platform transaction number
Wallet/Channel transaction number chnlsn String
Product name goods_name String(64) Goods Name / Marking: Cannot exceed 20 alphanumeric or contain special characters. Cannot be empty for app payment. Parameter needs to be UTF-8 encoded if it is written in Chinese characters.
Transaction currency txcurrcd String(3) View the Currencies table for a complete list of available currencies
Original transaction number origssn String(40) Refers to the original QFPay transaction number. This parameter is only available when the syssn of a refund is queued
Payment type pay_type String(6) Please refer to the section Payment Codes for a complete list of payment types
Order type order_type String(16) Payment: Payment transaction Refund: Refund transaction
Request transaction time txdtm String(20) Request transaction time provided by merchant in payment and refund request. Format: YYYY-MM-DD hh:mm:ss
Transaction amount txamt Int(11) Amount of the transaction. Unit in cents (i.e. 100 = $1)
System transaction time sysdtm String(20) Format: YYYY-MM-DD hh:mm:ss
This parameter value is used as the cut-off time for settlements.
Cancellation or refund indicator cancel String(1) Transaction cancel status:
0 = Not cancelled
1 = For CPM: Transaction reversed or refunded successfully
2 = For MPM: Transaction canceled successfully
3 = Transaction refunded
4 = Alipay Preauth order finished
5 = Transaction partially refunded
Payment status respcd String(4) 0000 = transaction succeeded
1143/1145 = Please wait to evaluate the transaction status. All other response codes indicate transaction failure
Payment status message errmsg String(128) Payment result description
Currency exchange rate exchange_rate String Applied currency conversion exchange rate
Net payment amount cash_fee String Actual payment amount by user = transaction amount - discounts
Payment currency cash_fee_type String Actual payment currency e.g. CNY
Net refund amount cash_refund_fee String Actual refund amount
Refund currency cash_refund_fee_type String Actual refund currency e.g. CNY

Account Statement

The clearing statement for a particular payment channel is downloaded regularly. Additional requests can only be made in the production environment. The system response is in form of a compressed zip file. Data is based on the selected payment channel and contains all merchants therefore the mchid cannot be passed in as a request parameter.

API Endpoint for Account Statement

HTTP Request

GET ../download/v1/trade_bill

Request Parameter

Request code Mandatory Parameter type Description
trade_date Yes String(10) Get a specific account statement for the selected date. Example: 2017-10-17

Reversal/ Cancel


For code instructions select Python, Java, Node.js or PHP with the tabs above.


import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, hashlib
import requests
from hashids import Hashids
import datetime
import string
import random

# Enter Client Credentials
environment = 'https://test-openapi-eur.qfapi.com'
app_code = '3F504C39125E4886AB4741**********'
client_key = '5744993FBC034DBBB995FA**********'


# Create parameter values for data payload
current_time = datetime.datetime.now().replace(microsecond=0)                                
random_string = ''.join(random.choices(string.ascii_uppercase + string.digits, k=32))

print(current_time)

# Create signature
def make_req_sign(data, key):
    keys = list(data.keys())
    keys.sort()
    p = []
    for k in keys: 
        v = data[k]
        p.append('%s=%s'%(k,v))
    unsign_str = ('&'.join(p) + key).encode("utf-8")
    print(unsign_str)
    s = hashlib.md5(unsign_str).hexdigest()
    return s.upper()



# Body payload
txamt = '2500' #In USD,EUR,etc. Cent
out_trade_no = '4MDGEJ7L496LAAU1V1HBY9HMOGWZWLXQ'
syssn = '20200305066100020000977812' 
txdtm = '2020-03-05 16:50:30' 
mchid = 'MNxMp11FV35qQN'
key = client_key

#data ={'txamt': txamt, 'out_trade_no': out_trade_no, 'syssn': syssn, 'txdtm': txdtm, 'udid': udid, 'mchid': mchid}
data ={'txamt': txamt, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'mchid': mchid}

r = requests.post(environment+"/trade/v1/reversal",data=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, key)})

print(r.json())

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


public class Refund {
    public static void main(String args[]){
        String appcode="3F504C39125E4886AB4741**********";
        String key="5744993FBC034DBBB995FA**********";
        String mchid="MNxMp11FV35qQN"; // Only Agents must provide the mchid

        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date=df.format(new Date());

        String txdtm="2020-03-05 16:50:30"; 
        String txamt="2500";
        String syssn="20200305066100020000977812"; //only syssn or out_trade_no must be provided
        String out_trade_no="4MDGEJ7L496LAAU1V1HBY9HMOGWZWLXQ"; //only syssn or out_trade_no must be provided


        Map<String, String> unsortMap = new HashMap<>();
        unsortMap.put("mchid", mchid);
        unsortMap.put("txamt", txamt);
        unsortMap.put("syssn", syssn);
        unsortMap.put("out_trade_no", out_trade_no);
        unsortMap.put("txdtm", txdtm);

        String data=QFPayUtils.getDataString(unsortMap);
        System.out.println("Data:\n"+data+key);
        String md5Sum=QFPayUtils.getMd5Value(data+key);
        System.out.println("Md5 Value:\n"+md5Sum);

         //如果是国内钱台,网址是:https://openapi-test.qfpay.com.
        String url="https://test-openapi-eur.qfapi.com";
        String resp= Requests.sendPostRequest(url+"/trade/v1/reversal", data, appcode,key);
        System.out.println(resp);
    }
}

// Enter Client Credentials
environment = 'https://test-openapi-eur.qfapi.com'
app_code = '3F504C39125E4886AB4741**********'
client_key = '5744993FBC034DBBB995FA**********'

// Generate Timestamp
var dateTime = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
console.log(dateTime)

// Body Payload
const key = client_key
var tradenumber = String(Math.round(Math.random() * 1000000000))
console.log(tradenumber)

var payload = {
'txamt': '2500', 
'out_trade_no': '4MDGEJ7L496LAAU1V1HBY9HMOGWZWLXQ', //only syssn or out_trade_no must be provided
'syssn': '20200305066100020000977812', //only syssn or out_trade_no must be provided
'txdtm': '2020-03-05 16:50:30',
'mchid': 'MNxMp11FV35qQN'
};

// Signature Generation
const ordered = {};
Object.keys(payload).sort().forEach(function(key) {
  ordered[key] = payload[key] });
console.log(ordered)

var str = [];
for (var p in ordered)
if (ordered.hasOwnProperty(p)) {
str.push((p) + "=" + (ordered[p]));
}
var string = str.join("&")+client_key;
console.log(string)

const crypto = require('crypto')
var hashed = crypto.createHash('md5').update(string).digest('hex')
console.log(hashed)


// API Request
var request = require("request");
request({
  uri: environment+"/trade/v1/reversal",
  headers: {
    'X-QF-APPCODE': app_code,
    'X-QF-SIGN': hashed
  },
  method: "POST",
  form: payload,
  }, 
  function(error, response, body) {
  console.log(body);
});

<?php
ob_start();
  function GetRandStr($length){
  $str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $len=strlen($str)-1;
  $randstr='';
  for($i=0;$i<$length;$i++){
  $num=mt_rand(0,$len);
  $randstr .= $str[$num];
  }
  return $randstr;
  }

     $url = 'https://test-openapi-eur.qfapi.com';
     $api_type = '/trade/v1/reversal';
     $syssn = '800101';
     //$out_trade_no = 'zCvo0IqTg0SaQkGnHd6w';
     //$mchid = "MNxMp11FV35qQN"; //Only agents must provide this parameter
     $app_code = 'FF2FF74F2F2E42769A4A73E********'; //API credentials are provided by QFPay
     $app_key = '7BE791E0FD2E48E6926043B5********'; //API credentials are provided by QFPay
     $now_time = date("Y-m-d H:i:s"); //Get the current date-time   

     $fields_string = '';
     $fields = array(
      //'mchid' => urlencode($mchid),
      'syssn' => urlencode($syssn),
      //'out_trade_no' => urlencode($out_trade_no),
      'txcurrcd' => urlencode('EUR'),
      'txamt' => urlencode(2200),
      'txdtm' => date('2020-03-05 16:50:30'),
    );
    ksort($fields); //Sort parameters in ascending order from A to Z
    print_r($fields);

    foreach($fields as $key=>$value) { 
    $fields_string .= $key.'='.$value.'&' ;
  }
  $fields_string = substr($fields_string , 0 , strlen($fields_string) - 1); 

  $sign = strtoupper(md5($fields_string . $app_key));

  //// Header ////
  $header = array();
  $header[] = 'X-QF-APPCODE: ' . $app_code;
  $header[] = 'X-QF-SIGN: ' . $sign;

  //Post Data
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url . $api_type);
  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);    

  $final_data = json_decode($output, true);
  print_r($final_data);

ob_end_flush();
?>

The above command returns JSON structured like this:


{
    "surcharge_fee": "0", 
    "resperr": "success", 
    "txdtm": "2020-03-05 16:50:30", 
    "syssn": "20200305066100020000977814", 
    "sysdtm": "2020-03-05 16:54:38", 
    "txcurrcd": "EUR", 
    "respmsg": "", 
    "chnlsn2": "", 
    "cardcd": "", 
    "udid": "qiantai2", 
    "txamt": "2500", 
    "orig_syssn": "20200305066100020000977813", 
    "surcharge_rate": "0", 
    "respcd": "0000", 
    "chnlsn": ""
}

The reversal API endpoint allows the merchant to cancel/ reverse a transaction that is currently in progress. Transactions that have already been processed successfully (return code 0000 = successful) can no longer be reversed or cancelled. If you would like to revert a successful transaction please refer to the Refund Endpoint.

HTTP Request for Alipay CPM & MPM

GET ..trade/v1/reversal

HTTP Request for WeChat Pay CPM

GET ..trade/v1/reversal

HTTP Request for WeChat Pay MPM

GET ..trade/v1/close

HTTP Request for other qualified Wallets*

GET ..trade/v1/close

*If you would like to use this endpoint on a wallet other than Alipay & Wechat Pay please contact us for instructions.

Request Parameters

Parameter Mandatory Type Description
mchid No String(16) Merchant ID allocated by QFPay
syssn Yes* String(40) QFPay transaction number, returned by the system once payment is completed
out_trade_no Yes* String(128) External transaction number
txamt Yes Int(11) Amount of the transaction. Unit in cents (i.e. 100 = $1)
txdtm Yes String(20) Transaction time format: YYYY-MM-DD hh:mm:ss
udid No String(40) Unique transaction device ID. Is displayed on the merchant portal.

*Either the syssn or out_trade_no must be provided.

Response Parameters

Parameter Type Description
orig_syssn String(40) Refers to the original QFPay transaction number
syssn String(40) QFPay transaction number of the cancel/ reversal
out_trade_no String(128) External transaction number
txamt Int(11) Amount of the transaction. Unit in cents (i.e. 100 = $1)
txcurrcd String(3) Transaction currency. View the Currencies table for a complete list of available currencies
txdtm String(20) Transaction time. Format: YYYY-MM-DD hh:mm:ss
sysdtm String(20) System transaction time. Format: YYYY-MM-DD hh:mm:ss
This parameter value is used as the cut-off time for settlements.
chnlsn String Transaction number from payment channel (wallet side)
respcd String(4) Response code
0000 = Reversal/ cancel successul
1143/1145 = Reversal/ cancel in progress
others = Reversal/ cancel failed
resperr String(128) Result description
respmsg String(128) Information description

Refunds

API Endpoint for Refunds

Request Header:

{
  Content-Type: application/x-www-form-urlencoded;
  X-QF-APPCODE: D5589D2A1F2E42A9A60C37**********
  X-QF-SIGN: 6FB43AC29175B4602FF95F8332028F19
}

Request Body:

{
  txamt=10&syssn=20191227000200020061752831&out_trade_no=12345678&txdtm=2019-12-27 10:39:39&key=0E32A59A8B454940A2FF39**********&mchid=ZaMVg*****
}

import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, hashlib
import requests
from hashids import Hashids
import datetime
import string
import random

# Enter Client Credentials
environment = 'https://openapi-test.qfpay.com'
app_code = 'D5589D2A1F2E42A9A60C37**********'
client_key = '0E32A59A8B454940A2FF39**********'


# Create parameter values for data payload
current_time = datetime.datetime.now().replace(microsecond=0)         
random_string = ''.join(random.choices(string.ascii_uppercase + string.digits, k=32))                       


# Create signature
def make_req_sign(data, key):
    keys = list(data.keys())
    keys.sort()
    p = []
    for k in keys: 
        v = data[k]
        p.append('%s=%s'%(k,v))
    unsign_str = ('&'.join(p) + key).encode("utf-8")
    s = hashlib.md5(unsign_str).hexdigest()
    return s.upper()


# Body payload
txamt = '10' #Partial or full refund amount
syssn = '20191227000200020061752831' #Original transaction number
out_trade_no = random_string
txdtm = current_time 
key = client_key
mchid = 'ZaMVg*****'


#data ={'txamt': txamt, 'syssn': syssn, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'udid': udid, 'mchid': mchid}
data ={'mchid': mchid, 'txamt': txamt, 'syssn': syssn,  'out_trade_no': out_trade_no, 'txdtm': txdtm}

r = requests.post(environment+"/trade/v1/refund",data=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, key)})

print(r.json())
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


public class Refund {
    public static void main(String args[]){
        String appcode="D5589D2A1F2E42A9A60C37**********";
        String key="0E32A59A8B454940A2FF39**********";
        String mchid="ZaMVg*****"; // Only Agents must provide the mchid

        String out_trade_no= "22333444455555";
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date=df.format(new Date());
        String txdtm=date;
        String txamt="15";
        String syssn="20191227000300020061662295";
         //如果是国内钱台,产品名称对应的字段是goods_name,不是product_name.
         //String product_name="Test Name";


        Map<String, String> unsortMap = new HashMap<>();
        unsortMap.put("mchid", mchid);
        unsortMap.put("txamt", txamt);
        unsortMap.put("syssn", syssn);
        unsortMap.put("out_trade_no", out_trade_no);
        unsortMap.put("txdtm", txdtm);

        String data=QFPayUtils.getDataString(unsortMap);
        System.out.println("Data:\n"+data+key);
        String md5Sum=QFPayUtils.getMd5Value(data+key);
        System.out.println("Md5 Value:\n"+md5Sum);

         //如果是国内钱台,网址是:https://openapi-test.qfpay.com.
        String url="https://openapi-test.qfpay.com";
        String resp= Requests.sendPostRequest(url+"/trade/v1/refund", data, appcode,key);
        System.out.println(resp);
    }
}
// Enter Client Credentials
const environment = 'https://openapi-test.qfpay.com'
const app_code = 'D5589D2A1F2E42A9A60C37**********'
const client_key = '0E32A59A8B454940A2FF3***********'

// Generate Timestamp
var dateTime = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
console.log(dateTime)

// Body Payload
const key = client_key
var tradenumber = String(Math.round(Math.random() * 1000000000))
console.log(tradenumber)

var payload = {
'syssn': '20191231000300020063521806',
'txamt': '10',
'out_trade_no': tradenumber,
'txdtm': dateTime,
'mchid': 'ZaMVg*****'
};

// Signature Generation
const ordered = {};
Object.keys(payload).sort().forEach(function(key) {
  ordered[key] = payload[key] });
console.log(ordered)

var str = [];
for (var p in ordered)
if (ordered.hasOwnProperty(p)) {
str.push((p) + "=" + (ordered[p]));
}
var string = str.join("&")+client_key;
console.log(string)

const crypto = require('crypto')
var hashed = crypto.createHash('md5').update(string).digest('hex')
console.log(hashed)


// API Request
var request = require("request");
request({
  uri: environment+"/trade/v1/refund",
  headers: {
    'X-QF-APPCODE': app_code,
    'X-QF-SIGN': hashed
  },
  method: "POST",
  form: payload,
  }, 
  function(error, response, body) {
  console.log(body);
});
<?php
ob_start();
  function GetRandStr($length){
  $str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $len=strlen($str)-1;
  $randstr='';
  for($i=0;$i<$length;$i++){
  $num=mt_rand(0,$len);
  $randstr .= $str[$num];
  }
  return $randstr;
  }

     $url = 'https://test-openapi-eur.qfapi.com';
     $api_type = '/trade/v1/refund';
     $syssn = '20200311066100020000977840';
     //$mchid = "MNxMp11FV35qQN"; //Only agents must provide this parameter
     $app_code = 'FF2FF74F2F2E42769A4A73*********'; //API credentials are provided by QFPay
     $app_key = '7BE791E0FD2E48E6926043B*********'; //API credentials are provided by QFPay
     $now_time = date("Y-m-d H:i:s"); //Get the currend date-time  

     $fields_string = '';
     $fields = array(
      //'mchid' => urlencode($mchid),
    'syssn' => urlencode($syssn),
      'out_trade_no' => urlencode(GetRandStr(20)),
      'txamt' => urlencode(2200),
      'txdtm' => $now_time
    );
    ksort($fields); //Sort parameters in ascending order from A to Z
    print_r($fields);

    foreach($fields as $key=>$value) { 
    $fields_string .= $key.'='.$value.'&' ;
  }
  $fields_string = substr($fields_string , 0 , strlen($fields_string) - 1);

  $sign = strtoupper(md5($fields_string . $app_key));

  //// Header ////
  $header = array();
  $header[] = 'X-QF-APPCODE: ' . $app_code;
  $header[] = 'X-QF-SIGN: ' . $sign;

  //Post Data
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url . $api_type);
  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);    

  $final_data = json_decode($output, true);
  print_r($final_data);

ob_end_flush();
?>

The above command returns JSON structured like this:

{
"orig_syssn": "20191227000200020061752831", 
"sysdtm": "2019-12-27 11:11:23", 
"paydtm": "2019-12-27 11:11:26", 
"txdtm": "2019-12-27 11:10:38", 
"udid": "qiantai2", 
"txcurrcd": "EUR", 
"txamt": "10", 
"resperr": "success", 
"respmsg": "", 
"out_trade_no": "RGNOEIVU9JZLNP9GGYXWXCW7OEMI720F", 
"syssn": "20191227000300020061652643", 
"respcd": "0000", 
"chnlsn": "2019122722001411461404119764", 
"cardcd": ""
}

HTTP Request

POST ../trade/v1/refund

Merchants can use the refund interface to refund transactions. The merchant account must have a sufficient transaction amount on the same trading day in order to refund transactions. The maximum refund amount for a transaction must not exceed to original payment amount. Unless otherwise specified, once a refund request is submitted and accepted, it is not reversible. The refund capability and the maximum time period for refund varies across payment channels. Please contact your QFPay support representative for more information.

Request Parameters

Parameter name Parameter code Mandatory Parameter type Description
QF Pay transaction number syssn Yes String(128) Original transaction ID syssn that is supposed to be refunded
API order number out_trade_no Yes String(128) External refund transaction number / Merchant platform refund transaction number: This parameter must be unique for each payment and refund request under the same merchant account in the system.
Refund amount txamt Yes Int(11) Amount of the refund. Unit in cents (i.e. 100 = $1)
Required for both full refund and partial refund. Some payment channel may not support partial refund.
Transaction request time txdtm Yes String(20) Format: YYYY-MM-DD hh:mm:ss
Merchant ID mchid No String(16) May or may not be given to merchant. If MCHID is given, it is mandatory to provide the MCHID. On the contrary, if MCHID is not provided, merchants shall not pass the MCHID field in the API request.
Transaction time txzone No String(5) Used to record the local transaction time. The default is Beijing time UTC+8 (+0800)
Device ID udid No String(40) Unique transaction device ID

Response Parameters

Parameter name Parameter code Parameter type Description
Refund Transaction ID syssn String(40) New transaction ID referring to the newly created refund transaction
Original Transaction ID orig_syssn String(128) Previous transaction ID referring to the original transaction that has been refunded
Refund amount txamt Int(11) Amount of the refund. Unit in cents (i.e. 100 = $1)
System transaction time sysdtm String(20) Format: YYYY-MM-DD hh:mm:ss
This parameter value is used as the cut-off time for settlements.
Return code respcd String(4) 0000-Request successful.
1143/1145 - merchants are required to continue to query the refund transaction result.
All other return codes indicate transaction failure. Please refer to the section payment status codes for a complete list of return codes.
Response message resperr String(128) Error message
Net payment amount cash_fee String Actual payment amount by user = transaction amount - discounts
Payment currency cash_fee_type String Actual payment currency e.g. CNY
Net refund amount cash_refund_fee String Actual refund amount
Refund currency cash_refund_fee_type String Actual refund currency e.g. CNY

Asynchronous Notifications

Notifications are available for payments "notify_type": "payment" and refunds "notify_type": "refund". The request parameters from Asynchronous Notifications may include additional parameters in future versions. Developers must ensure that their programs can support new parameters. In addition, developers can get the latest development documentation from this website.

Description

Upon successful payment and refund, QFPay API will send an asynchronous notification message to the URL address defined by the merchant. Merchant can develop an end-point to receive this notification message and update the status of a transaction accordingly. We recommend merchants to use the query function of the API in conjunction with the asynchronous notification end point to retireve the payment status. Asynchronous notifications only work with ports 80 and 443 due to security requirements.

Asynchronous Notification Rules

1) The merchant will only be notified after the payment or refund transaction has been successful.

2) Please send an email with your notification endpoint URL address to technical.support@qfpay.com for the asynchronous notification setup. Our technical support team will setup the provided URL for you.

3) Upon receiving the notification, merchant shall verifiy the message integrity according to signature verification procedure described below. If the verification is successful, the system is required to response with status code 200 OK and the string SUCCESS in the response body.

4) If our API does not receive a response with status code 200 OK and SUCCESS message, we will send out asynchronous notifications at the following intervals after the first message; 2m, 10m, 10m, 60m, 2h, 6h, 15h. Notifications will stop when the response with status code 200 OK and SUCCESS message is received.

5) One set of app code and key can be setup with one notification URL address only. Patners shall use one notification URL address for their sub-merchants.

6) Method: POST content-type: application/json

Signature Verification

For code instructions select Python with the tabs above.
import hashlib
import json

# Client Credentials
client_key = "3ABB1BFFE2E0497BB9270978B0BXXXXX"

# Raw Content Data
data = {"status": "1", "pay_type": "800101", "sysdtm": "2020-06-15 10:32:58", "paydtm": "2020-06-15 10:33:35", "goods_name": "", "txcurrcd": "THB", "txdtm": "2020-06-15 10:32:58", "mchid": "O37MRh6Qq5", "txamt": "10", "exchange_rate": "", "chnlsn2": "", "out_trade_no": "9G3ZIWTG1R3IVSC2AH2O5EGKJQ7I72QO", "syssn": "20200615000200020000641807", "cash_fee_type": "", "cancel": "0", "respcd": "0000", "goods_info": "", "cash_fee": "0", "notify_type": "payment", "chnlsn": "2020061522001453561406303428", "cardcd": "2088032341453564"}

combine_str = (json.dumps(data)+client_key).encode()

signature = hashlib.md5(combine_str).hexdigest().upper()

print(signature)

Signature String:

"A4021A3B1EBBB0F05451EF94E9EXXXXX"

The signature generation method for notifications is slightly different from other POST requests. In order to generate the signature simply take the raw content and add the client_key to the end. Then hash the encoded string with the MD5 algorithm.

Step 1: Obtain the signature from the X-QF-SIGN field in the HTTP request header

Step 2: Attach the key to the end of the request body received by the end point

Step 3: Sign the string from step 2 with MD5 algorithm

Step 4: Compare the MD5 result with the signature from X-QF-SIGN, return an HTTP response with status code 200 OK and SUCCESS in the response body if the verification is successful

Response Parameters of Asynchronous Notifications

Asynchronous Notifications POST data in JSON form structured like this:

{
  "status": "1",
  "pay_type": "800101",
  "sysdtm": "2020-05-14 12:32:56",
  "paydtm": "2020-05-14 12:33:56",
  "goods_name": "",
  "txcurrcd": "THB",
  "txdtm": "2020-05-14 12:32:56",
  "mchid": "lkbqahlRYj",
  "txamt": "10",
  "exchange_rate": "",
  "chnlsn2": "",
  "out_trade_no": "YEPE7WTW46NVU30JW5N90H7DHD94N56B",
  "syssn": "20200514000300020093755455",
  "cash_fee_type": "",
  "cancel": "0",
  "respcd": "0000",
  "goods_info": "",
  "cash_fee": "0",
  "notify_type": "payment",
  "chnlsn": "2020051422001453561444935817",
  "cardcd": "2088032341453564"
}
Parameter Send always Type Description
status Yes String 1 = payment success
pay_type Yes String Please refer to the section Payment Codes for a complete list of payment types.
sysdtm Yes String Transaction creation time in the system. This parameter value is used as the cut-off time for settlements.
paydtm Yes String Payment time of the transaction.
txcurrcd Yes String Transaction currency. View the Currencies table for a complete list of available currencies.
txdtm Yes String Order creation time provided by the merchant in the payment request.
txamt Yes String Transaction amount in Cents.
out_trade_no Yes String External transaction number.
syssn Yes String QFPay transaction number.
cancel Yes String Transaction cancel status:
0 = Not cancelled
1 = For CPM: Transaction reversed or refunded successfully
2 = For MPM: Transaction canceled successfully
3 = Transaction refunded
4 = Alipay Preauth order finished
5 = Transaction partially refunded.
respcd Yes String Transaction status - will be 0000 in the async notification message
notify_type Yes String Notification Type: payment or refund
mchid No String Unique merchant ID. This parameter is only returned to agents.
goods_name No String Goods name or marking. Custom goods name. Parameter needs to be UTF-8 encoded if it is written in Chinese characters.
exchange_rate No String Applied currency conversion exchange rate
chnlsn2 No String Additional transaction number added to the order
goods_info No String Product description
chnlsn No String Transaction number from the payment channel
cardcd No String Card number
cash_fee No String Actual payment amount by user = transaction amount - discounts
cash_fee_type No String Actual payment currency e.g. CNY
cash_refund_fee No String Actual refund amount
cash_refund_fee_type No String Actual refund currency e.g. CNY

Visa / Mastercard Online Payments

We currently support credit card payments in the Hong Kong environment. All major credit card issuers are supported.

PayType Description
802801 Visa / Mastercard Online Payments

Payment Steps


Credit Card Payment Flow

1. DDC request

Merchant server requests a Data collector form before the merchant checkout is loaded. The DDC JWT is returned

curl --location --request POST 'https://openapi-int.qfapi.com/trade/v1/payment' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'X-QF-APPCODE: A060091DA6034502B6075C4F4605061B' \
--header 'X-QF-SIGN: acf9eabe97c36ef065aa2be81e35651e' \
--data-urlencode 'txamt=1' \
--data-urlencode 'txcurrcd=HKD' \
--data-urlencode 'pay_type=802828' \
--data-urlencode 'out_trade_no=464025641' \
--data-urlencode 'txdtm=2021-12-02 05:18:11'
Parameter name Parameter code Mandatory Type Description
Payment amount txamt Yes Int(11) Amount of the transaction. Unit in cents (i.e. 100 = $1)
Currency txcurrcd Yes String(3) Transaction currency. View the Currencies table for a complete list of available currencies
Payment type pay_type Yes String(6) Please refer to the section Payment Codes for a complete list of payment types
API Order Number out_trade_no Yes String(128) External transaction number / Merchant platform transaction number: This parameter must be unique for each payment and refund request under the same merchant account in the system.
Request transaction time txdtm Yes String(20) Transaction time format:
YYYY-MM-DD hh:mm:ss

2. Get SessionId

On the payment page, create a hidden iframe and submit form POST when the "Pay now" button is just clicked. A Data collector sessionId is returned. View page: DDC_Test.html

<iframe name='iframet' height="1" width="1" style="display: none;"></iframe>
<form target='iframet' method="post" action="https://centinelapistag.cardinalcommerce.com/V1/Cruise/Collect" name="f1">
    <table>
        <div>
            <span>Bin(Card No.) :</span>
            <textarea rows="3" cols="200" name="Bin"></textarea>
        </div>
        <div>
            <span>JWT :</span>
            <textarea rows="3" cols="200" name="JWT"></textarea>
        </div>
    </table>
    <button type="submit">submit</button>
</form>
<h3 id='referenceId'></h3>
<script type="text/javascript">
    window.addEventListener("message", function (event) {
        console.log(JSON.parse(event.data));
        if (event.origin === "https://centinelapistag.cardinalcommerce.com") {
            var data = JSON.parse(event.data);
            console.log('Merchant received a message:', data);
            if (data !== undefined && data.Status) {
                document.getElementById('referenceId').innerHTML = data.SessionId
            }
        }
    }, false);
</script>

3. Payment request

The merchant server collects the payment information with sessionId and sends a payment request to QFPay. Encryption is required for sensitive information such as card number, expiry year/month, CVC, customer information

curl --location --request POST 'https://openapi-int.qfapi.com/trade/v1/payment' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'X-QF-APPCODE: A060091DA6034502B6075C4F4605061B' \
--header 'X-QF-SIGN: d33aadf2df78e568329a2d2dcf82070f' \
--data-urlencode 'txamt=1' \
--data-urlencode 'txcurrcd=HKD' \
--data-urlencode 'pay_type=802801' \
--data-urlencode 'out_trade_no=299085842' \
--data-urlencode 'txdtm=2021-12-02 05:46:23' \
--data-urlencode 'extend_info={"payment_data_enc":"d5715af3e290dae1c5980f4ceacd2fb7633962b26293de08f1fd9137802608c8e197e1f6fb6ef2eafa33e8933474876c46e31e7418021b9bfa5ea367421a307e80a1c4df74253b04112b6617b4bd5c7542327e61192f0010c0822de31f53c7dce6bce1b83d6eaeaa0e3020b98fabb93342433d7f0de43bdbe33a87c2e58220b614c859c3c4dc15afc234a1cec2dd3806b3f9957449cfcf2fee7910dd84ec64bd5a987914ab1d19d4d413e455e66c65eb50da71db62f4ea4a610d050ac051d82879cb83c00f9d78c017674a5f4287ce185db222f8d89f989896c504620c075b688b81a07211f98361587532b848abf488d78e3aaf7e49f398aba8f95561b00bcbc655b7e570df1fb169ddbd3b0289b38d05ae225ccf294c901a7559a382bf0e585e037158de0a479a25d0add81326bd3e91cee2e522b1f0c9e12ab5d7922eb626d6ab7a7132516614f900fa6b6401019ad9199cc09bab0a9b0dbd4b6edac964fd0d1e6f24a2a4c530fb231d24549d9751938b64407bdadf0149be0e687521e595c5f8d350e170cee4157758c7299e4fc4a6578676516e2ceabb1f631f39808eee7f40217e77055b64910658e6e4ad41b3d6a16cd6a53217632eb01c5ed9f6993e7fcd8814ce98ca86578047e741eef31ff9780f91323a9ed0bf18cbb0a9d20983e52b3c2ed1df80e9d48dfd6d3ce2eaf2bc870cbfdf5fb4fc89d34dfe6920f2d829b7751f81b3f68222a4e7187f302f77a0d218adad9540be675205e8ee82a603684ce15865dc3e815db91f723c489122266b85ac705390a4e58796803512dbc5c80b2cb4104db559e55f6d6fc10635b68f5f0a216cd3106558ece137dc7675f3ec9c2e9a3f8cb41fd377c3098941f4b85fd45347f97a55cae4af1549cfb3b8bf","return_url":"https://example.com"}'
Parameter name Parameter code Mandatory Type Description
Payment amount txamt Yes Int(11) Amount of the transaction. Unit in cents (i.e. 100 = $1)
Currency txcurrcd Yes String(3) Transaction currency. View the Currencies table for a complete list of available currencies
Payment type pay_type Yes String(6) Please refer to the section Payment Codes for a complete list of payment types
API Order Number out_trade_no Yes String(128) External transaction number / Merchant platform transaction number: This parameter must be unique for each payment and refund request under the same merchant account in the system.
Request transaction time txdtm Yes String(20) Transaction time format:
YYYY-MM-DD hh:mm:ss
Credit Card extend_info Yes json Json encoded string that contains the following information:


In extend_info:

Field name Mandatory Type Description
payment_data_enc Yes String encrypted payment information, please refer to payment_data table below
return_url Yes String The return url after going through 3DS authentication

Payment data sample:

{
   "card": {
     "number": "5200000000001096",
     "cardholder_name": "chan tai man",
     "exp_month": "12",
     "exp_year": " 2034",
     "cvc": "567"
   },
   "billing_address": {
     "address1": "1007",
     "address2": "tins enterprise center",
     "address3": "777 lai chi kok road",
     "postal_code": "000000",
     "city": "hong kong",
     "country_code": "HK"
   },
   "customer": {
     "browser": {
       "accept_header": "text/html",
       "user_agent_header": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.109 Safari/537.36",
       "browser_language": "en-GB"
     },
     "email": "test@example.com",
     "session_id": "86650cfa-9ea3-11ec-b909-0242ac120002",
     "ip_address": "12.34.56.78",
     "reference_id": "0_48af32ba-e658-4b4c-82b1-e85355a0e9f4"
   }
 }

Encryption code example of the payment_data

Please refer to sample in PHP tab
Please refer to sample in PHP tab
Please refer to sample in PHP tab
Please refer to sample in PHP tab
<?php
$plaintext = '{"card":{"number":"5200000000001096","cardholder_name":"chan tai man","exp_month":"12","exp_year":" 2034","cvc":"567"},"billing_address":{"address1":"1007","address2":"tins enterprise center","address3":"777 lai chi kok road","postal_code":"000000","city":"hong kong","country_code":"HK"},"customer":{"browser":{"accept_header":"text/html","user_agent_header":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.109 Safari/537.36","browser_language":"en-GB"},"email":"test@example.com","session_id":"6227228bc7740","ip_address":"12.34.56.78","reference_id":"0_48af32ba-e658-4b4c-82b1-e85355a0e9f4"}}';
$cipher = "aes-256-cbc";
$key = 'APP_KEY'; // paste your key here
if (in_array($cipher, openssl_get_cipher_methods()))
{
   $ivlen = openssl_cipher_iv_length($cipher);
   $iv = openssl_random_pseudo_bytes($ivlen);
   $ciphertext = openssl_encrypt($plaintext, $cipher, $key, $options=0, $iv, $tag);

   $ciphertext = bin2hex(base64_decode($ciphertext));

   echo bin2hex(($iv)).$ciphertext;
   echo "\n";


   // decrypt test
   $ciphertext = base64_encode(hex2bin($ciphertext));
   $original_plaintext = openssl_decrypt($ciphertext, $cipher, $key, $options=0, $iv, $tag);
   echo $original_plaintext."\n";
}
else {
 echo 'algo not support';
}
?>


payment_data scheme before encryption:

Level 2 Level 3 Level 4 Mandatory Type Description
card number Y String card number
exp_month Y String expiration month in format MM
exp_year Y String expiration year in format YYYY
cardholder_name Y String card holder name
cvc N String card cvc
customer ip_address Y String IP Address of the shopper
reference_id Y String reference id (SessionId) return from DDC
session_id Y String unique identifier, highly recommend UUID
email Y (if 3ds) String email address of the shopper
browser accept_header N String browser accept header, default text/html
user_agent_header Y String browser user agent header
browser_language Y String browser language
billing_address address1 N String First line of address, required if city is not empty
address2 N String Second line of address
address3 N String Third line of address
city N String city, required if address1 is not empty
postal_code Y (if 3ds) String postal code, e.g. 000000 (if not applicable)
country_code Y (if 3ds) String country code, refer to ISO 3166. e.g. HK

Encryption algorithm of the payment_data

4. Verification (3DS) form data / payment result

Please pay attention to the variety of the API response, there are two different handlings.

Case 1: 3DS required

Response for 3DS required case

{
   "qrcode": "",
   "pay_type": "802801",
   "resperr": "success",
   "txdtm": "2021-12-08 07:04:15",
   "out_trade_no": "354267281",
   "syssn": "20211208180500020000001637",
   "sysdtm": "2021-12-08 15:04:16",
   "paydtm": "2021-12-08 15:04:16",
   "txcurrcd": "USD",
   "respmsg": "",
   "respcd": "0000",
   "pay_url": "",
   "cardcd": "",
   "udid": "qiantai2",
   "txamt": "1",
   "pay_params": {
       "3ds_challenge_details": {
           "url": "https://centinelapistag.cardinalcommerce.com/V2/Cruise/StepUp",
           "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJSZXR1cm5VcmwiOiJodHRwczovL2hrLnlhaG9vLmNvbSIsImlzcyI6IjYxNTViZThlYTJlNDhkNzAzYTM5ODI1NSIsIk9iamVjdGlmeVBheWxvYWQiOnRydWUsImp0aSI6IjdmZDkxOGM2LTJkNjItNDE2My1iOTJiLWUxZGU0YjY3MzJmMCIsImlhdCI6MTYzODk0NzA1NywiUGF5bG9hZCI6eyJBQ1NVcmwiOiJodHRwczovLzBtZXJjaGFudGFjc3N0YWcuY2FyZGluYWxjb21tZXJjZS5jb20vTWVyY2hhbnRBQ1NXZWIvY3JlcS5qc3AiLCJUcmFuc2FjdGlvbklkIjoia0VJVlRiWDFRc21DUkpWM05OMzAiLCJQYXlsb2FkIjoiZXlKdFpYTnpZV2RsVkhsd1pTSTZJa05TWlhFaUxDSnRaWE56WVdkbFZtVnljMmx2YmlJNklqSXVNUzR3SWl3aWRHaHlaV1ZFVTFObGNuWmxjbFJ5WVc1elNVUWlPaUppT1dZNVkyVXdOeTB3TldJekxUUTJNR1F0T0RJMk5TMWlNVGt6T1ROaFlqa3dOVFlpTENKaFkzTlVjbUZ1YzBsRUlqb2lOVGRoWVdReU1HSXRNakUyWkMwME0ySmhMVGxqWldJdFl6azNPV00xTkRKa05USmhJaXdpWTJoaGJHeGxibWRsVjJsdVpHOTNVMmw2WlNJNklqQXlJbjAifSwiT3JnVW5pdElkIjoiNjE1NWJlOGU1NjFlNWQyNGNlZWY0MGYyIn0.6xvBDFB4qV4RN-XvceNH7PllWChrQQthmbtskar0qAw"
       },
       "set-cookie": "machine=0a854015;path=/",
       "order_code": "20211208180500020000001637"
   },
   "chnlsn": ""
}

If there is pay_params.3ds_challenge_details or pay_params.request_3d_secure item, which contains 3DS form POST data, the shopper will be redirected to the bank verification page by composing automatic form POST in frontend.


















Case 2: Frictionless

Case 2: Response for 3DS Frictionless flow

{
    "qrcode": "",
    "pay_type": "802801",
    "resperr": "success",
    "txdtm": "2022-05-03 02:38:51",
    "out_trade_no": "312717842",
    "syssn": "20220503180500020000003749",
    "sysdtm": "2022-05-03 10:38:51",
    "paydtm": "2022-05-03 10:38:51",
    "txcurrcd": "USD",
    "respmsg": "",
    "respcd": "0000",
    "pay_url": "",
    "cardcd": "",
    "udid": "qiantai2",
    "txamt": "7000",
    "pay_params": {
        "payment_method": "VISA_CREDIT-SSL",
        "3ds_secure_result": "Cardholder authenticated",
        "last_event": "AUTHORISED",
        "order_code": "20220503180500020000003749",
        "set-cookie": "machine=0a844015;path=/"
    },
    "chnlsn": ""
}

Case 2b: Error Response Example

{
  "pay_type": "802801",
  "sysdtm": "2022-09-12 22:07:05",
  "paydtm": "2022-09-12 22:07:05",
  "udid": "qiantai2",
  "txcurrcd": "USD",
  "txdtm": "2022-09-12 14:07:05",
  "txamt": "39900",
  "resperr": "ISO8583 Error Code 34: FRAUD SUSPICION",
  "respmsg": "",
  "out_trade_no": "93FXFJ2UXX",
  "syssn": "20220912154200020014859811",
  "respcd": "1205",
  "chnlsn": "",
  "cardcd": ""
}

If the 3DS Frictionless is in place, which decision was made by the bank. Steps 4, 5 will be skipped, the direct response (Step 6.) will be returned









































5. Redirect to 3DS page using form POST

Code reference for redirect to 3DS page

<form method="post" action="https://centinelapistag.cardinalcommerce.com/V2/Cruise/StepUp" name="f1">
    <table>
        <div>
            <span>JWT :</span>
            <textarea rows="3" cols="200" name="JWT"></textarea>
        </div>
    </table>
    <button type="submit">submit</button>
    <script type="text/javascript">
    </script>
</form>

Code reference: Browser_Redirect_3DS_input.html









6. Payment Verify

Payment verify request

curl --location --request POST 'https://openapi-int.qfapi.com/trade/v1/payment_verify' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'X-QF-APPCODE: A060091DA6034502B6075C4F4605061B' \
--header 'X-QF-SIGN: cc1b6a456731b85cc136c214a4a1f6c1' \
--data-urlencode 'syssn=20211202180500020000003515' \
--data-urlencode 'txdtm=2021-12-02 06:37:57' \
--data-urlencode 'chnl_ext={"session_id": "86650cfa-9ea3-11ec-b909-0242ac120002","set_cookie": "machine=0a854015;path=/"}' \
--data-urlencode 'out_trade_no=385913749'

Notify QFPay when 3DS is completed, and the payment result can be determined from the API response. We recommend doubling confirm with the payment notification

Level 1 Level 2 Mandatory Type Description
chnl_ext set_cookie Y String the cookie value return from the payment request, e.g. machine=0a854015;path=/
session_id Y String same unique identifier in the payment request, e.g. 86650cfa-9ea3-11ec-b909-0242ac120002







7. Asynchronous Notification

QFPay will also send the asynchronous payment notification for the transaction status update

Sample notification payload

{
    "cardtp": "5",
    "cancel": "0",
    "pay_type": "802801",
    "order_type": "payment",
    "clisn": "054256",
    "txdtm": "2021-12-08 07:04:15",
    "goods_detail": "",
    "out_trade_no": "354267281",
    "syssn": "20211208180500020000001637",
    "sysdtm": "2021-12-08 15:04:16",
    "paydtm": "2021-12-08 15:06:51",
    "goods_name": "",
    "txcurrcd": "USD",
    "chnlsn2": "",
    "cardcd": "",
    "udid": "qiantai2",
    "userid": "1130000355",
    "txamt": "1",
    "chnlsn": "",
    "respcd": "0000",
    "goods_info": "",
    "errmsg": "success"
}

Resources

Test values

Test values are available for the Sandbox environment for result simulation. By using Test values to simulate an expected result, the Payment steps: DDC request and Get SessionId must pass

Field Value Expected Result
card - MasterCard 5200000000001096 valid
card - Visa 4000000000001091 valid
card - MasterCard 5200000000001005 valid (3DS frictionless)
card - Visa 4000000000001000 valid (3DS frictionless)
card - MasterCard 5200000000001120 failed (at verification)
card - Visa 4000000000001125 failed (at verification)
card - MasterCard 5200000000001013 failed (at 3DS frictionless)
card - Visa 4000000000001018 failed (at 3DS frictionless)

Alipay Online Payments


For code instructions select Python, Java, Node.js or PHP with the tabs above.

#coding=utf8
import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, hashlib
import requests
import datetime
import string

# Enter Client Credentials
environment = 'https://openapi-test.qfpay.com'
app_code = 'D5589D2A1F2E42A9A60C37*********'
client_key = '0E32A59A8B454940A2FF39**********'


# Create parameter values for data payload
current_time = datetime.datetime.now().replace(microsecond=0)                                

print(current_time)

# Create signature
def make_req_sign(data, key):
    keys = list(data.keys())
    keys.sort()
    p = []
    for k in keys: 
        v = data[k]
        p.append('%s=%s'%(k,v))
    unsign_str = ('&'.join(p) + key).encode("utf-8")
    s = hashlib.md5(unsign_str).hexdigest()
    return s.upper()


# Body payload
txamt = '10' #In USD,EUR,etc. Cent
txcurrcd = 'EUR'
pay_type = '801101' # Alipay Web Payment = 801101
auth_code='283854702356157409' #CPM only
out_trade_no = '01234567890123'
txdtm = current_time
goods_name = 'test1'   
mchid = 'ZaMVg*****'
key = client_key


#data ={'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'goods_name': goods_name, 'mchid': mchid}
data ={'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'mchid': mchid}

r = requests.post(environment+"/trade/v1/payment",data=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, key)})

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="D5589D2A1F2E42A9A60C37*********";
        String key="0E32A59A8B454940A2FF39*********";
        String mchid="ZaMVg*****";

        String pay_type="801101";
        String out_trade_no= "01234567890123";
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date=df.format(new Date());
        String txdtm=date;
        String txamt="10";
        String txcurrcd="EUR";

        Map<String, String> unsortMap = new HashMap<>();
        unsortMap.put("mchid", mchid);
        unsortMap.put("pay_type", pay_type);
        unsortMap.put("out_trade_no", out_trade_no);
        unsortMap.put("txdtm", txdtm);
        unsortMap.put("txamt", txamt);
        unsortMap.put("txcurrcd", txcurrcd);
        //unsortMap.put("product_name", product_name);
        //unsortMap.put("valid_time", "300");

        String data=QFPayUtils.getDataString(unsortMap);
        System.out.println("Data:\n"+data+key);
        String md5Sum=QFPayUtils.getMd5Value(data+key);
        System.out.println("Md5 Value:\n"+md5Sum);

        String url="https://openapi-test.qfpay.com";
        String resp= Requests.sendPostRequest(url+"/trade/v1/payment", data, appcode,key);
        System.out.println(resp);
    }
}
// Enter Client Credentials
const environment = 'https://openapi-test.qfpay.com'
const app_code = 'D5589D2A1F2E42A9A60C37*********'
const client_key = '0E32A59A8B454940A2FF39*********'

// Generate Timestamp
var dateTime = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
console.log(dateTime)

// Body Payload
const key = client_key
var tradenumber = String(Math.round(Math.random() * 1000000000))
console.log(tradenumber)

var payload = {
'txamt': '10', // In USD,EUR,etc. Cent
'txcurrcd': 'EUR',
'pay_type': '801101', // Alipay Web Payment = 801101
'out_trade_no': tradenumber,
'txdtm': dateTime,
'mchid': 'ZaMVg*****'
};

// Signature Generation
const ordered = {};
Object.keys(payload).sort().forEach(function(key) {
  ordered[key] = payload[key] });
console.log(ordered)

var str = [];
for (var p in ordered)
if (ordered.hasOwnProperty(p)) {
str.push((p) + "=" + (ordered[p]));
}
var string = str.join("&")+client_key;
console.log(string)

const crypto = require('crypto')
var hashed = crypto.createHash('md5').update(string).digest('hex')
console.log(hashed)


// API Request
var request = require("request");
request({
  uri: environment+"/trade/v1/payment",
  headers: {
    'X-QF-APPCODE': app_code,
    'X-QF-SIGN': hashed
  },
  method: "POST",
  form: payload,
  }, 
  function(error, response, body) {
  console.log(body);
});
<?php
ob_start();
  function GetRandStr($length){
  $str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $len=strlen($str)-1;
  $randstr='';
  for($i=0;$i<$length;$i++){
  $num=mt_rand(0,$len);
  $randstr .= $str[$num];
  }
  return $randstr;
  }

     $url = 'https://test-openapi-eur.qfapi.com';
     $api_type = '/trade/v1/payment';
     $pay_type = '801101'; //Alipay Web Payment = 801101
     //$mchid = "MNxMp11FV35qQN"; //Only agents must provide this parameter
     $app_code = 'FF2FF74F2F2E42769A4A73*********'; //API credentials are provided by QFPay
     $app_key = '7BE791E0FD2E48E6926043B*********'; //API credentials are provided by QFPay
     $now_time = date("Y-m-d H:i:s"); //Get current date-time

     $fields_string = '';
     $fields = array(
      //'mchid' => urlencode($mchid),
      'pay_type' => urlencode($pay_type),
      'out_trade_no' => urlencode(GetRandStr(20)),
      'txcurrcd' => urlencode('EUR'),
      'txamt' => urlencode(2200),
      'txdtm' => $now_time
    );
    ksort($fields); //字典排序A-Z升序方式
    print_r($fields);

    foreach($fields as $key=>$value) { 
  $fields_string .= $key.'='.$value.'&' ;
  }
  $fields_string = substr($fields_string , 0 , strlen($fields_string) - 1);

  $sign = strtoupper(md5($fields_string . $app_key));

  //// Header ////
  $header = array();
  $header[] = 'X-QF-APPCODE: ' . $app_code;
  $header[] = 'X-QF-SIGN: ' . $sign;

  //Post Data
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url . $api_type);
  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);    

  $final_data = json_decode($output, true);
  print_r($final_data);

ob_end_flush();
?>

The above command returns JSON structured like this:

{
  "sysdtm": "2020-04-13 10:30:34", 
  "paydtm": "2020-04-13 10:30:34", 
  "txcurrcd": "THB", 
  "respmsg": "", 
  "pay_type": "801101", 
  "cardcd": "", 
  "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?total_fee=3.0&secondary_merchant_name=###merchant_name###&out_trade_no=20200413000300020087033882&secondary_merchant_industry=7011&service=create_forex_trade&_input_charset=UTF-8&sign=02beb99974ce6167666280b9727c4444&currency=THB&notify_url=https%3A%2F%2Fo2.qfpay.com%2Fonline-test%2Ftrade%2Falipay%2Fv1%2Fonline_notify&order_valid_time=1800&secondary_merchant_id=2565075&sign_type=MD5&partner=2088631377368888&product_code=NEW_OVERSEAS_SELLER&order_gmt_create=2020-04-13+10%3A30%3A34&return_url=&subject=###merchant_name###", 
  "chnlsn": ""
}

Web/WAP Payment

Customers make purchases on a merchant website with Alipay. The user scans the displayed QR code to pay, confimrs the total amount and makes payment. Finally the customer can be redirected to a selected page on the merchant's website using the return_url parameter. Alipay deducts the payment amount from the consumer's Alipay wallet in real-time in CNY and QFPay settles the payment amount to merchants in local currency.

HTTP Request

POST ../trade/v1/payment
PayType: 801101 Overseas Merchants Web
PayType: 801107 Overseas Merchants WAP
PayType: 801501 Hong Kong Merchants Web
PayType: 801512 Hong Kong Merchants WAP

Request Parameters

Parameter name Parameter code Mandatory Type Description
Payment amount txamt Yes Int(11) Amount of the transaction. Unit in cents (i.e. 100 = $1)
Currency txcurrcd Yes String(3) Transaction currency. View the Currencies table for a complete list of available currencies
Payment type pay_type Yes String(6) Alipay Web Payment = 801101
API Order Number out_trade_no Yes String(128) External transaction number / Merchant platform transaction number: This parameter must be unique for each payment and refund request under the same merchant account in the system.
Request transaction time txdtm Yes String(20) Transaction time format:
YYYY-MM-DD hh:mm:ss
Order expiration time expired_time No
(MPM only)
String(3) QRC expiration time in unit minutes. The default expiration time is 30 minutes. The parameter can manually be adjusted to a minimum of 5 minutes, and up to a maximum of 120 minutes.
Available for:
800201 - WeChat scan code
Product name identification goods_name No String(64) Goods Name / Marking: Cannot exceed 20 alphanumeric or contain special characters. Cannot be empty for app payment. Parameter needs to be UTF-8 encoded if it is written in Chinese characters.
QF Pay merchant number mchid No String(16) May or may not be given to merchant. If MCHID is given, it is mandatory to provide the MCHID .On the contrary, if MCHID is not provided, merchants shall not pass the MCHID field in the API request.
Time zone txzone No String(5) Transaction Time zone: Record of the transaction in local time, default time zone is Beijing time UTC+8 (+0800).
Device ID udid No String(40) Unique transaction device ID. Is displayed on the merchant portal.
Redirect URL return_url No String(512) Address for user redirect after successful payment. Mandatory parameter to submit for GrabPay Online. Alipay WAP restricts the return_url to maximum 200 characters.

Response Parameters

Parameter name Parameter code Type Description
Payment type pay_type String(6) Alipay Web/Wap Payment = 801101/801107
System transaction time sysdtm String(20) Format:YYYY-MM-DD hh:mm:ss
This parameter value is used as the cut-off time for settlements.
Request transaction time txdtm String(20) Format:YYYY-MM-DD hh:mm:ss
Response message resperr String(128)
Payment amount txamt Int(11)
Other message information respmsg String(128)
External transaction number out_trade_no String(128) External transaction number
QFPay transaction number syssn String(40)
Return code respcd String(4) 0000 = Request successful.
1143/1145 = merchants are required to continue to query the transaction result.
All other return codes indicate transaction failure. Please refer to the page Transaction Status Codes for a complete list of response codes.
Payment URL pay_url String(512)

Alipay Service Window H5


For code instructions select Python, Java, Node.js or PHP with the tabs above.

#coding=utf8
import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, hashlib
import requests
import datetime
import string

# Enter Client Credentials
environment = 'https://openapi-test.qfpay.com'
app_code = 'D5589D2A1F2E42A9A60C37*********'
client_key = '0E32A59A8B454940A2FF39**********'


# Create parameter values for data payload
current_time = datetime.datetime.now().replace(microsecond=0)                                

print(current_time)

# Create signature
def make_req_sign(data, key):
    keys = list(data.keys())
    keys.sort()
    p = []
    for k in keys: 
        v = data[k]
        p.append('%s=%s'%(k,v))
    unsign_str = ('&'.join(p) + key).encode("utf-8")
    s = hashlib.md5(unsign_str).hexdigest()
    return s.upper()


# Body payload
txamt = '10' #In USD,EUR,etc. Cent
txcurrcd = 'EUR'
pay_type = '801107' # Alipay Wap Payment = 801107
auth_code='283854702356157409' #CPM only
out_trade_no = '01234567890123'
txdtm = current_time
goods_name = 'test1'   
mchid = 'ZaMVg*****'
key = client_key


#data ={'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'goods_name': goods_name, 'mchid': mchid}
data ={'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'mchid': mchid}

r = requests.post(environment+"/trade/v1/payment",data=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, key)})

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="D5589D2A1F2E42A9A60C37*********";
        String key="0E32A59A8B454940A2FF39*********";
        String mchid="ZaMVg*****";

        String pay_type="801107";
        String out_trade_no= "01234567890123";
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date=df.format(new Date());
        String txdtm=date;
        String txamt="10";
        String txcurrcd="EUR";

        Map<String, String> unsortMap = new HashMap<>();
        unsortMap.put("mchid", mchid);
        unsortMap.put("pay_type", pay_type);
        unsortMap.put("out_trade_no", out_trade_no);
        unsortMap.put("txdtm", txdtm);
        unsortMap.put("txamt", txamt);
        unsortMap.put("txcurrcd", txcurrcd);
        //unsortMap.put("product_name", product_name);
        //unsortMap.put("valid_time", "300");

        String data=QFPayUtils.getDataString(unsortMap);
        System.out.println("Data:\n"+data+key);
        String md5Sum=QFPayUtils.getMd5Value(data+key);
        System.out.println("Md5 Value:\n"+md5Sum);

        String url="https://openapi-test.qfpay.com";
        String resp= Requests.sendPostRequest(url+"/trade/v1/payment", data, appcode,key);
        System.out.println(resp);
    }
}
// Enter Client Credentials
const environment = 'https://openapi-test.qfpay.com'
const app_code = 'D5589D2A1F2E42A9A60C37*********'
const client_key = '0E32A59A8B454940A2FF39*********'

// Generate Timestamp
var dateTime = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
console.log(dateTime)

// Body Payload
const key = client_key
var tradenumber = String(Math.round(Math.random() * 1000000000))
console.log(tradenumber)

var payload = {
'txamt': '10', // In USD,EUR,etc. Cent
'txcurrcd': 'EUR',
'pay_type': '801107', // Alipay Wap Payment = 801107
'out_trade_no': tradenumber,
'txdtm': dateTime,
'mchid': 'ZaMVg*****'
};

// Signature Generation
const ordered = {};
Object.keys(payload).sort().forEach(function(key) {
  ordered[key] = payload[key] });
console.log(ordered)

var str = [];
for (var p in ordered)
if (ordered.hasOwnProperty(p)) {
str.push((p) + "=" + (ordered[p]));
}
var string = str.join("&")+client_key;
console.log(string)

const crypto = require('crypto')
var hashed = crypto.createHash('md5').update(string).digest('hex')
console.log(hashed)


// API Request
var request = require("request");
request({
  uri: environment+"/trade/v1/payment",
  headers: {
    'X-QF-APPCODE': app_code,
    'X-QF-SIGN': hashed
  },
  method: "POST",
  form: payload,
  }, 
  function(error, response, body) {
  console.log(body);
});
<?php
ob_start();
  function GetRandStr($length){
  $str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $len=strlen($str)-1;
  $randstr='';
  for($i=0;$i<$length;$i++){
  $num=mt_rand(0,$len);
  $randstr .= $str[$num];
  }
  return $randstr;
  }

     $url = 'https://test-openapi-eur.qfapi.com';
     $api_type = '/trade/v1/payment';
     $pay_type = '801107'; //Alipay Wap Payment = 801107
     //$mchid = "MNxMp11FV35qQN"; //Only agents must provide this parameter
     $app_code = 'FF2FF74F2F2E42769A4A73*********'; //API credentials are provided by QFPay
     $app_key = '7BE791E0FD2E48E6926043B*********'; //API credentials are provided by QFPay
     $now_time = date("Y-m-d H:i:s"); //Get current date-time

     $fields_string = '';
     $fields = array(
      //'mchid' => urlencode($mchid),
      'pay_type' => urlencode($pay_type),
      'out_trade_no' => urlencode(GetRandStr(20)),
      'txcurrcd' => urlencode('EUR'),
      'txamt' => urlencode(2200),
      'txdtm' => $now_time
    );
    ksort($fields); //字典排序A-Z升序方式
    print_r($fields);

    foreach($fields as $key=>$value) { 
  $fields_string .= $key.'='.$value.'&' ;
  }
  $fields_string = substr($fields_string , 0 , strlen($fields_string) - 1);

  $sign = strtoupper(md5($fields_string . $app_key));

  //// Header ////
  $header = array();
  $header[] = 'X-QF-APPCODE: ' . $app_code;
  $header[] = 'X-QF-SIGN: ' . $sign;

  //Post Data
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url . $api_type);
  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);    

  $final_data = json_decode($output, true);
  print_r($final_data);

ob_end_flush();
?>

The above command returns JSON structured like this:

{
  "sysdtm": "2020-04-13 11:32:03", 
  "paydtm": "2020-04-13 11:32:03", 
  "txcurrcd": "THB", 
  "respmsg": "", 
  "pay_type": "801107", 
  "cardcd": "", 
  "udid": "qiantai2", 
  "txdtm": "2020-04-13 11:32:03", 
  "txamt": "300", 
  "resperr": "success", 
  "out_trade_no": "BUFB3PT9ZDUWEUAE4ATD21JKNHVEIIPV", 
  "syssn": "20200413000200020087171988", 
  "respcd": "0000", 
  "pay_url": "https://globalmapi.alipay.com/gateway.do?total_fee=3.0&secondary_merchant_name=###merchant_name###&out_trade_no=20200413000200020087171988&secondary_merchant_industry=7011&service=create_forex_trade_wap&_input_charset=UTF-8&sign=f16ef36efbb55058d1c1d36fef89bcf8&currency=THB&timeout_rule=30m&notify_url=https%3A%2F%2Fo2.qfpay.com%2Fonline-test%2Ftrade%2Falipay%2Fv1%2Fonline_notify&secondary_merchant_id=2565075&sign_type=MD5&partner=2088631377368888&product_code=NEW_WAP_OVERSEAS_SELLER&return_url=&subject=###merchant_name###", 
  "chnlsn": ""
}


Alipay H5 process-flow

Alipay Service Window H5 Payment (WAP)

Alipay Service Window H5 Payment enables merchants to call the Alipay payment module by using the JSAPI interface to collect payments. The customer checks out on the merchant's mobile website in Alipay, confirms the total amount and makes the payment.

HTTP Request

POST ../trade/v1/payment PayType: 800107

Step 1: Get User ID For more details about how to acquire the user id please refer to the official Alipay documentation.

Step 2: Request Payment

Payment Parameters

Parameter name Parameter code Mandatory Parameter type Description
Public payment parameters
Alipay authorization code openid Yes String(64) The user_id is returned by the interface, e.g. 2088802811715388
Redirect URL return_url No String(512) Address for user redirect after successful payment
Designated payment method limit_pay No String Only applicable for mainland China

Response Parameters

Parameter name Secondary parameter code Parameter type Parameter name Description
pay_params tradeNO String Transaction number Provide the transaction number in the call function
txcurrcd String(3) Transaction currency. View the Currencies table for a complete list of available currencies
Public response parameters

Step 3: Payout through the cashout interface For more information regarding the cashout interface please refer to the official Alipay documentation.

Alipay Pre-Authorization

Freeze Funds

At the moment only Alipay wallet funds can be used for pre-authorization, credit-cards are not supported. Authorization requests lose their validity after 15min. In case of technical or currency related integration difficulties please contact technical.support@qfpay.com for support. Merchants can, at any time, unfreeze the funds in which case the assets will be available for spending on the original wallet. In addition, merchants can initiate a transfer for a fraction or all of the frozen funds in order to collect money for open customer invoices.


Alipay Pre-Auth process-flow

HTTP Request

POST ../trade/v1/payment

Find the correct pay_type for your checkout szenario from the table below.

PayType Description
801801 Alipay Pre-Authorization in-store QRC Payment - Consumer Present Mode (CPM)
801808 Alipay Pre-Authorization in-store QRC Payment - Merchant Present Mode (MPM)
801810 Alipay Pre-Authorization in-APP Payment
801814 Alipay Pre-Authorization Online Payment

Request Parameters


Request Body:

{
  goods_name=goodcode1&mchid=R1zQrTdJnn&out_trade_no=alipay201909261129164551bcdd40&pay_type=801802&txamt=1&txcurrcd=USD&txdtm=2019-09-26 11:29:16&txzone=+0800
}

The above command returns JSON structured like this:

{
  "pay_type": "801802", 
  "sysdtm": "2019-09-26 11:29:18", 
  "paydtm": "2019-09-26 11:29:19", 
  "txdtm": "2019-09-26 11:29:16", 
  "udid": "qiantai2", 
  "txcurrcd": "USD", 
  "txamt": "1", 
  "resperr": "Network busy, don't worry, we are fixing it (1297)", 
  "respmsg": "预授权发码参数异常或参数缺失", 
  "out_trade_no": "alipay201909261129164551bcdd40", 
  "syssn": "20190926000200020016004244", 
  "respcd": "1297", 
  "chnlsn": "", 
  "cardcd": ""
}
Parameter name Parameter code Mandatory Parameter type Description
Public payment parameter
Alipay openid openid No String(64) Corresponding to the APP authorization method.
Alipay payment code auth_code No String(128) Specifies the authorization code for scanning a barcode/QR Code. The auth_code returned is unique in each authorization. Each auth_code can only be used once and will automatically expire. For testing CPM with Alipay and WeChat Pay the auth_code can be extracted by any QRC reader or manually found in the consumer wallet below the barcode.

Response Parameters

Parameter code Second parameter code Parameter type Parameter name Description
Public response parameters

Unfreeze Funds

Only calls alipay.fund.auth.operation.cancel when the merchant’s system encounters timeout and has to stop the subsequent processes, or when the pre-auth result is unknown. If you want to perform a similar task for normal pre-auth (freezing) transactions, please call alipay.fund.auth.order.unfreeze. After submitting the fund authorization call Order Inquiry, and there is no clear authorization result and then call Fund Authorization Cancellation.

HTTP Request

POST ../trade/v1/reversal

Request Parameters


Request Body:

{
  mchid=R1zQrTd***&syssn=20190722000300020081074842
}

The above command returns JSON structured like this:

{
  "respmsg": "", 
  "resperr": "请求成功",
  "respcd": "0000",
  "syssn": "20190722000302320081074842",
  "sysdtm": "2019-07-22 15:20:54",
  "txamt": "10",
  "txdtm": "2019-07-22 15:20:54",
  "cardcd": "",
  "txcurrcd": "HKD",
  "orig_syssn": "20190722000300020081074842",
  "respmsg": ""
}
Parameter name Parameter code Mandatory Parameter type Description
Merchant ID mchid Yes String The unique merchant ID is created by QF Pay during the merchant onboarding process.
QF Pay transaction number syssn No String Multiple entries are separated by English commas
External transaction number out_trade_no No String e.g. Developer platform order number
Transaction amount txamt No Int Whether to pass this parameter depends on the payment channel, Alipay and WeChat Pay do not need to submit this information
Transaction request time txdtm Yes String Format: YYYY-MM-dd hh:mm:ss
Unique device id udid No String
Time zone txzone No String Used to record the local order time. The default is Beijing time GMT+8 (+0800)

Response Parameter

Parameter code Parameter type Parameter name Description
syssn String(40) QF Pay transaction number
orig_syssn String(40) External transaction number Developer platform transaction number
txdtm String(20) Time of the transaction request Format: YYYY-MM-dd hh:mm:ss
txamt Int(11) Order payment amount
sysdtm String(20) System trading time Format: YYYY-MM-dd hh:mm:ss
This parameter value is used as the cut-off time for settlements.
respcd String(4) Return code
respmsg String(128) Information description
resperr String(128) Description error
cardcd String Card number
txcurrcd String(3) Currency Transaction currency. View the Currencies table for a complete list of available currencies

Deduct Funds

HTTP Request

POST ../trade/v1/authtrade

Request Parameters


Request Body:

{
  mchid=R1zQrTd***&syssn=20190722000300020081074842&out_trade_no=alipay201909271528139576015cbf&txamt=1&txdtm=2019-09-27 15:28:13&txzone=+0800
}

The above command returns JSON structured like this:

{
  "respmsg": "", 
  "resperr": "请求成功",
  "respcd": "0000",
  "syssn": "20190722000302320081074842",
  "sysdtm": "2019-07-22 15:20:54",
  "txamt": "10",
  "txdtm": "2019-07-22 15:20:54",
  "cardcd": "",
  "txcurrcd": "HKD",
  "orig_syssn": 20190722000300020081074842
}
Parameter name Parameter code Mandatory Parameter type Description
Merchant ID mchid No String The unique merchant ID is created by QF Pay during the merchant onboarding process.
QF Pay transaction number syssn Yes String Fund authorization number
External transaction number out_trade_no Yes String Developer platform transaction number
Transaction amount txamt Yes int The actual amount of consumption, the maximum deduction amount cannot exceed the fozen funds
Transaction request time txdtm Yes String Format: YYYY-MM-DD hh:mm:ss
Device ID udid No String Must be unique
Time zone txzone No String Used to record the local order time. The default is Beijing time GMT+8 (+0800)
Redirect URL return_url No String Redirect to address after successful payment. Mandatory parameter to submit for GrabPay Online. Alipay WAP restricts the return_url to maximum 200 characters.

Response Parameters

Parameter code Parameter type Parameter name Description
syssn String(40) QF Pay Transaction number This number is being used when freezing funds, detucting money from the frozen amount as well as unfreezing funds.
orig_syssn String(40) External transaction number Developer platform transaction number
txdtm String(20) Transaction request time Format: YYYY-MM-DD hh:mm:ss
txamt Int(11) Transaction amount
sysdtm String(20) System transaction time Format: YYYY-MM-DD hh:mm:ss
respcd String(4) Return code
respmsg String(128) Information description
resperr String(128) Description error
cardcd String Card number
txcurrcd String Currency Transaction currency. View the Currencies table for a complete list of available currencies

Alipay in-APP Payments


Alipay APP Payment process-flow

To download Alipay Oversea SDK , please refer to this link.
To download Alipay HK SDK, please refer to this link.
To know how to trigger Alipay HK SDK , please refer to this link.

HTTP Request

POST ../trade/v1/payment
PayType: 801110 Oversea Merchants
PayType: 801510 Hong Kong Merchants

Request Parameters


Request Body:

txamt=1&txcurrcd=HKD&pay_type=801510&out_trade_no=052711570017898&txdtm=2021-05-27+11%3A57%3A00&goods_name=goods_name&goods_info=goods_info&mchid=nDB64h9qJ1An&trade_name=trade_name&goods_detail=goods_detail&return_url=http%3A%2F%2Fwww.qfpay.com%2F&pay_tag=ALIPAYHK&seller_id=testoverseas9191%40alipay.com

QFPay Response:

{
  "pay_type": "801510",
  "sysdtm": "2021-05-27 11:57:02",
  "paydtm": "2021-05-27 11:57:02",
  "udid": "qiantai2",
  "txcurrcd": "HKD",
  "txdtm": "2021-05-27 11:57:00",
  "txamt": "1",
  "resperr": "交易成功",
  "respmsg": "",
  "out_trade_no": "052711570017898",
  "syssn": "20210527154100020004180921",
  "pay_params": {
    "body": "goods_info",
    "forex_biz": "FP",
    "seller_id": "2088231067382451",
    "secondary_merchant_id": "1000007081",
    "service": "mobile.securitypay.pay",
    "payment_inst": "ALIPAYHK",
    "it_b_pay": "30m",
    "secondary_merchant_name": "IFlare Hong Kong Limited (external) - online",
    "_input_charset": "UTF-8",
    "sign": "iU1yXUnsCK7rJAu0DoN61arVexbIfo3GLR5jr3QzjkZ29INSPhcA4e%2F2%2BdPrsf5huzQAkxVKP0CTfvaGPMYqNkxmhoaJWUH0ZhgYDgKugMvtweBvRqOX2W0h3A%2F%2FIdJuxeyOAuh7bHiuazSB3ZH%2BEQwRGP%2Bkk8Jpha930gHwPtw%3D",
    "currency": "HKD",
    "out_trade_no": "20210527154100020004180921",
    "payment_type": "1",
    "total_fee": 0.01,
    "sign_type": "RSA",
    "notify_url": "https://test-o2-hk.qfapi.com/trade/alipay_hk/v1/notify",
    "partner": "2088231067382451",
    "secondary_merchant_industry": "5941",
    "product_code": "NEW_WAP_OVERSEAS_SELLER",
    "return_url": "http://www.qfpay.com/",
    "subject": "goods_name"
  },
  "respcd": "0000",
  "chnlsn": "",
  "cardcd": ""
}
Request using Alipay SDK:

(After you receive the content of pay_params, when you call Alipay SDK, 
the orderinfo request parameters need to be adjusted in the following format:
Combine all the array values in the format of key="value", request parameters 
in ascending order of parameter name, then use "&" to link the parameters, 
"sign" and "sign_type" parameters need to be placed at the end.) 

Sample:

_input_charset="UTF-8"&body="goods_info"&currency="HKD"&forex_biz="FP"&it_b_pay="30m"&notify_url="https://test-o2-hk.qfapi.com/trade/alipay_hk/v1/notify"&out_trade_no="20210527154100020004180921"&partner="2088231067382451"&payment_inst="ALIPAYHK"&payment_type="1"&product_code="NEW_WAP_OVERSEAS_SELLER"&return_url="http://www.qfpay.com/"&secondary_merchant_id="1000007081"&secondary_merchant_industry="5941"&secondary_merchant_name="IFlare Hong Kong Limited (external) - online"&seller_id="2088231067382451"&service="mobile.securitypay.pay"&subject="goods_name"&total_fee="0.01"&sign="iU1yXUnsCK7rJAu0DoN61arVexbIfo3GLR5jr3QzjkZ29INSPhcA4e%2F2%2BdPrsf5huzQAkxVKP0CTfvaGPMYqNkxmhoaJWUH0ZhgYDgKugMvtweBvRqOX2W0h3A%2F%2FIdJuxeyOAuh7bHiuazSB3ZH%2BEQwRGP%2Bkk8Jpha930gHwPtw%3D"&sign_type="RSA"

Parameter name Parameter code Mandatory Parameter type Description
Public payment parameters
Product description goods_info No String Must not contain special characters
Payment mark pay_tag No String(16) The default value is: ALIPAYHK
Alipay Continental version: ALIPAYCN
801103 - Alipay overseas online refund (QF_BUSICD_ALIPAY_ONLINE_REFUND)
801104 - Alipay overseas online inquiry (QF_BUSICD_ALIPAY_ONLINE_QUERY)
801110 - Alipay overseas online APP payment (QF_BUSICD_ALIPAY_ONLINE_APP)
801501 - Alipay Hong Kong pc scan code
801512 - Alipay Hong Kong Wap payment
801510 - Alipay Hong Kong APP payment
Order expiration time expired_time No
(MPM only)
String(3) QRC expiration time in unit minutes. The default expiration time is 30 minutes. The parameter can manually be adjusted to a minimum of 5 minutes, and up to a maximum of 120 minutes.
Available for:
800201 - WeChat scan code
800101 - Alipay scan code
801512 - Alipay Hong Kong Wap payment
801501 - Alipay Hong Kong scan code
801107 - Alipay overseas Wap payment
801101 - Alipay overseas scan code
801010 - WeChat Hong Kong APP
801510 - Alipay Hong Kong APP

Response Parameters

Parameter code Secondary parameter code Parameter name
pay_params partner Partner
seller_id Unique Alipay user number referencing the Alipay payment account
subject Product name / transaction number / order number / order keyword, etc.
body A specific description of a transaction. If it refers to a basket of products, please accumulate the product description string in the body.
total_fee Total amount
notify_url Notification address
service Service
cardcd Card number
payment_type Payment type
_input_charset Encoding format
it_b_pay Custom timeout parameter
return_url Redirect URL
payment_inst Payment institution
currency Currency
product_code Product code
sign Required or not
sign_type Signature type
secondary_merchant_id Secondary merchant identification
secondary_merchant_name Secondary business name
secondary_merchant_industry Secondary merchant industry
chnlsn Channel coding
Public response parameters

WeChat Web QRC Payments


For code instructions select Python, Java, Node.js or PHP with the tabs above.

#coding=utf8
import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, hashlib
import requests
import datetime
import string

# Enter Client Credentials
environment = 'https://openapi-test.qfpay.com'
app_code = 'D5589D2A1F2E42A9A60C37*********'
client_key = '0E32A59A8B454940A2FF39**********'


# Create parameter values for data payload
current_time = datetime.datetime.now().replace(microsecond=0)                                

print(current_time)

# Create signature
def make_req_sign(data, key):
    keys = list(data.keys())
    keys.sort()
    p = []
    for k in keys: 
        v = data[k]
        p.append('%s=%s'%(k,v))
    unsign_str = ('&'.join(p) + key).encode("utf-8")
    s = hashlib.md5(unsign_str).hexdigest()
    return s.upper()


# Body payload
txamt = '10' #In USD,EUR,etc. Cent
txcurrcd = 'EUR'
pay_type = '800201'
auth_code='283854702356157409' #CPM only
out_trade_no = '01234567890123'
txdtm = current_time
goods_name = 'test1'   
mchid = 'ZaMVg*****'
key = client_key


#data ={'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'goods_name': goods_name, 'udid': udid, 'mchid': mchid}
data ={'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'mchid': mchid}

r = requests.post(environment+"/trade/v1/payment",data=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, key)})

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="D5589D2A1F2E42A9A60C37*********";
        String key="0E32A59A8B454940A2FF39*********";
        String mchid="ZaMVg*****";

        String pay_type="800201";
        String out_trade_no= "01234567890123";
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date=df.format(new Date());
        String txdtm=date;
        String txamt="10";
        String txcurrcd="EUR";

        Map<String, String> unsortMap = new HashMap<>();
        unsortMap.put("mchid", mchid);
        unsortMap.put("pay_type", pay_type);
        unsortMap.put("out_trade_no", out_trade_no);
        unsortMap.put("txdtm", txdtm);
        unsortMap.put("txamt", txamt);
        unsortMap.put("txcurrcd", txcurrcd);
        //unsortMap.put("product_name", product_name);
        //unsortMap.put("valid_time", "300");

        String data=QFPayUtils.getDataString(unsortMap);
        System.out.println("Data:\n"+data+key);
        String md5Sum=QFPayUtils.getMd5Value(data+key);
        System.out.println("Md5 Value:\n"+md5Sum);

        String url="https://openapi-test.qfpay.com";
        String resp= Requests.sendPostRequest(url+"/trade/v1/payment", data, appcode,key);
        System.out.println(resp);
    }
}
// Enter Client Credentials
const environment = 'https://openapi-test.qfpay.com'
const app_code = 'D5589D2A1F2E42A9A60C37*********'
const client_key = '0E32A59A8B454940A2FF39*********'

// Generate Timestamp
var dateTime = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
console.log(dateTime)

// Body Payload
const key = client_key
var tradenumber = String(Math.round(Math.random() * 1000000000))
console.log(tradenumber)

var payload = {
'txamt': '10', // In USD,EUR,etc. Cent
'txcurrcd': 'EUR',
'pay_type': '800201',
'out_trade_no': tradenumber,
'txdtm': dateTime,
'mchid': 'ZaMVg*****'
};

// Signature Generation
const ordered = {};
Object.keys(payload).sort().forEach(function(key) {
  ordered[key] = payload[key] });
console.log(ordered)

var str = [];
for (var p in ordered)
if (ordered.hasOwnProperty(p)) {
str.push((p) + "=" + (ordered[p]));
}
var string = str.join("&")+client_key;
console.log(string)

const crypto = require('crypto')
var hashed = crypto.createHash('md5').update(string).digest('hex')
console.log(hashed)


// API Request
var request = require("request");
request({
  uri: environment+"/trade/v1/payment",
  headers: {
    'X-QF-APPCODE': app_code,
    'X-QF-SIGN': hashed
  },
  method: "POST",
  form: payload,
  }, 
  function(error, response, body) {
  console.log(body);
});
<?php
ob_start();
  function GetRandStr($length){
  $str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $len=strlen($str)-1;
  $randstr='';
  for($i=0;$i<$length;$i++){
  $num=mt_rand(0,$len);
  $randstr .= $str[$num];
  }
  return $randstr;
  }

     $url = 'https://test-openapi-eur.qfapi.com';
     $api_type = '/trade/v1/payment';
     $pay_type = '800201';
     //$mchid = "MNxMp11FV35qQN"; //Only agents must provide this parameter
     $app_code = 'FF2FF74F2F2E42769A4A73*********'; //API credentials are provided by QFPay
     $app_key = '7BE791E0FD2E48E6926043B*********'; //API credentials are provided by QFPay
     $now_time = date("Y-m-d H:i:s"); //Get current date-time

     $fields_string = '';
     $fields = array(
      //'mchid' => urlencode($mchid),
      'pay_type' => urlencode($pay_type),
      'out_trade_no' => urlencode(GetRandStr(20)),
      'txcurrcd' => urlencode('EUR'),
      'txamt' => urlencode(2200),
      'txdtm' => $now_time
    );
    ksort($fields); //字典排序A-Z升序方式
    print_r($fields);

    foreach($fields as $key=>$value) { 
  $fields_string .= $key.'='.$value.'&' ;
  }
  $fields_string = substr($fields_string , 0 , strlen($fields_string) - 1);

  $sign = strtoupper(md5($fields_string . $app_key));

  //// Header ////
  $header = array();
  $header[] = 'X-QF-APPCODE: ' . $app_code;
  $header[] = 'X-QF-SIGN: ' . $sign;

  //Post Data
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url . $api_type);
  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);    

  $final_data = json_decode($output, true);
  print_r($final_data);

ob_end_flush();
?>

The above command returns JSON structured like this:

{
  "sysdtm": "2020-04-10 11:45:44", 
  "paydtm": "2020-04-10 11:45:44", 
  "txcurrcd": "THB", 
  "respmsg": "OK", 
  "qrcode": "weixin://wxpay/bizpayurl?pr=4PsXP5N", 
  "pay_type": "800201", 
  "cardcd": "", 
  "udid": "qiantai2", 
  "txdtm": "2020-04-10 11:45:44", 
  "txamt": "300", 
  "resperr": "success", 
  "out_trade_no": "3Z6HPCS6RN54J2Y8LUQM8RBDVBA9URYE", 
  "syssn": "20200410000300020086358791", 
  "respcd": "0000", 
  "chnlsn": ""
  }

Online QR Code Payment process-flow

Customers can use WeChat's "Scan" feature to scan a payment code generated by a merchant on a web page to make a payment. Web payments allows order information to be embedded in a unique QR code. By scanning the code in WeChat, users complete the payment after passing obligatory security checks.

Optionally merchants can activate real-name authentication with WeChat. Currently real-name identification is only available for Mainland Chinese citizens and include a person's real name and national ID card number. In case identification is provided the payer's wallet information like a connected bank card must be identical with the data provided by merchants. If customers did not yet bind their WeChat account to a bank card the payment will go through regardless.

HTTP Request

POST ../trade/v1/payment PayType: 800201

Request Parameters

Parameter name Parameter code Secondary parameter Mandatory Type Description
Payment amount txamt Yes Int(11) Amount of the transaction. Unit in cents (i.e. 100 = $1)
Currency txcurrcd Yes String(3) Transaction currency. View the Currencies table for a complete list of available currencies
Payment type pay_type Yes String(6) WeChat online payments PayType 800201
API Order Number out_trade_no Yes String(128) External transaction number / Merchant platform transaction number: This parameter must be unique for each payment and refund request under the same merchant account in the system.
Request transaction time txdtm Yes String(20) Transaction time format:
YYYY-MM-DD hh:mm:ss
Order expiration time expired_time No
(MPM only)
String(3) QRC expiration time in unit minutes. The default expiration time is 30 minutes. The parameter can manually be adjusted to a minimum of 5 minutes, and up to a maximum of 120 minutes.
Available for:
800201 - WeChat scan code
Product name identification goods_name No String(64) Goods Name / Marking: Cannot exceed 20 alphanumeric or contain special characters. Cannot be empty for app payment. Parameter needs to be UTF-8 encoded if it is written in Chinese characters.
QF Pay merchant number mchid No String(16) May or may not be given to merchant. If MCHID is given, it is mandatory to provide the MCHID .On the contrary, if MCHID is not provided, merchants shall not pass the MCHID field in the API request.
Time zone txzone No String(5) Transaction Time zone: Record of the transaction in local time, default time zone is Beijing time UTC+8 (+0800).
Device ID udid No String(40) Unique transaction device ID. Is displayed on the merchant portal.
RMB Tag rmb_tag No String(1) WeChat Pay in Hong Kong uses rmb_tag = Y together with txcurrcd = CNY to indicate that the transaction currency is RMB.
Extended Customer Info extend_info user_creid
user_truename
No Object Real name customer identification. This parameter is currently only available for Mainland Chinese citizens and needs to be explicitly activated with WeChat for the selected PayType. The consumer's national ID card number is contained in the parameter user_creid and the payer's real name in encoded form or written in Chinese characters must be provided in user_truename. An example looks like this; extend_info = '{"user_creid":"430067798868676871","user_truename":"\\u5c0f\\u6797"}'

Response Parameters

Parameter name Parameter code Type Description
Payment type pay_type String(6) WeChat online payments PayType 800201
System transaction time sysdtm String(20) Format:YYYY-MM-DD hh:mm:ss
This parameter value is used as the cut-off time for settlements.
Request transaction time txdtm String(20) Format:YYYY-MM-DD hh:mm:ss
Response message resperr String(128)
Payment amount txamt Int(11)
Other message information respmsg String(128)
External transaction number out_trade_no String(128) External transaction number
QFPay transaction number syssn String(40)
Return code respcd String(4) 0000 = Request successful.
1143/1145 = merchants are required to continue to query the transaction result.
All other return codes indicate transaction failure. Please refer to the page Transaction Status Codes for a complete list of response codes.

WeChat Pay JSAPI (in wechat browser)


WeChat JSAPI process-flow

JSAPI Payment Types

Note: Merchants in Canada, please refer to this section for payment request and response parameters with pay_type 800207.

There are two different methods how JSAPI payments can be implemented.


1. JSAPI with Real Name Authenticated Official Accounts

For this kind of integration, merchants shall register their own official account with WeChat and we will bind the official account to the merchant's QF Pay payment account. In this case merchants can create and publish their own content, access customer information and collect their own followers. When choosing this implementation method, merchants have to acquire the oauth_code, user openid and trigger WeChat Pay via the official WeChat platform. Merchants only need to refer to the QF Pay transaction enquiry API endpoint.

Step 1: WeChat official account payments are available to developers after they completed real name authentication on the WeChat official account platform. Once authentication has been completed developers can obtain the openid parameter of the certified public account. Please refer to the official WeChat documentation for more information.

Step 2: Request the QFPAY order payment API /trade/v1/payment by providing the appointed openid and return the pay_params data, for further instructions please refer to the API Endpoint for Payments.

Step 3: Open JSAPI Payment Authorization Directory at the time of the merchant certification application to initiate payments. For more details please refer to the official WeChat Pay documentation.


2. JSAPI without a Real Name Registered Official Account

For this kind of payment, merchants can build upon QF Pay's official account. This integration is only applicable to merchants who are using the indirect settlement option (i.e. settlement is provided by QFPay). For this implementation, merchants shall use QFPay's API to get the oauth_code, user openid and trigger WeChat Pay as described below.

GET oauth_code

GET WeChat oauth_code request:

{
  https://openapi-test.qfpay.com/tool/v1/get_weixin_oauth_code?app_code=5D81D64E602043F7AF51CEXXXXXXXXXX&sign=F4D8FB00894F213993B33116BC1B4E10&redirect_uri=https://sdk.qfapi.com
}
import hashlib
import requests
from flask import Flask, redirect
from flask import request
import json
import random
import datetime
import string
import urllib
import urllib.parse

# Enter Client Credentials
environment = 'https://openapi-test.qfpay.com'
app_code = "******"
client_key = "******"

# Create MD5 signature 
def make_req_sign(data, key):
    keys = list(data.keys())
    keys.sort()
    p = []
    for k in keys: 
        v = data[k]
        p.append('%s=%s'%(k,v))
    unsign_str = ('&'.join(p) + key).encode("utf-8")
    s = hashlib.md5(unsign_str).hexdigest()
    return s.upper()

def get_out_code():
    # Body payload
    redirect_uri = 'http://49ae4dbd47a6.ngrok.io/getcode'  
    data = {'app_code': app_code, 'redirect_uri': redirect_uri}   
    sign = make_req_sign(data, client_key)

    return environment+"/tool/v1/get_weixin_oauth_code?app_code="+app_code+"&sign="+sign+"&redirect_uri="+redirect_uri #+"&mchid="+mchid

Redirect to URL after the GET oauth_code request has been successful:

{
  "http://xg.fshop.top/index.php/wap/pay/wxredirect?showwxpaytitle=1&code=011QipnO1yMIla1VJdoO1FUrnO1Qipnv"
}

HTTP Request

GET ../tool/v1/get_weixin_oauth_code

Both the app_code and sign have to be submitted as parameters instead of in the http header. The URL request has to be send in the WeChat environment. Everytime a payment is initiated the WeChat oauth_code and openid have to be obtained again.

Request Parameters

Parameter name Parameter code Mandatory Parameter type Description
Developer ID app_code Yes String(32) The app_code is assigned to partners by QFPay
Callback URL redirect_uri Yes String(512) After the request has been successful the user will be redirected to the callback address
Merchant ID mchid No String(16) The mchid is a unique identification for every merchant assigned by QFPay
Signature sign Yes String Signature obtained according to the unified framework

GET openid


HTTP Request:

{
  https://openapi.qfpay.com/tool/v1/get_weixin_openid?code=011QipnO1yMIla1VJdoO1FUrnO1Qipnv
}

def get_open_id(data):

    try:
        r = requests.get(environment+"/tool/v1/get_weixin_openid",params=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, client_key)})
        print (r.request.url)
        print (r.content)
        if r.json()["respcd"]=="0000":
            return r.json()["openid"]
        else:
            pass
    except:
        print("An exception occurred")

The above command returns JSON structured like this:

{
  "resperr": "",
  "respcd": 0000,
  "respmsg": "",
  "openid": "oo3Lss8d0hLOuyTuSJMVwLTk68JE"
}

HTTP Request

GET ../tool/v1/get_weixin_openid

Request Parameters

Parameter code Secondary parameter code Mandatory Parameter type Description
WeChat oauth_code code Yes String The code is returned by the GET oauth_code request. It is unique and can only be used once.
Merchant ID mchid No String(16) The mchid is a unique identification for every merchant assigned by QFPay

Response Parameters

Parameter code Secondary parameter code Parameter type Parameter name Description
openid String(64) WeChat openid Every WeChat user is assigned a unique openid

POST Payments

For code instructions select Python with the tabs above.
def payment(openid):
    # Create parameter values for data payload
    current_time = datetime.datetime.now().replace(microsecond=0)                                
    # Body payload
    txamt = '1' #In USD,EUR,etc. Cent
    txcurrcd = 'THB'
    pay_type = '800207' 
    letters = string.digits   
    out_trade_no = ''.join(random.choice(letters) for i in range(20)) 
    txdtm = current_time
    key = client_key


    data = {'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'sub_openid':openid}    

    try:
        r = requests.post(environment+"/trade/v1/payment",params=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, key)})
        if r.json()["respcd"]=="0000":

            return r.json()['pay_params']
        else:
            pass
    except:
        print("An exception occurred")


app = Flask(__name__)

@app.route("/payment",methods=['GET', 'POST'])
def api_payment():

    if "MichroMessenger" in request.headers.get('User-Agent'):  #get an oauth_code
        print (get_out_code())
        return redirect(get_out_code(), code=302)    

@app.route("/getcode",methods=['GET', 'POST'])
def api_get_code():      
    print ("------------------------------------")
    print (request.args)                      
    print (request.args.get("code"))
    code = request.args.get('code')
    print (code)
    if code != "":    # user returned with oauth_code      

        sub_openid=get_open_id({"code": code})  # get open id using oauth_code
        param=payment(sub_openid)   # payment request to QFPay

        # add necessary parameters and redirect
        param["mchntnm"]="Pet Shop"
        param["txamt"]="1"
        param["currency"]="THB"
        param["redirect_url"]="www.example.com"
        return redirect("https://o2-th.qfapi.com/q/direct?"+urllib.parse.urlencode(param), code=302)             # direct user"""
    else:
        print("unable to obtain code")
        return     

if __name__ == '__main__':
    app.run(host="127.0.0.1",port = 80)

Optionally merchants can activate real-name authentication with WeChat. Currently real-name identification is only available for Mainland Chinese citizens and include a person's real name and national ID card number. In case identification is provided the payer's wallet information like a connected bank card must be identical with the data provided by merchants. If customers did not yet bind their WeChat account to a bank card the payment will go through regardless.

HTTP Request

POST ../trade/v1/payment PayType: 800207

Request Parameters

Parameter name Parameter code Mandatory Parameter type Description
Public payment parameters Refer to the general documentation about transactions
WeChat authorization code sub_openid Yes String WeChat OpenID. Refer to the GET openid documentation
Designated payment method limit_pay No String Used to limit credit card transactions
Extended Customer Info extend_info No Object Real name customer identification. This parameter is currently only available for Mainland Chinese citizens and needs to be explicitly activated with WeChat for the selected PayType. The consumer's national ID card number is contained in the parameter user_creid and the payer's real name in encoded form or written in Chinese characters must be provided in user_truename. An example looks like this; extend_info = '{"user_creid":"430067798868676871","user_truename":"\\u5c0f\\u6797"}'

Response Parameters

Parameter code Secondary parameter code Parameter type Parameter name Description
pay_params appId String(16) Public number id The App ID is provided by Tencent once developers register their Mini Program on the WeChat developer portal
timeStamp String(32) Timestamp Current time
nonceStr String(32) Random string Random string with no more than 32 bits
package String(128) Transaction details The value of the prepay_id parameter returned by the interface has the format: prepay_id=**
signType String(32) Signature method Signature method, default is MD5
paySign String(64) Signature Signature method, default is MD5
Public response parameters
txcurrcd String(3) Transaction currency. View the Currencies table for a complete list of available currencies

GET WeChat Pay Data

HTTP Request

GET https://o2.qfpay.com/q/direct

Request Parameters

Parameter code Mandatory Parameter type Description
mchntnm Yes String(128) Custom business name. Parameter needs to be UTF-8 encoded if it is written in Chinese characters
txamt Yes Int(11) Amount
currency Yes String(3)
goods_name No String(64) Custom goods name. Parameter needs to be UTF-8 encoded if it is written in Chinese characters
redirect_url Yes String(512) Redirect URL after Payment is complete. Urlencode handles this parameter
package Yes String(128) Parameter return from WeChat after calling the payment API
timeStamp Yes String(32) Parameter return from WeChat after calling the payment API
signType Yes String(32) Parameter return from WeChat after calling the payment API
paySign Yes String(64) Parameter return from WeChat after calling the payment API
appId Yes String(16) Parameter return from WeChat after calling the payment API
nonceStr Yes String(32) Parameter return from WeChat after calling the payment API

WeChat Pay H5 (in mobile browser)


WeChat H5 process-flow

HTTP Request

POST ../trade/v1/payment PayType: 800212

Request Parameters

Parameter name Parameter code Mandatory Parameter type Description
Public payment parameters Refer to the general documentation about transactions
Extended Customer Info extend_info Yes Object
extend_info:
{"scene_info":{
                "h5_info": { // h5支付固定传"h5_info"
                             "type": "Wap", //场景类型
                              "wap_url": "https://qfpay.com/h5/pay", //WAP网站URL地址
                              "wap_name": "qfpay" //WAP 网站名
                            }              },
  "spbill_create_ip": "192.168.1.10"// 用户真实ip地址获取指引 https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_5
}


extend_info:

Parameter code Parameter code Parameter code Mandatory Parameter type Description
scene_info Yes Object
h5_info Yes Object
type Yes String scene type "Wap"
wap_url Yes String mobile website address
wap_name Yes String mobile website name
spbill_create_ip Yes String IP address of user

Response Parameters

Parameter code Secondary parameter code Parameter Type Parameter name Description
Public response parameters
Payment URL pay_url Yes String

pay_url

https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096

Payment URL after redirect_url inserted

https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096
&redirect_url=https%3A%2F%2Fwww.wechatpay.com.cn

WeChat Mini Programs


WeChat MiniProgram process-flow

HTTP Request

POST ../trade/v1/payment PayType: 800213

Step 1: WeChat real name authentification Before the payment function within WeChat can be used the business personnel must authenticate themselves on the official WeChat platform.

Step 2: Get openid Once real name authentication has been completed, the openid parameter is obtained through the small program of the real name of the merchant. The specific acquisition method is described in the Wechat documentation.

Step 3: Send payment request Initiate a payment request with the parameters below.

Optionally merchants can activate real-name authentication with WeChat. Currently real-name identification is only available for Mainland Chinese citizens and include a person's real name and national ID card number. In case identification is provided the payer's wallet information like a connected bank card must be identical with the data provided by merchants. If customers did not yet bind their WeChat account to a bank card the payment will go through regardless.

For code instructions select Node.js with the tabs above.
qfPayOpenAPI: function () {
    let app_code = 'A2BE4E015A8A4B0A8E9D88**********';
    let client_key = '498717301B0846D1992B6F**********';
    let environment = 'https://openapi-sg.qfapi.com/trade/v1/payment';
    let openid = this.data.openid;
    let amount = this.data.amount * 100;
    let random_number = String(Math.round(Math.random() * 1000000000));
    let datetime = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '');

    let payload = {
      txamt: 100,
      txcurrcd: 'SGD',
      pay_type: '800213',
      out_trade_no: '0123456789',
      txdtm: '2020-07-03 03:14:29',
      sub_openid: 'oS80_5dxekECAOlVBeQFk34q123s'
    };

    var ordered = {};
    Object.keys(payload).sort().forEach(function(key) {
      ordered[key] = payload[key] });
    console.log(ordered)

    var str = [];
    for (var p in ordered)
    if (ordered.hasOwnProperty(p)) {
    str.push((p) + "=" + (ordered[p]));
    }
    var string = str.join("&")+client_key;
    console.log(string)

    var signature = utilMd5.hexMD5(string).toUpperCase()
    console.log(signature)

    wx.request({
      url: environment,
      data: payload,
      method: 'POST',
      header: {
        'X-QF-APPCODE': app_code,
        'X-QF-SIGN': signature,
        'content-Type': 'application/x-www-form-urlencoded'
      },
      success: (res) => {
        if (res.statusCode == 200) {
          console.log(res)
          console.log(res.data)
          this.weChatPayment(res);
        }
      },
      fail: (err) => {
        console.log(err);
      },
      complete: (res) => {
        wx.hideLoading();
        console.log("API request completed")
      }
    })
   },

Request Parameters

Parameter name Parameter code Mandatory Parameter type Description
Public payment parameters Refer to the public payment API documentation
WeChat authorization code sub_openid Yes String(128)
Order expiration time expired_time No String(3) QRC expiration time in unit minutes. The default QRC expiration time for WeChat Mini Programs is 30 minutes. The parameter can manually be adjusted to a minimum of 5 minutes, and up to a maximum of 120 minutes.
Designated payment method limit_pay No String The parameter value is specified as no_credit, and credit card payment is prohibited. This setting is only valid for mainland China.
Extended Customer Info extend_info No Object Real name customer identification. This parameter is currently only available for Mainland Chinese citizens and needs to be explicitly activated with WeChat for the selected PayType. The consumer's national ID card number is contained in the parameter user_creid and the payer's real name in encoded form or written in Chinese characters must be provided in user_truename. An example looks like this; extend_info = '{"user_creid":"430067798868676871","user_truename":"\\u5c0f\\u6797"}'

Response Parameters

Parameter code Secondary parameter code Parameter Type Parameter name Description
pay_params appId String(16) Public WMP ID After the developer registers the Mini Program with the WeChat, the appId can be obtained.
timeStamp String(32) Timestamp Current time
nonceStr String(32) Random string Random string, no longer than 32 bits
package String(128) Order details extension string The value of the prepay_id parameter returned by the unified interface is in the format of prepay_id=**
signType String(32) Signature method Signature type, default is MD5
paySign String(64) Signature
Public response parameters
txcurrcd Currency Transaction currency. View the Currencies table for a complete list of available currencies

Step 4: Evoke the payment module

For code instructions select Node.js with the tabs above.
weChatPayment: function(res) {
    wx.requestPayment(
    {
    'timeStamp': '1593746074',
    'nonceStr': '69d8a67fe34e44ca9bb2a20dd299cc58',
    'package': 'prepay_id=wx03111434674853b80d25e0911996417600',
    'signType': 'MD5',
    'paySign': 'B0AECE676746F2A310CB06F27641E809',
    'success': function(res){},
    'fail': function(res){},
    'complete': function(res){}
    })
},

Obtain the pay_params parameter, and then provide payment details accordingly. For more details, please refer to the Wechat documentation.

WeChat Mini Program Boilerplate

To get started quickly, download the QF Pay WeChat Mini Program Boilerplate and get access to the MD5 hash algorithm.


WeChat Mini Program Boilerplate


Setup Instructions

1) Sign up with QFPay and we bind your WeChat appid to your API credentials.
2) Visit the WeChat MP portal at https://mp.weixin.qq.com and whitelist our environment for incoming server traffic:
开发 -> 开发设置 -> 服务器域名 -> request合法域名: e.g. https://openapi-sg.qfapi.com
3) Copy and paste the files from the zip file to your local harddrive and setup a cloudfunction environment.
4) Obtain the user openid with the cloudfunction "getUserOpenID" and run the API calls accroding to the code.

WeChat in-APP Payments


WeChat APP Payment process-flow

HTTP Request

POST ../trade/v1/payment PayType: 800210

WeChat in-APP payments require a formal application on the WeChat Open Platform. Merchants have to register an account and the APP and then receive an appid to enable payments. For more information, please refer to the official Wechat documentation.

Optionally merchants can activate real-name authentication with WeChat. Currently real-name identification is only available for Mainland Chinese citizens and include a person's real name and national ID card number. In case identification is provided the payer's wallet information like a connected bank card must be identical with the data provided by merchants. If customers did not yet bind their WeChat account to a bank card the payment will go through regardless.

To download Wechat SDK please refer to this link.

Request Parameters


Request Body:

{
  goods_info=test_app&goods_name=qfpay&out_trade_no=O5DNgEgL1XpvbvQSfPhN&pay_type=800210&txamt=10&txcurrcd=HKD&txdtm=2019-09-13 04:53:03&udid=AA
}

The above command returns JSON structured like this:

{
  "sysdtm": "2019-09-13 12:53:04",
  "paydtm": "2019-09-13 12:53:04",
  "txcurrcd": "HKD",
  "respmsg": "",    
  "pay_params": 
        {
        "package": "Sign=WXPay",
        "timestamp": 1568350384,
        "sign": "XwFjohEKWdkhhT4ueg7BxeDn8tT9LcqoZYdXzifTMYyDGe3/tRchpii6vWgOn21tPSaAtqo766gvifXgDEOwR+ILKN8t97r624IJlrH0EkvSUSLh9E/cga9scXGVy0jPWHM/oVvVzJIvXew79CwZFCNTSJok2KmpSm9X9oPg7PGXbqvNMHltf+YlIOsuiz391qVmFtTE5A/cpA50+06T7iW8GYsOJQTTJed75VY+aSzNo5C6ju6WSgJKpAJJ0ocl+ONtmOp6GLVBSQXaMC4PitQcebcoP2J6fFgQ+YcPwHXasCYEnn4LaFN7zT/AjGg3E3gdCx3ksGNBOazYBRVz+g==",
        "partnerid": "316525492",
        "appid": "wx3c6896fa9b351f2a",
        "prepayid": "wx131253044253463a81dc336e1254149882",
        "noncestr": "7786db42d9a245c2b1cfc717ac59376e"
        },
  "pay_type": "800210",
  "cardcd": "",    
  "udid": "AA",
  "txdtm": "2019-09-13 04:53:03",
  "txamt": "10",
  "resperr": "交易成功",
  "out_trade_no": "O5DNgEgL1XpvbvQSfPhN",
  "syssn": "20190913152100020001567741",   
  "respcd": "0000",
  "chnlsn": ""
}
Parameter name Parameter code Mandatory Parameter type Description
Merchant ID mchid No String The unique merchant ID is created by QF Pay during the merchant onboarding process.
External transaction number out_trade_no Yes String Developer platform transaction number
Transaction amount txamt Yes String The actual amount of consumption, the maximum deduction amount cannot exceed the fozen funds
Currency txcurrcd Yes String(3) Transaction currency. View the Currencies table for a complete list of available currencies
RMB Tag rmb_tag No String(1) WeChat Pay in Hong Kong uses rmb_tag = Y together with txcurrcd = CNY to indicate that the transaction currency is RMB.
Transaction request time txdtm Yes String Format: YYYY-MM-DD hh:mm:ss
Device ID udid No String Must be unique
Time zone txzone No String Used to record the local order time. The default is Beijing time GMT+8 (+0800)
Redirect URL return_url No String Redirect to address after successful payment. Mandatory parameter to submit for GrabPay Online. Alipay WAP restricts the return_url to maximum 200 characters.
Extended Customer Info extend_info No Object Real name customer identification. This parameter is currently only available for Mainland Chinese citizens and needs to be explicitly activated with WeChat for the selected PayType. The consumer's national ID card number is contained in the parameter user_creid and the payer's real name in encoded form or written in Chinese characters must be provided in user_truename. An example looks like this; extend_info = '{"user_creid":"430067798868676871","user_truename":"\\u5c0f\\u6797"}'

Response Parameters

Parameter code Parameter type Parameter name Description
syssn String(40) QF Pay Transaction number QFPay transaction number, returned by the system once payment is completed
orig_syssn String(40) External transaction number Developer platform transaction number
txdtm String(20) Transaction request time Format: YYYY-MM-DD hh:mm:ss
txamt Int(11) Transaction amount
sysdtm String(20) System transaction time Format: YYYY-MM-DD hh:mm:ss
This parameter value is used as the cut-off time for settlements.
respcd String(4) Return code
respmsg String(128) Information description
resperr String(128) Description error
cardcd String Card number
txcurrcd String Currency Transaction currency. View the Currencies table for a complete list of available currencies
pay_params Object payment data Payment data to call Wechat SDK

PayMe Online Payment


For code instructions select Python, Java, Node.js or PHP with the tabs above.

#coding=utf8
import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, hashlib
import requests
import datetime
import string

# Enter Client Credentials
environment = 'https://openapi-test.qfpay.com'
app_code = 'D5589D2A1F2E42A9A60C37*********'
client_key = '0E32A59A8B454940A2FF39**********'


# Create parameter values for data payload
current_time = datetime.datetime.now().replace(microsecond=0)                                

print(current_time)

# Create signature
def make_req_sign(data, key):
    keys = list(data.keys())
    keys.sort()
    p = []
    for k in keys: 
        v = data[k]
        p.append('%s=%s'%(k,v))
    unsign_str = ('&'.join(p) + key).encode("utf-8")
    s = hashlib.md5(unsign_str).hexdigest()
    return s.upper()


# Body payload
txamt = '10' # In cents
txcurrcd = 'HKD'
pay_type = '805814' # PayMe Web Payment = 805814
out_trade_no = '01234567890123'
txdtm = current_time
goods_name = 'test1'   
mchid = 'ZaMVg*****'
key = client_key

data ={'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'mchid': mchid}

r = requests.post(environment+"/trade/v1/payment",data=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, key)})

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="D5589D2A1F2E42A9A60C37*********";
        String key="0E32A59A8B454940A2FF39*********";
        String mchid="ZaMVg*****";

        String pay_type="805801";
        String out_trade_no= "01234567890123";
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date=df.format(new Date());
        String txdtm=date;
        String txamt="10";
        String txcurrcd="HKD";

        Map<String, String> unsortMap = new HashMap<>();
        unsortMap.put("mchid", mchid);
        unsortMap.put("pay_type", pay_type);
        unsortMap.put("out_trade_no", out_trade_no);
        unsortMap.put("txdtm", txdtm);
        unsortMap.put("txamt", txamt);
        unsortMap.put("txcurrcd", txcurrcd);
        //unsortMap.put("product_name", product_name);
        //unsortMap.put("valid_time", "300");

        String data=QFPayUtils.getDataString(unsortMap);
        System.out.println("Data:\n"+data+key);
        String md5Sum=QFPayUtils.getMd5Value(data+key);
        System.out.println("Md5 Value:\n"+md5Sum);

        String url="https://openapi-test.qfpay.com";
        String resp= Requests.sendPostRequest(url+"/trade/v1/payment", data, appcode,key);
        System.out.println(resp);
    }
}
// Enter Client Credentials
const environment = 'https://openapi-test.qfpay.com'
const app_code = 'D5589D2A1F2E42A9A60C37*********'
const client_key = '0E32A59A8B454940A2FF39*********'

// Generate Timestamp
var dateTime = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
console.log(dateTime)

// Body Payload
const key = client_key
var tradenumber = String(Math.round(Math.random() * 1000000000))
console.log(tradenumber)

var payload = {
'txamt': '10', // In cents
'txcurrcd': 'HKD',
'pay_type': '805814', // PayMe Web Payment = 805814
'out_trade_no': tradenumber,
'txdtm': dateTime,
'mchid': 'ZaMVg*****'
};

// Signature Generation
const ordered = {};
Object.keys(payload).sort().forEach(function(key) {
  ordered[key] = payload[key] });
console.log(ordered)

var str = [];
for (var p in ordered)
if (ordered.hasOwnProperty(p)) {
str.push((p) + "=" + (ordered[p]));
}
var string = str.join("&")+client_key;
console.log(string)

const crypto = require('crypto')
var hashed = crypto.createHash('md5').update(string).digest('hex')
console.log(hashed)


// API Request
var request = require("request");
request({
  uri: environment+"/trade/v1/payment",
  headers: {
    'X-QF-APPCODE': app_code,
    'X-QF-SIGN': hashed
  },
  method: "POST",
  form: payload,
  }, 
  function(error, response, body) {
  console.log(body);
});
<?php
ob_start();
  function GetRandStr($length){
  $str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $len=strlen($str)-1;
  $randstr='';
  for($i=0;$i<$length;$i++){
  $num=mt_rand(0,$len);
  $randstr .= $str[$num];
  }
  return $randstr;
  }

     $url = 'https://openapi-test.qfapi.com';
     $api_type = '/trade/v1/payment';
     $pay_type = '805814'; //PayMe Web Payment = 805814
     //$mchid = "MNxMp11FV35qQN"; //Only agents must provide this parameter
     $app_code = 'FF2FF74F2F2E42769A4A73*********'; //API credentials are provided by QFPay
     $app_key = '7BE791E0FD2E48E6926043B*********'; //API credentials are provided by QFPay
     $now_time = date("Y-m-d H:i:s"); //Get current date-time

     $fields_string = '';
     $fields = array(
      //'mchid' => urlencode($mchid),
      'pay_type' => urlencode($pay_type),
      'out_trade_no' => urlencode(GetRandStr(20)),
      'txcurrcd' => urlencode('EUR'),
      'txamt' => urlencode(2200),
      'txdtm' => $now_time
    );
    ksort($fields); //字典排序A-Z升序方式
    print_r($fields);

    foreach($fields as $key=>$value) { 
  $fields_string .= $key.'='.$value.'&' ;
  }
  $fields_string = substr($fields_string , 0 , strlen($fields_string) - 1);

  $sign = strtoupper(md5($fields_string . $app_key));

  //// Header ////
  $header = array();
  $header[] = 'X-QF-APPCODE: ' . $app_code;
  $header[] = 'X-QF-SIGN: ' . $sign;

  //Post Data
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url . $api_type);
  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);    

  $final_data = json_decode($output, true);
  print_r($final_data);

ob_end_flush();
?>

The above command returns JSON structured like this:

{
  "sysdtm": "2020-04-13 10:30:34", 
  "paydtm": "2020-04-13 10:30:34", 
  "txcurrcd": "HKD", 
  "respmsg": "", 
  "pay_type": "805814", 
  "cardcd": "", 
  "udid": "qiantai2", 
  "txdtm": "2020-04-13 10:30:34", 
  "txamt": "300", 
  "resperr": "success", 
  "out_trade_no": "4K35N374II7UJJ8RGIAE45O2CVHGHFF0", 
  "syssn": "20200413000300020087033882", 
  "respcd": "0000", 
  "pay_url": "https://qr.payme.hsbc.com.hk/2/C5bvYGEyrgXbxxxxxxxxxx", 
  "chnlsn": ""
}

Web/WAP Payment

Customers make purchases on a merchant website with PayMe. The user scans the displayed QR code to pay, confirms the total amount and makes the payment. Finally the customer can be redirected to a selected page on the merchant's website using the return_url parameter. PayMe deducts the payment amount from the consumer's PayMe wallet in real-time in HKD and QFPay settles the payment amount to merchants in HKD.

HTTP Request

POST ../trade/v1/payment
PayType: 805814 PayMe Online WEB (in browser Chrome etc.) Payment (HK Merchants)
PayType: 805812 PayMe Online WAP (in mobile browser Chrome etc.) Payment (HK Merchants)

Request Parameters

Parameter name Parameter code Mandatory Type Description
Payment amount txamt Yes Int(11) Amount of the transaction. Unit in cents (i.e. 100 = $1)
Currency txcurrcd Yes String(3) Transaction currency. View the Currencies table for a complete list of available currencies
Payment type pay_type Yes String(6) PayMe Web Payment = 805814
API Order Number out_trade_no Yes String(128) External transaction number / Merchant platform transaction number: This parameter must be unique for each payment and refund request under the same merchant account in the system.
Request transaction time txdtm Yes String(20) Transaction time format:
YYYY-MM-DD hh:mm:ss
Order expiration time expired_time No
(MPM only)
String(3) QRC expiration time in unit minutes. The default expiration time is 30 minutes. The parameter can manually be adjusted to a minimum of 5 minutes, and up to a maximum of 120 minutes.
Product name identification goods_name No String(64) Goods Name / Marking: Cannot exceed 20 alphanumeric or contain special characters. Cannot be empty for app payment. Parameter needs to be UTF-8 encoded if it is written in Chinese characters.
QF Pay merchant number mchid No String(16) May or may not be given to merchant. If MCHID is given, it is mandatory to provide the MCHID .On the contrary, if MCHID is not provided, merchants shall not pass the MCHID field in the API request.
Time zone txzone No String(5) Transaction Time zone: Record of the transaction in local time, default time zone is Beijing time UTC+8 (+0800).
Device ID udid No String(40) Unique transaction device ID. Is displayed on the merchant portal.
Redirect URL return_url No String(512) URL that the user will be redirected to when the payment finishes.

Response Parameters

Parameter name Parameter code Type Description
Payment type pay_type String(6) PayMe Web/Wap Payment
System transaction time sysdtm String(20) Format:YYYY-MM-DD hh:mm:ss
This parameter value is used as the cut-off time for settlements.
Request transaction time txdtm String(20) Format:YYYY-MM-DD hh:mm:ss
Response message resperr String(128)
Payment amount txamt Int(11)
Other message information respmsg String(128)
External transaction number out_trade_no String(128) External transaction number
QFPay transaction number syssn String(40)
Return code respcd String(4) 0000 = Request successful.
1143/1145 = merchants are required to continue to query the transaction result.
All other return codes indicate transaction failure. Please refer to the page Transaction Status Codes for a complete list of response codes.
Payment URL pay_url String(512) generate QR code in Desktop web; redirect URL in WAP

PayMe Offline Payment

For code instructions select Python, Java, Node.js or PHP with the tabs above.
#coding=utf8
import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, hashlib
import requests
import datetime
import string

# Enter Client Credentials
environment = 'https://openapi-test.qfpay.com'
app_code = 'D5589D2A1F2E42A9A60C37*********'
client_key = '0E32A59A8B454940A2FF39**********'


# Create parameter values for data payload
current_time = datetime.datetime.now().replace(microsecond=0)                                

print(current_time)

# Create signature
def make_req_sign(data, key):
    keys = list(data.keys())
    keys.sort()
    p = []
    for k in keys: 
        v = data[k]
        p.append('%s=%s'%(k,v))
    unsign_str = ('&'.join(p) + key).encode("utf-8")
    s = hashlib.md5(unsign_str).hexdigest()
    return s.upper()


# Body payload
txamt = '200' # In cents
txcurrcd = 'HKD'
pay_type = '805801' # PayMe Offline Payment = 805801
out_trade_no = '16565588217444950016'
txdtm = current_time
goods_name = 'qfpay_payme'
return_url = 'http://www.qfpay.com'
txzone = '+0800'
udid = 'my_udid'

key = client_key

data ={'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'udid': udid, 'return_url': return_url, 'txzone': txzone}

r = requests.post(environment+"/trade/v1/payment",data=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, key)})

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="D5589D2A1F2E42A9A60C37*********";
        String key="0E32A59A8B454940A2FF39*********";


        String pay_type="805801";
        String out_trade_no= "165655882174";
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date=df.format(new Date());
        String txdtm=date;
        String txzone="+0800";
        String txamt="200";
        String txcurrcd="HKD";
        String usid="myudid";
        String return_url="http://www.qfpay.com";
        String goods_name="qfpay_payme";

        Map<String, String> unsortMap = new HashMap<>();
        unsortMap.put("udid", udid);
        unsortMap.put("pay_type", pay_type);
        unsortMap.put("out_trade_no", out_trade_no);
        unsortMap.put("txdtm", txdtm);
        unsortMap.put("txzone", txzone);
        unsortMap.put("txamt", txamt);
        unsortMap.put("txcurrcd", txcurrcd);
        unsortMap.put("return_url", return_url);
        unsortMap.put("goods_name", goods_name);

        String data=QFPayUtils.getDataString(unsortMap);
        System.out.println("Data:\n"+data+key);
        String md5Sum=QFPayUtils.getMd5Value(data+key);
        System.out.println("Md5 Value:\n"+md5Sum);

        String url="https://openapi-test.qfpay.com";
        String resp= Requests.sendPostRequest(url+"/trade/v1/payment", data, appcode,key);
        System.out.println(resp);
    }
}
// Enter Client Credentials
const environment = 'https://openapi-test.qfpay.com'
const app_code = 'D5589D2A1F2E42A9A60C37*********'
const client_key = '0E32A59A8B454940A2FF39*********'

// Generate Timestamp
var dateTime = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')
console.log(dateTime)

// Body Payload
const key = client_key

var payload = {
'txamt' : '200' # In cents
'txcurrcd' : 'HKD'
'pay_type' : '805801' # PayMe Offline Payment = 805801
'out_trade_no' : '16565588217444950016'
'txdtm' = dateTime
'goods_name' : 'qfpay_payme'   
'return_url' : 'http://www.qfpay.com'
'txzone' : '+0800'
'udid' : 'my_udid'
};

// Signature Generation
const ordered = {};
Object.keys(payload).sort().forEach(function(key) {
  ordered[key] = payload[key] });
console.log(ordered)

var str = [];
for (var p in ordered)
if (ordered.hasOwnProperty(p)) {
str.push((p) + "=" + (ordered[p]));
}
var string = str.join("&")+client_key;
console.log(string)

const crypto = require('crypto')
var hashed = crypto.createHash('md5').update(string).digest('hex')
console.log(hashed)


// API Request
var request = require("request");
request({
  uri: environment+"/trade/v1/payment",
  headers: {
    'X-QF-APPCODE': app_code,
    'X-QF-SIGN': hashed
  },
  method: "POST",
  form: payload,
  }, 
  function(error, response, body) {
  console.log(body);
});
<?php
ob_start();
  function GetRandStr($length){
  $str='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $len=strlen($str)-1;
  $randstr='';
  for($i=0;$i<$length;$i++){
  $num=mt_rand(0,$len);
  $randstr .= $str[$num];
  }
  return $randstr;
  }

     $url = 'https://openapi-test.qfapi.com';
     $api_type = '/trade/v1/payment';
     $pay_type = '805801'; //PayMe Offline Payment = 805801
     $app_code = 'FF2FF74F2F2E42769A4A73*********'; //API credentials are provided by QFPay
     $app_key = '7BE791E0FD2E48E6926043B*********'; //API credentials are provided by QFPay
     $now_time = date("Y-m-d H:i:s"); //Get current date-time

     $fields_string = '';
     $fields = array(
      'pay_type' => urlencode($pay_type),
      'out_trade_no' => urlencode(16565588217444950016),
      'txcurrcd' => urlencode('HKD'),
      'txamt' => urlencode(200),
      'txzone' => urlencode('+0800'),
      'txdtm' => $now_time,
      'goods_name' => urlencode('qfpay_payme'),
      'return_url' => urlencode('http://www.qfpay.com'),
      'udid' => urlencode($myudid),
    );
    ksort($fields); //字典排序A-Z升序方式
    print_r($fields);

    foreach($fields as $key=>$value) { 
  $fields_string .= $key.'='.$value.'&' ;
  }
  $fields_string = substr($fields_string , 0 , strlen($fields_string) - 1);

  $sign = strtoupper(md5($fields_string . $app_key));

  //// Header ////
  $header = array();
  $header[] = 'X-QF-APPCODE: ' . $app_code;
  $header[] = 'X-QF-SIGN: ' . $sign;

  //Post Data
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url . $api_type);
  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);    

  $final_data = json_decode($output, true);
  print_r($final_data);

ob_end_flush();
?>

The above command returns JSON structured like this:

{
  "pay_type" : "805801",
  "sysdtm" : "2022-06-30 11:14:29",
  "paydtm" : "2022-06-30 11:14:29",
  "resperr" : "交易成功",
  "txcurrcd" : "HKD",
  "txdtm" : "2022-06-30 11:13:41",
  "txamt" : "200",
  "payme_logo" : "https://shopfront.paymebiz.hsbc.com.hk/onboarding/dfbd33ed8dd4282ccb0f0db0e9301a9a04ab29db0b7e2b7597bff9fd7382776d/businessLogo_300x300.png",
  "respmsg" : "PR001:Request for Payment Initiated",
  "out_trade_no" : "16565588217444950016",
  "syssn" : "20220630154100020012764799",
  "respcd" : "0000",
  "qrcode" : "https://qr.payme.hsbc.com.hk/2/CmJBJZAXRgCh8GmBXJKuXG",
  "udid" : "my_udid",
  "pay_url" : "",
  "chnlsn" : "5f43d654-d309-4560-8585-fb78f8dc694b",
  "cardcd" : ""
}

Offline Payment

For MPM Mode, The merchant generates a dynamic QR code based on the Payme protocol and presents it to the customer. The user opens their PayMe wallet and scans the displayed QR Code in order to complete payment. For CPM Mode, the customer generates a dynamic QR code in their QR code wallet and presents it to the cashier for scanning. If the response codes 1143/1145 are returned, the transaction is being processed or the customer is required to input the wallet password. Merchants have to query the transaction result for a final assessment of the transaction status.

HTTP Request

POST ../trade/v1/payment
PayType: 805801 PayMe Merchant Presented QR Code Payment in store (MPM) (HK Merchants)
PayType: 805808 PayMe Consumer Presented QR Code Payment (CPM) (HK Merchants)

Request Parameters

Parameter name Parameter code Mandatory Type Description
Payment amount txamt Yes Int(11) Amount of the transaction. Unit in cents (i.e. 100 = $1)
Currency txcurrcd Yes String(3) Transaction currency. View the Currencies table for a complete list of available currencies
Payment type pay_type Yes String(6) PayMe Web Payment = 805801
API Order Number out_trade_no Yes String(128) External transaction number / Merchant platform transaction number: This parameter must be unique for each payment and refund request under the same merchant account in the system.
Request transaction time txdtm Yes String(20) Transaction time format:
YYYY-MM-DD hh:mm:ss
Order expiration time expired_time No
(MPM only)
String(3) QRC expiration time in unit minutes. The default expiration time is 30 minutes. The parameter can manually be adjusted to a minimum of 5 minutes, and up to a maximum of 120 minutes.
Product name identification goods_name No String(64) Goods Name / Marking: Cannot exceed 20 alphanumeric or contain special characters. Cannot be empty for app payment. Parameter needs to be UTF-8 encoded if it is written in Chinese characters.
QF Pay merchant number mchid No String(16) May or may not be given to merchant. If MCHID is given, it is mandatory to provide the MCHID .On the contrary, if MCHID is not provided, merchants shall not pass the MCHID field in the API request.
Time zone txzone No String(5) Transaction Time zone: Record of the transaction in local time, default time zone is Beijing time UTC+8 (+0800).
Device ID udid No String(40) Unique transaction device ID. Is displayed on the merchant portal.
Redirect URL return_url No String(512) URL that the user will be redirected to when the payment finishes.

Response Parameters

Parameter name Parameter code Type Description
Payment type pay_type String(6) PayMe Web/Wap Payment
System transaction time sysdtm String(20) Format:YYYY-MM-DD hh:mm:ss
This parameter value is used as the cut-off time for settlements.
Request transaction time txdtm String(20) Format:YYYY-MM-DD hh:mm:ss
Response message resperr String(128)
Payment amount txamt Int(11)
Other message information respmsg String(128)
External transaction number out_trade_no String(128) External transaction number
QFPay transaction number syssn String(40)
Return code respcd String(4) 0000 = Request successful.
1143/1145 = merchants are required to continue to query the transaction result.
All other return codes indicate transaction failure. Please refer to the page Transaction Status Codes for a complete list of response codes.
Payment URL pay_url String(512) generate QR code in Desktop web; redirect URL in WAP

Customs Declaration

Customs declaration API auto-sends the WeChat/Alipay payment data to the customs to simplify the clearance process and saves time for online cross-border stores.

Push Customs Declaration

HTTP Request

POST ../custom/v1/declare

Request Parameters

Parameter code Mandatory Parameter type Description
trade_type Y String(8) weixin or alipay
syssn Y String(32) QFPay transaction number
customs Y String(20) Customs for declaration. Example:SHANGHAI_ZS
mch_customs_no Y String(20) Customs registration No. of the merchant
action_type N String(256) Declaration type. Only valid when trate_type is "wechat". "ADD" - new appplication, "MODIFY" - modification of applied declaration
mch_customs_name N String(256) Merchant customs record name. Must be passed when trate_type is "alipay". Exaple: jwyhanguo_card
out_request_no N String(32) Merchant order number. Must be passed when trate_type is "alipay". Exaple: 15725904083420588032
amount N String(20) Declaration amount. Must be passed when trate_type is "alipay". Example: 2.00

The following fields should be passed in case splitting or modifying order:

Parameter code Mandatory Parameter type Description
sub_order_no C String(64) Merchant sub-order No. It is required if there is a split order. Example:1111960490
fee_type C String(8) Currency. Must be passed when trate_type is "wechat". It can only be CNY
order_fee C String(8) Sub-order amount (in 0.01 CNY). Cannot exceed the original order amount. order_fee=transport_fee+product_fee. It is required if there is a split order Example:888
product_fee C String(8) Product price (in 0.01 CNY). It is required if there is a split order. Example:888
transport_fee C String(8) Logistics fee (in 0.01 CNY). It is required if there is a split order. Example:888

Response Parameters

Parameter code Mandatory Parameter type Description
syssn String(40) QFPay transaction number
respcd String(4) 0000 = Declaration successful.
1143/1145 = merchants are required to continue to query the declaration result.
All other return codes indicate transaction failure. Please refer to the page Transaction Status Codes for a complete list of response codes.
resperr String(128) Response message
respmsg String(128) Other message information
verify_department Verification organization
verify_department_trade_id Transaction number of verification organization

Query Customs Declaration

Merchants query declaration status by QFPay transaction number.

HTTP Request

POST/GET ../custom/v1/query

Request Parameters

Parameter code Mandatory Parameter type Description
trade_type Y String(8) weixin or alipay
customs Y String(20) Customs for declaration. Example:SHANGHAI_ZS
syssn Y String(32) QFPay transaction number
sub_order_no N String(40) Sub order number. It is required if there is a split order.

Response Parameters

Parameter code Mandatory Parameter type Description
syssn String(40) QFPay transaction number
respcd String(4) 0000 = Declaration successful.
1143/1145 = merchants are required to continue to query the declaration result.
All other return codes indicate transaction failure. Please refer to the page Transaction Status Codes for a complete list of response codes.
resperr String(128) Response message
respmsg String(128) Other message information
data Customs declaration details [{"resperr" : "", "errmsg" : null, "sub_order_no" : "15752730835729139712", "verify_department" : "OTHERS", "verify_department_trade_id" : "4200000459201911265585026208"}]

Repush Customs Declaration

If additional order information has been submitted to the customs but is lost in the electronic port, the customs declaration re-push API can be used to push the information to the customs again.

HTTP Request

POST ../custom/v1/redeclare

Request Parameters

Parameter code Mandatory Parameter type Description
trade_type Y String(8) weixin or alipay
customs Y String(20) Customs for declaration. Example:SHANGHAI_ZS
syssn Y String(32) QFPay transaction number
mch_customs_no Y String(20) Customs registration No. of the merchant. Example: 110084111
sub_order_no N String(40) Sub order number. It is required if there is a split order.

Response Parameters

Parameter code Mandatory Parameter type Description
syssn String(40) QFPay transaction number
respcd String(4) 0000 = Declaration successful.
1143/1145 = merchants are required to continue to query the declaration result.
All other return codes indicate transaction failure. Please refer to the page Transaction Status Codes for a complete list of response codes.
resperr String(128) Response message
respmsg String(128) Other message information

FAQs

Q1. In provided test account credentials which one is the partner or the merchant identifier?
A1. If you're an agent which provides payment services for merchants; X-QF-APPCODE and ClientKey are the partner while MCHID is the merchant identifier. If you're a merchant then X-QF-APPCODE and ClientKey are merchant identifier and MCHID is not provided.

Q2. Can I use given (Test/Production) account in another country?
A2. No. An (Test/Production) account is country specific.

Q3. How can I test a transaction?
A3. Since test environment is a replica of production you can use production wallets to test transactions. If you need any assistance please contact tech support.

Q4. I receive a 1143/1145 response code, what should I do next?
A4. It's advised to keep querying transaction status. If partner/merchant wants to process as binary status (success/fail), can mark the transaction as failed and upon a successful asynchronous notifications can apply for refund at backend.

Q5. There is no specific title for the payment method I want to integrate, what should I do?
A5. You should use Public Payment Parameters and check the special cases in Notes section at the end of the Payment Codes.

Q6. Can I refund a transaction made n day(s) ago?
A6. Only if the total transaction of the day is equal or greater than the refund amount you can refund.

Q7. Do you transfer funds to our bank account when we test transactions in the sandbox environment?
A7. There are no settlements possible in the sandbox environment. Please make sure that you refund test transactions immediately after testing.

Q8. Can I use my overseas Alipay wallet to pay?
A8. No, currently only real-name identified Alipay wallets which belong to Mainland Chinese citizens can be used to conduct cross-border transactions.