Skip to main content
Only transactions with the return code 0000(transaction successful) can be refunded.
For credit card payments, QFPay performs automatic capture. If a refund is submitted on the same day, it will be treated as a void and handled by this same refund API.

API Endpoint

Endpoint : /trade/v1/refund
Method : POST

Request Headers

Content-Type: application/x-www-form-urlencoded
X-QF-APPCODE: <your-app-code>
X-QF-SIGN: <signature>

Request Parameters

ParameterMandatoryTypeDescription
syssnYesString(128)QFPay transaction number of the original transaction to be refunded
out_trade_noYesString(128)Unique refund transaction ID (must not repeat across refund requests)
txamtYesInt(11)Refund amount in cents (e.g. 100 = $1). Suggest > 200 to avoid risk control.
txdtmYesString(20)Refund request time. Format: YYYY-MM-DD hh:mm:ss
mchidConditionalString(16)Merchant ID. Required only if one is issued.
udidNoString(40)Unique transaction device ID

Response Parameters

ParameterTypeDescription
syssnString(40)New refund transaction ID
orig_syssnString(128)Original transaction ID
txamtInt(11)Refunded amount in cents
sysdtmString(20)Refund system time (YYYY-MM-DD hh:mm:ss)
respcdString(4)0000 = success, 1143/1145 = processing, other = failed
resperrString(128)Response message
cash_feeStringActual amount paid by user (after discounts)
cash_fee_typeStringPayment currency (e.g. CNY)
cash_refund_feeStringActual refunded amount
cash_refund_fee_typeStringRefund currency (e.g. CNY)

Sample HTTP Body

txamt=10&syssn=20191227000200020061752831&out_trade_no=12345678&txdtm=2019-12-27 10:39:39&mchid=ZaMVg*****

SDK Code Examples

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-hk.qfapi.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 = {'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())

Sample JSON Response

{
  "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": ""
}

Notes

  • Ensure refund amount does not exceed the original transaction value.
  • Some wallets may not support partial refunds.
  • Refund time limits vary by channel. Contact QFPay support for details.
  • For failed refunds (respcd not 0000), retry logic or query via Transaction Enquiry is advised.