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
Content-Type: application/x-www-form-urlencoded
X-QF-APPCODE: <your-app-code>
X-QF-SIGN: <signature>
Request Parameters
| Parameter | Mandatory | Type | Description |
|---|
syssn | Yes | String(128) | QFPay transaction number of the original transaction to be refunded |
out_trade_no | Yes | String(128) | Unique refund transaction ID (must not repeat across refund requests) |
txamt | Yes | Int(11) | Refund amount in cents (e.g. 100 = $1). Suggest > 200 to avoid risk control. |
txdtm | Yes | String(20) | Refund request time. Format: YYYY-MM-DD hh:mm:ss |
mchid | Conditional | String(16) | Merchant ID. Required only if one is issued. |
udid | No | String(40) | Unique transaction device ID |
Response Parameters
| Parameter | Type | Description |
|---|
syssn | String(40) | New refund transaction ID |
orig_syssn | String(128) | Original transaction ID |
txamt | Int(11) | Refunded amount in cents |
sysdtm | String(20) | Refund system time (YYYY-MM-DD hh:mm:ss) |
respcd | String(4) | 0000 = success, 1143/1145 = processing, other = failed |
resperr | String(128) | Response message |
cash_fee | String | Actual amount paid by user (after discounts) |
cash_fee_type | String | Payment currency (e.g. CNY) |
cash_refund_fee | String | Actual refunded amount |
cash_refund_fee_type | String | Refund 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.