跳轉到主要內容

非同步通知

QFPay 目前支援以下兩種非同步通知:
  • 付款成功:"notify_type": "payment"
  • 退款成功:"notify_type": "refund"
未來版本的通知參數可能新增欄位。建議你的接收端採用「可忽略未知欄位」的處理方式,並定期查看最新文件更新。

概述

當支付或退款成功後,QFPay 會以 HTTP POST 方式向商戶已設定的 callback URL 發送一筆 JSON 通知,用於即時更新交易結果。
即使已收到通知,也建議使用 交易查詢 API 二次驗證交易狀態,避免因網路重試或重放造成誤判。
出於安全考量,callback URL 僅支援 80 / 443 端口,且 Content-Type 固定為 application/json

非同步通知規則

  1. 僅在交易成功(付款或退款)後才會發送通知。
  2. 請透過電郵提交通知端點 URL 至 technical.support@qfpay.com,由技術支援協助設定。
  3. 商戶收到通知後必須進行簽名驗證。驗證成功後回覆:
    • HTTP Status Code:200 OK
    • Response Body:SUCCESS
  4. 若未收到預期回應,系統會依以下時間間隔重試:
    • 2 分鐘 → 10 分鐘 → 10 分鐘 → 60 分鐘 → 2 小時 → 6 小時 → 15 小時
  5. 同一組 app_code + client_key 僅能綁定 一個 通知 URL。代理商應為子商戶共用同一接收端點。
  6. HTTP 方法POST
    Content-Typeapplication/json

簽名驗證

非同步通知的簽名驗證方式與一般 API 請求不同:必須使用「原始 request body(未重排 / 未格式化的 JSON 字串)」來驗證。

驗證步驟

  1. 從 HTTP header 取得 X-QF-SIGN
  2. 取得原始 request body(JSON 字串),直接在尾端串接 client_key
  3. 對字串做 MD5 雜湊,並轉成 大寫
  4. 若雜湊結果等於 X-QF-SIGN,視為驗證成功,回覆 200 OKSUCCESS
請使用「原始 body」做驗證。若你把 JSON parse 後再 json.dumps() 重新序列化,欄位順序與空白可能不同,會導致簽名不一致。

簽名範例

import hashlib

client_key = "3ABB1BFFE2E0497BB9270978B0BXXXXX"

# 假設你取得的 raw_body 是 HTTP request 的原始 body(bytes 或 str)
raw_body = b'{"status":"1","notify_type":"payment"}'

combine = raw_body + client_key.encode("utf-8")
signature = hashlib.md5(combine).hexdigest().upper()

print(signature)
實作時請以你實際收到的完整 raw body 進行計算;上例僅示意流程。

通知內容範例

JSON
{
  "status": "1",
  "pay_type": "800101",
  "sysdtm": "2020-05-14 12:32:56",
  "paydtm": "2020-05-14 12:33:56",
  "goods_name": "",
  "txcurrcd": "HKD",
  "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"
}

回傳欄位說明

欄位名稱必填類型說明
statusString交易成功狀態,固定為 1
notify_typeString通知類型:paymentrefund
pay_typeStringQFPay 支付代碼,請參考 支付方式
syssnStringQFPay 交易號(可能是「付款交易號」或「退款交易號」,取決於 notify_type
out_trade_noString商戶訂單號
txamtString金額(單位:分)。建議金額 > 200 以避免風控
txcurrcdString幣別,請參考 交易貨幣
txdtmString商戶請求時間
sysdtmString系統交易時間(常用作結算日切點)
paydtmString用戶實際支付時間
cancelString交易取消狀態:0=未取消;其他值請見下方「Cancel 定義」
respcdString固定為 0000(表示成功通知)
mchidString商戶號(多見於代理商場景)
goods_nameString商品名稱(中文請使用 UTF-8)
goods_infoString商品描述
exchange_rateString匯率(若有跨幣種轉換)
chnlsnString支付渠道交易號
chnlsn2String附加渠道交易參考
cardcdString卡號
cash_feeString實際用戶支付金額(扣除優惠後)
cash_fee_typeStringcash_fee 的幣別
cash_refund_feeString實際退款金額
cash_refund_fee_typeStringcash_refund_fee 的幣別
syssn 的語境容易混淆:在非同步通知中,syssn 代表「本次通知所對應的交易號」。若 notify_type=refund,它通常是退款交易號,而不是原始付款交易號。

Cancel 定義

意義
0未取消
1CPM:已撤銷或已退款
2MPM:已取消
3已退款
4預授權訂單已完成(Alipay)
5部分退款

通知來源 IP

請確保你的伺服器允許以下來源 IP 發送的 POST 請求:
  • 13.228.112.115
  • 18.138.115.47
  • 18.166.202.92