用街口掃碼結帳,確認付款,畫面顯示成功,整個過程不到兩秒,而且幾乎是即時扣款;這和信用卡的「三秒體驗、兩天資金流」截然不同,電子支付的即時感不是介面設計的錯覺,而是底層架構決定的;電子支付平台同時扮演發帳戶、處理交易、直接對商家結算三個角色,整條鏈路由單一平台控制,不需要在多個金融機構之間等待批次處理。
這種架構稱為 Closed Loop(閉環),對應信用卡的 Open Loop(開放迴路)四方模型,兩者在交易觸發方式、狀態機設計、Webhook 處理、對帳複雜度上都有根本差異;本文聚焦在電子支付的完整生命週期,拆解三種主要的付款模式,說明每種模式的狀態流轉,並補充 Webhook 可靠性設計的工程細節。
核心架構特點
電子支付平台在一個生態系中同時扮演三個角色:自己發行帳戶或錢包給用戶(等同 Issuer)、自建清算和風控系統(等同 Card Network)、直接與商家簽約收取服務費(等同 Acquirer);這三個角色的整合,帶來了幾個和信用卡截然不同的特性。
授權與扣款通常合一:信用卡是先授權(凍結額度)、再 Capture(正式請款)的兩步流程;電子支付的錢包模式通常是確認付款後直接扣款,不存在分開的 Capture 步驟。
資金到帳更快:信用卡走 T+1 到 T+2 的批次結算;電子支付的平台內部帳務操作在秒內完成,商家的平台帳戶餘額立即更新,撥款至銀行帳戶視平台週期而定,通常是 T+0 到 T+1。
全鏈路數據自己掌握:信用卡的消費資料分散在各 Issuer,Card Network 只看到交易流;電子支付平台能看到用戶在哪家店、買了什麼、什麼時間、搭配什麼優惠,這個數據優勢在精準行銷和反詐欺上非常關鍵。
不存在 Interchange:電子支付是閉環系統,發帳戶和收單是同一家平台,不需要 Interchange 這個跨機構的費用補貼機制,費用結構相對透明。
三種主要付款模式
電子支付的「電子支付」四個字包含了三種底層完全不同的付款方式,每種模式的交易流程和狀態機設計都不一樣。
模式一:錢包餘額付款(如街口錢包、全支付)
用戶預先儲值到平台錢包,付款時直接扣減餘額,這是速度快且架構簡單的模式。
交易流程
Step 1:用戶確認付款
Step 2:電支平台驗證用戶身份(PIN / 生物辨識)
Step 3:平台內部扣減用戶錢包餘額(帳務分錄)
Step 4:平台更新商家的收款帳戶餘額(帳務分錄)
Step 5:回傳付款成功通知(Webhook)給商家系統
Step 6:平台依週期結算,將商家餘額撥款至銀行帳戶
Step 2 到 Step 5 是平台內部的帳務操作,不需要外部銀行參與,速度極快(通常在一秒內完成)。
帳務邏輯(複式記帳)
借:用戶錢包帳戶 NT$500
貸:商家收款帳戶 NT$500
平台內部維持帳務平衡,所有的錢都存放在平台向主管機關申報的備付金帳戶裡,帳務分錄只是改變了餘額的歸屬,不涉及實際的銀行資金移動。
狀態機
INITIATED → PAID → SETTLED → REFUNDED(部分或全額)
↘ FAILED
這個模式沒有 AUTHORIZED 和 CAPTURED 兩個中間狀態,因為授權與扣款是同一個動作。
模式二:綁定銀行帳戶付款(如 LINE Pay 綁一般帳戶)
用戶綁定銀行帳戶,付款時平台向銀行發出扣款請求,資金從用戶的銀行帳戶轉入平台備付金帳戶;這條路走的是 ACH(台灣稱跨行轉帳)或直接連線銀行 API。
交易流程
Step 1:用戶確認付款
Step 2:電支平台送出扣款請求給綁定銀行
Step 3:銀行執行扣款,資金進入平台備付金帳戶
Step 4:平台記入商家收款帳戶
Step 5:Webhook 通知商家系統
關鍵差異:Step 3 可能是非同步的,部分銀行的扣款確認需要等到次日批次處理才完成,因此商家系統收到的第一個 Webhook 可能是「扣款申請已送出」而非「扣款成功」,狀態機需要能處理這個中間狀態。
狀態機
INITIATED → PENDING → PAID → SETTLED → REFUNDED
↘ FAILED
PENDING 是這個模式特有的中間狀態,代表扣款請求已送出但尚未收到銀行確認;系統需要設計超時處理機制:若 PENDING 超過合理時間(例如 24 小時)仍無銀行回應,主動查詢或將訂單標記為需要人工確認。
模式三:綁定信用卡付款(如 LINE Pay 綁信用卡)
本質上是電子支付平台在底層走信用卡的四方授權流程,對商家系統屏蔽了複雜性。
用戶確認付款
→ 電支平台收到請求
→ 平台向信用卡閘道發出授權請求(走四方模型)
→ 授權成功,平台通知商家系統(Webhook)
→ 平台日終 Capture、等待信用卡結算
→ 結算後撥款給商家
在這個模式下,商家系統不需要關心底層走的是信用卡還是錢包,電支平台已經處理了信用卡的授權、Capture、結算流程,因此只需要接收平台推送的 Webhook;對商家系統而言,這個模式的狀態機和模式一相同:
INITIATED → PAID → SETTLED → REFUNDED
↘ FAILED
但要注意,由於底層走信用卡,資金到帳的時間會比錢包模式慢,退款也需要等信用卡結算後才能退回持卡人帳戶。
電子支付的對帳特性
電子支付的對帳比信用卡簡單,但有自己的特點。
只需對兩本帳:系統帳和電支平台的結算報表,不需要處理信用卡的 Interchange 拆分,電支平台的結算報表直接列出商家應得的淨額。
備付金帳戶是對帳基準:電支平台持有的備付金帳戶餘額,應等於所有用戶錢包餘額加上商家未提領的餘額之和,這個等式若不成立,代表平台帳務有問題;作為對接平台的商家系統,不需要追蹤備付金層級的對帳,但需要確認平台結算報表中的金額和自己系統的訂單記錄一致。
退款速度差異影響對帳時序:電支平台的退款通常比信用卡快,但部分平台的退款仍需 1 到 3 個工作天才會進入結算報表;對帳系統需要以結算日而非退款申請日為基準,避免跨日的退款記錄產生假差異。
Webhook 的可靠性設計
電子支付平台在付款成功、退款完成、爭議發起等關鍵節點,都透過 Webhook 通知商家系統。可靠的 Webhook 處理是電子支付後端最核心的工程要求。
立即回 200,非同步處理
1[HttpPost("webhook/payment")]
2public async Task<IActionResult> ReceiveWebhook([FromBody] WebhookPayload payload)
3{
4 // 第一步:驗證簽名,確認請求來源合法
5 if (!VerifySignature(payload, Request.Headers["X-Signature"]))
6 return Unauthorized();
7
8 // 第二步:立即將事件寫入佇列,馬上回 200
9 await _queue.EnqueueAsync(payload);
10 return Ok(); // ← 在這裡回應,不要等處理完
11}
12
13// 背景 Worker 非同步處理
14public async Task ProcessWebhookAsync(WebhookPayload payload)
15{
16 // 冪等性檢查、業務邏輯處理、更新訂單狀態
17}
電支平台通常設定 3 到 10 秒的回應超時;若在 Controller 裡同步處理,一旦下游有延遲,平台會誤以為通知失敗並重試,產生重複事件。
冪等性處理
電支平台在未收到 200 回應時會重試 Webhook,因此系統要能安全地處理重複事件:
1public async Task ProcessWebhookAsync(WebhookPayload payload)
2{
3 // 以 event_id 作為冪等鍵,防止重複處理
4 var alreadyProcessed = await _db.WebhookEvents
5 .AnyAsync(e => e.EventId == payload.EventId);
6
7 if (alreadyProcessed)
8 {
9 _logger.LogInformation("Duplicate webhook {EventId}, skipping", payload.EventId);
10 return; // 靜默忽略,不拋錯
11 }
12
13 // 在同一個 DB Transaction 內寫入事件記錄並處理業務邏輯
14 // 確保原子性:事件記錄和訂單狀態更新同時成功或同時失敗
15 using var tx = await _db.BeginTransactionAsync();
16 await _db.WebhookEvents.AddAsync(new WebhookEvent { EventId = payload.EventId });
17 await UpdateOrderStatusAsync(payload);
18 await tx.CommitAsync();
19}
簽名驗證
電支平台的 Webhook 簽名機制通常是 HMAC-SHA256,驗證方式大同小異,但每家平台的簽名欄位和計算方式可能不同,需要依照各平台文件實作:
1private bool VerifySignature(WebhookPayload payload, string receivedSignature)
2{
3 var secret = _config["PaymentGateway:WebhookSecret"];
4 var rawBody = JsonSerializer.Serialize(payload);
5
6 using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
7 var expectedSignature = Convert.ToHexString(
8 hmac.ComputeHash(Encoding.UTF8.GetBytes(rawBody))
9 ).ToLower();
10
11 // 使用 constant-time 比較防止 timing attack
12 return CryptographicOperations.FixedTimeEquals(
13 Encoding.UTF8.GetBytes(expectedSignature),
14 Encoding.UTF8.GetBytes(receivedSignature)
15 );
16}
PENDING 狀態的超時處理
綁定銀行帳戶模式下,PENDING 狀態的訂單若長時間沒有收到銀行確認的 Webhook,需要排程任務定期處理:
1// 每小時執行一次,處理超時的 PENDING 訂單
2public async Task HandlePendingTimeoutsAsync()
3{
4 var timeout = DateTime.UtcNow.AddHours(-24);
5 var staleOrders = await _db.Orders
6 .Where(o => o.Status == OrderStatus.Pending
7 && o.CreatedAt < timeout)
8 .ToListAsync();
9
10 foreach (var order in staleOrders)
11 {
12 // 主動向電支平台查詢最新狀態
13 var result = await _gateway.QueryPaymentStatusAsync(order.GatewayOrderId);
14
15 if (result.IsPaid)
16 order.MarkPaid();
17 else if (result.IsFailed)
18 order.Fail();
19 // 若平台也不確定,標記為需要人工確認
20 else
21 order.MarkNeedsReview();
22 }
23
24 await _db.SaveChangesAsync();
25}
26
27---
28
29## 為多個電支平台設計統一介面
30
31若系統需要同時對接街口、LINE Pay、全支付等多個電支平台,不應針對每個平台寫死邏輯,而應抽象出統一介面:
32
33```csharp
34public interface IPaymentGateway
35{
36 string GatewayName { get; }
37 Task<PaymentResult> CreatePaymentAsync(PaymentRequest request);
38 Task<RefundResult> RefundAsync(string gatewayOrderId, decimal amount);
39 Task<PaymentStatus> QueryStatusAsync(string gatewayOrderId);
40}
41
42public class JkoPayGateway : IPaymentGateway
43{
44 public string GatewayName => "jkopay";
45 // 街口特定的 API 實作
46}
47
48public class LinePayGateway : IPaymentGateway
49{
50 public string GatewayName => "linepay";
51 // LINE Pay 特定的 API 實作
52}
這個設計讓核心業務邏輯不需要關心底層是哪個電支平台,新增支付方式時只需要新增一個實作類別,不動核心邏輯。
電子支付的生命週期因為 Closed Loop 的架構特性,比信用卡更即時、狀態機更簡潔,但也有自己獨特的工程挑戰。
- 三種模式的狀態機設計不同:錢包模式是最簡潔的 INITIATED → PAID → SETTLED;綁帳戶模式多了一個 PENDING 中間狀態,需要超時處理機制;綁信用卡模式從商家視角看和錢包模式相同,但底層時間跨度接近信用卡。
- PENDING 狀態需要主動查詢:不能只依賴平台 Webhook,當 Webhook 超時未到時,排程任務主動查詢平台狀態是必要的備援機制。
- Webhook 冪等性在電子支付同樣關鍵:電支平台的重試機制和信用卡閘道相同,以 event_id 做去重複、在同一個 Transaction 內寫入事件記錄和更新訂單狀態,是防止重複處理的標準做法。
- 對帳比信用卡簡單,但仍需結算日基準:以結算日而非訂單建立日作為對帳基準,才能準確處理退款的跨日時序,避免假差異單。
- 統一介面讓多平台對接可維護:IPaymentGateway 介面把各平台的差異封裝起來,讓系統在對接第三家、第四家平台時,不需要動核心業務邏輯。
理解信用卡以及電子支付交易的完整生命週期,才能設計出完整的支付系統;下一步將深入研究該如何管理訂單的完整生命週期。
本文為個人學習筆記,持續更新中。