金流 API 接起來大概兩週,剩下的維護成本可能跟著你兩年。這是很多電商團隊在第一次自建結帳流程後才理解的事。串接刷卡、ATM、超商代收的 API 文件其實都不難讀,難的是 API 之外的世界。
一、非同步通知遺失,是預設會發生的事
大部分金流服務商(無論國內的綠界、藍新,或國外的 Stripe)採用的都是 webhook 模式:使用者付完款,金流伺服器再回呼你的後端確認。問題是這個回呼不保證一次成功。網路抖動、你的伺服器剛好重啟、SSL 憑證一瞬間驗證失敗,都會讓通知掉在地上。
設計上一定要做兩件事:
- 冪等性:同一筆訂單收到多次通知,最終狀態必須一致。
- 主動輪詢補位:對「使用者已經跳轉回來但後端還沒收到通知」的訂單,定時去打查詢 API 確認。
舉個示意的處理骨架:
# 示意:實際 API 參數請依各金流文件
def handle_payment_callback(order_id, status, txn_id):
order = Order.lock_for_update(order_id)
if order.status == 'PAID':
return 'OK' # 已處理過,直接回應成功
if status == 'SUCCESS':
order.mark_paid(txn_id)
return 'OK'
看似簡單,但少了那把 row lock,或少了第一個提前 return,就會在促銷尖峰發生重複出貨。
二、對帳與爭議款,是另一個系統
金流商每天(或每月)會給你一份對帳檔,格式通常是 CSV 或 Excel。你以為訂單系統的 PAID 狀態就等於錢進來了?不一定。手續費、退刷、爭議款(chargeback)、跨境匯差,這些會讓你帳上的訂單金額跟銀行實際入帳對不起來。
假設一家中型電商每天有數千筆訂單,光是人工比對對帳檔就足以養出一個專職會計。比較務實的做法是:
- 設計訂單資料表時,就預留
settled_amount、fee、settled_at欄位。 - 寫一支對帳腳本,每天自動把金流商的對帳檔拉進來、跟內部訂單做差異比對,列出 mismatch 清單給人看。
- 退款流程要走獨立的狀態機,不要把退款硬塞進原訂單的 status 欄位。
三、跨境的稅、幣別與 3DS
如果你打算做跨境,事情又會多一層。不同國家對 3D Secure 的強制程度不同,歐盟 SCA 一旦觸發、轉換率會立刻反映出來;幣別轉換要決定是讓買家看當地幣別還是台幣;稅務上日本的消費稅、歐盟的 VAT、美國各州 sales tax,金流串接時就要決定誰來算、算在哪一層。
這部分沒有萬用解。常見的取捨是:規模小就用 Stripe、PayPal 這類已經把多數合規包好的服務;規模大到手續費咬人時,再考慮分區接在地金流。
我們的觀察
在報價金流相關專案時,我們的經驗法則是:API 本身的串接時間,只佔整體工時的一小部分;真正吃時間的是冪等設計、對帳機制與退款流程。如果一份提案只報了「串接 X 家金流」的工,沒有把對帳與異常處理拆出來,那後期幾乎一定會追加。先把這三塊講清楚,對雙方都好。
