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.global.

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 https://openapi-test.qfpay.com
China Mainland https://test-openapi.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 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 Merchant)
800107 Alipay Service Window H5 Payment
800108 Alipay Consumer Presented QR Code Payment (CPM)
800201 WeChat Merchant Presented QR Code Payment (MPM) (Online Payment) (Overseas & HK Merchant)
800207 WeChat JSAPI Payment - WeChat Official Account Payment (Overseas & HK Merchant)
800208 WeChat Consumer Presented QR Code Payment (CPM)
800210 WeChat in-APP Payment
800213 WeChat Mini-Program Payment
800701 UNIONPAY Quick Pass Merchant Presented QR Code Payment (MPM)
800708 UNIONPAY Quick Pass Consumer Presented QR Code Payment (CPM)
801008 WeChat Pay HK Consumer Presented QR Code Payment (CPM) (Direct Settlement, HK Merchant)
801010 WeChat Pay HK In-App Payment (Direct Settlement, HK Merchant)
801114 Alipay Online QR Code Payment (Overseas Merchant)
801112 Alipay Online WAP Payment (Overseas Merchant)
801110 Alipay in-APP Payments (Overseas Merchant)
801208 LINEPAY dynamic QRC Payment - Consumer Present Mode (CPM)
801301 LINEPAY Online Payment
801408 AIRPAY dynamic QRC Payment - Consumer Present Mode (CPM)
801501 Alipay HK Merchant Presented Online QR Code Payment (HK Merchant)
801510 Alipay HK In-App Payment (HK Merchant)
801512 Alipay HK Online WAP Payment (HK Merchant)
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 HK FPS Merchant Presented QR Code Payment (MPM)
802201 AIRPAY Online Payment
802301 PayNow Merchant Presented QR Code Payment (MPM)
802901 PromptPay dynamic QRC Payment - Merchant Present Mode (MPM)
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)
803108 VIA dynamic QRC Payment - Consumer Present Mode (CPM)
803208 Touch 'n Go (TNG) dynamic QRC Payment - Consumer Present Mode (CPM)
803214 Touch 'n Go (TNG) Online Payment
803301 Razer dynamic QRC Payment - Merchant Present Mode (MPM)
803308 Razer dynamic QRC Payment - Consumer Present Mode (CPM)
803314 Razer Online Payment
803701 Octopus dynamic QRC Payment - Merchant Present Mode (MPM) (HK Merchant)
803712 Octopus WAP Payment (HK Merchant)
803801 Dash dynamic QRC Payment - Merchant Present Mode (MPM)
803808 Dash dynamic QRC Payment - Consumer Present Mode (CPM)
804001 Boost dynamic QRC Payment - Merchant Present Mode (MPM)
804008 Boost dynamic QRC Payment - Consumer Present Mode (CPM)
804014 Boost Online Payment
804101 Maybank dynamic QRC Payment - Merchant Present Mode (MPM)
804108 Maybank dynamic QRC Payment - Consumer Present Mode (CPM)
804114 Maybank Online Payment
804201 GrabPay dynamic QRC Payment - Merchant Present Mode (MPM)
804208 GrabPay dynamic QRC Payment - Consumer Present Mode (CPM) (Malaysia Merchant)
804214 GrabPay Online Payment
805208 TrueMoney dynamic QRC Payment - Consumer Present Mode (CPM)
805401 ThaiQR dynamic QRC Payment - Merchant Present Mode (MPM) (Singapore Merchant)
805601 GoPay dynamic QRC Payment - Merchant Present Mode (MPM)
805612 GoPay WAP Payment

Currencies

The below listed currencies are currently available in our payment network. Please consult technical.support@qfpay.global 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

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*****'
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}
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
801112 - Alipay overseas WAP payment
801114 - 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.
Device ID udid No String(40) Unique transaction device ID. Is displayed on the merchant portal.

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)
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

#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
801112 - Alipay overseas WAP payment
801114 - 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*****'
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}
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.
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.
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 +08:00
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
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

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 +08:00
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

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.global 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.
cash_fee No String Actual payment amount by user = transaction amount - discounts
cash_fee_type No String Actual payment currency e.g. CNY
goods_info No String Product description
chnlsn No String Transaction number from the payment channel
cardcd No String Card number

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 = '801114' # Alipay Web Payment = 801114
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="801114";
        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': '801114', // Alipay Web Payment = 801114
'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 = '801114'; //Alipay Web Payment = 801114
     //$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": "801114", 
  "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

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

HTTP Request

POST ../trade/v1/payment
PayType: 801114 Overseas Merchants Web
PayType: 801112 Overseas Merchants Wap
PayType: 801501 Hong Kong 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) Alipay Web Payment = 801114
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.
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 = 801114/801112
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 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 USD,EUR,etc. Cent
txcurrcd = 'EUR'
pay_type = '801112' # Alipay Wap Payment = 801112
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="801112";
        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': '801112', // Alipay Wap Payment = 801112
'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 = '801112'; //Alipay Wap Payment = 801112
     //$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": "801112", 
  "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

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.global 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

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
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 APP Payments


Alipay APP Payment process-flow

HTTP Request

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

Request Parameters


Request Body:

{
  goods_info=test_app&goods_name=qfpay&mchid=R1zQrTdJnn&out_trade_no=Native20190725152211e999e6db0e&pay_tag=ALIPAYHK&pay_type=801510&txamt=10&txcurrcd=HKD&txdtm=2019-07-25 15:22:12&udid=AA
}

The above command returns JSON structured like this:

{
  "sysdtm": "2019-07-25 15:22:14", 
  "paydtm": "2019-07-25 15:22:14", 
  "txcurrcd": "HKD", 
  "respmsg": "", 
  "pay_params": 
        { 
        "body": "test_app", 
        "forex_biz": "FP", 
        "seller_id": "2088231067382451", 
        "product_code": "NEW_WAP_OVERSEAS_SELLER", 
        "total_fee": 0.1, 
        "service": "mobile.securitypay.pay", 
        "payment_inst": "ALIPAYHK", 
        "subject": "qfpay", 
        "secondary_merchant_name": "HKTest (Branch Store)", 
        "_input_charset": "UTF-8", 
        "sign": "GetP0UKfKIAoCdeop7oFhMaVkDfMGZ9cFjpAHXgvNxZG1FYhsMDcrkgn38LmyN8p9mhzOPEuNWVCZaXjutkqGn9FG%2F1uD8%2FPT8lwyNUNLZ%2BxTJ5mY2RpmGJsQhU2aICbE%2F1uGAPYaQsbN0mFwTLs7IkIXE8lz5kG4VneLyO3%2BZQ%3D", 
        "currency": "HKD", 
        "out_trade_no": "20190725000300020082770207", 
        "payment_type": "1", 
        "secondary_merchant_id": "2319316", 
        "sign_type": "RSA", 
        "notify_url": "https://o2.qfpay.com/online-test/trade/alipay_hk/v1/notify", 
        "partner": "2088231067382451", 
        "it_b_pay": "30m", 
        "return_url": "", 
        "secondary_merchant_industry": 5311
        }, 
  "pay_type": "801510", 
  "cardcd": "", 
  "udid": "AA", 
  "txdtm": "2019-07-25 15:22:12", 
  "txamt": "10", 
  "resperr": "交易成功", 
  "out_trade_no": "Native20190725152211e999e6db0e", 
  "syssn": "20190725000300020082770207", 
  "respcd": "0000", 
  "chnlsn": ""
}
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
801112 - Alipay overseas Wap payment
801114 - 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
ign 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.

HTTP Request

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

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) 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.
Device ID udid No String(40) Unique transaction device ID. Is displayed on the merchant portal.

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


WeChat JSAPI process-flow

JSAPI Payment Types

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 "MicroMessenger" 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)

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

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 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.

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.

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 APP Payments


WeChat APP Payment process-flow

HTTP Request

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

WeChat 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.

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 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
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 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