本教材介紹第三方支付平台的全端架構與 API 對接方式,並以類似 Stripe.com、PayPal 的產品型態作為參考。 內容涵蓋商戶前端、商戶後端、支付平台、收單銀行、卡組織、Webhook、退款、對帳、安全與錯誤處理。
注意:Stripe、PayPal 的實際 API 會隨版本與地區改變。本文使用教學用 API 形狀說明設計思想,實作時應以官方文件與合約為準。
目錄
Part A:第三方支付全貌
Part B:商戶端前後端整合
Part C:支付平台後端設計
Part D:營運、安全與可靠性
Part A:第三方支付全貌
1. 第三方支付在解決什麼問題?
第三方支付平台讓商戶不用直接串接每一家銀行、卡組織、錢包與地區性支付方式,就能接受付款。
它提供:
- 統一 Checkout
- 信用卡與金融卡收款
- 電子錢包付款
- PayPal 類帳戶餘額付款
- 授權與請款
- 退款
- 訂閱扣款
- 發票或收據
- Webhook 事件
- 對帳報表
- 詐欺偵測
- 爭議款處理
- 多幣別與匯率
對商戶而言,第三方支付平台的價值是:
- 降低金流整合成本。
- 減少 PCI 合規負擔。
- 提供穩定 API。
- 支援多種付款方式。
- 封裝複雜的金融網路與清算流程。
2. 支付流程中的角色
Customer
付款的消費者。可能使用信用卡、金融卡、PayPal 帳戶、Apple Pay、Google Pay、銀行轉帳或其他本地支付方式。
Merchant
收款的商戶,例如電商、SaaS、外送平台、課程平台。
Payment Service Provider
第三方支付平台,也就是類 Stripe、PayPal、Adyen、Braintree 的角色。它負責提供 API、Checkout、風控、路由與結算能力。
Acquirer
收單銀行或收單機構。它代表商戶接收卡片交易。
Card Network
卡組織,例如 Visa、Mastercard、JCB、American Express。它負責路由卡片交易與制定網路規則。
Issuer
發卡銀行。它決定是否授權消費者這筆卡片交易。
Merchant Backend
商戶自己的後端。它負責建立訂單、建立付款意圖、接收 webhook、更新訂單狀態。
3. 類 Stripe / PayPal 的平台架構
Customer Browser / Mobile App
|
| checkout page
v
Merchant Frontend
|
| create order
v
Merchant Backend
|
| create payment intent / order
v
Payment Platform API
|
+--> Risk Engine
+--> Tokenization Service
+--> Payment Orchestrator
+--> Card Processor Adapter
+--> Wallet Adapter
+--> Ledger Service
+--> Webhook Service
+--> Settlement Service
|
v
Acquirer / Card Network / Issuer / Wallet Network
支付平台的主要職責
- 接收商戶 API 請求。
- 儲存商戶設定與 API key。
- 建立 payment intent 或 order。
- 將卡號 token 化。
- 呼叫收單或錢包網路。
- 管理付款狀態機。
- 寫入平台 ledger。
- 發送 webhook。
- 產生對帳與結算資料。
4. 第三方支付與銀行系統的差異
銀行系統通常以「帳戶」與「銀行核心帳務」為中心;第三方支付平台以「商戶收款」與「多支付方式路由」為中心。
重要差異:
- 銀行更關注帳戶真實餘額與法定帳務。
- 第三方支付更關注交易路由、授權、請款、退款、結算。
- 第三方支付常要處理多家外部網路的不同回應格式。
- 第三方支付非常依賴 webhook,因為付款結果可能延遲。
- 商戶端不能只依賴前端成功頁,必須以 webhook 或後端查詢為準。
Part B:商戶端前後端整合
5. 商戶前端 Checkout 流程
典型一次性付款流程:
Customer clicks checkout
|
v
Merchant Frontend calls Merchant Backend
|
v
Backend creates PaymentIntent at PSP
|
v
Frontend receives clientSecret
|
v
Customer enters payment method
|
v
Payment SDK confirms payment
|
v
Frontend shows processing / result
|
v
Merchant Backend receives webhook
|
v
Order marked paid
前端通常不應直接用商戶 secret key 呼叫支付 API。正確做法是:
- 前端呼叫商戶後端。
- 商戶後端使用 secret key 建立付款。
- 後端只回傳前端需要的
clientSecret或 approval URL。 - 前端使用支付平台 SDK 完成付款資料收集與確認。
前端 Checkout 頁面需要處理
- 商品明細
- 稅金、運費、折扣
- 付款方式選擇
- 卡片輸入元件
- 3D Secure 驗證跳轉或彈窗
- 付款處理中狀態
- 付款結果頁
- 錯誤訊息與重新付款
6. 商戶後端的責任
商戶後端是支付整合中最重要的安全邊界。
它負責:
- 建立訂單。
- 檢查商品價格是否正確。
- 建立 payment intent 或 PayPal order。
- 保存支付平台回傳的 payment id。
- 接收 webhook。
- 驗證 webhook 簽章。
- 更新訂單狀態。
- 處理退款請求。
- 執行對帳。
它不應:
- 相信前端傳來的金額。
- 把 secret API key 傳給前端。
- 僅靠前端 redirect success 判斷付款成功。
- 在 webhook 未驗證時更新訂單。
- 將同一筆訂單重複建立多筆有效付款。
7. Payment Intent / Order 模型
Stripe 類平台常用 PaymentIntent 模型;PayPal 類平台常用 Order / Capture 模型。名稱不同,但核心概念相似:先建立一個「支付意圖」,再讓客戶完成授權或付款。
PaymentIntent 教學模型
PaymentIntent
- id
- merchantId
- orderId
- amount
- currency
- status
- paymentMethodTypes
- clientSecret
- metadata
- createdAt
- updatedAt
常見狀態:
requires_payment_method
requires_confirmation
requires_action
processing
succeeded
canceled
PayPal Order 教學模型
Order
- id
- merchantId
- amount
- currency
- intent
- status
- approvalUrl
- captures
- createdAt
常見狀態:
CREATED
APPROVED
COMPLETED
VOIDED
PAYER_ACTION_REQUIRED
8. 前端卡片資料處理與 Tokenization
商戶前端應使用支付平台提供的 hosted fields 或 SDK 元件收集卡片資料。
原因:
- 卡號不經過商戶伺服器,可降低 PCI 範圍。
- 支付平台能處理格式化、驗證與 tokenization。
- 可支援 3D Secure、Apple Pay、Google Pay 等流程。
錯誤做法
Frontend collects card number
-> sends raw card number to Merchant Backend
-> Merchant Backend sends card number to PSP
這會大幅提高商戶 PCI 合規範圍。
建議做法
Frontend uses PSP SDK
-> card data goes directly to PSP
-> PSP returns token / payment method id
-> Merchant Backend references token only
商戶系統中應只保存:
- payment method id
- card brand
- last4
- expiry month/year
- billing country
不應保存完整卡號與 CVC。
9. 支付狀態頁與使用者體驗
付款後不一定能立即知道最終結果。
前端可能看到:
- 付款成功
- 付款失敗
- 需要驗證
- 處理中
- 使用者取消
- 外部頁面跳回
最重要原則
商戶訂單狀態應以後端確認為準,而不是只靠前端畫面。
前端可以顯示:
Payment is processing. We will update your order once payment is confirmed.
後端應透過 webhook 或主動查詢支付平台 API 更新訂單狀態。
Part C:支付平台後端設計
10. 支付平台服務分層
Public API Layer
|
Authentication / Merchant Context
|
Payment Orchestrator
|
Risk Engine
|
Payment Method Services
|
Processor Adapters
|
Ledger / Event / Webhook / Settlement
Public API Layer
負責:
- API key 驗證
- request schema validation
- idempotency key handling
- rate limiting
- response normalization
Payment Orchestrator
負責:
- 根據 payment method 選擇處理器。
- 管理付款狀態機。
- 處理同步與非同步結果。
- 呼叫風控。
- 寫入事件。
- 觸發 webhook。
Processor Adapter
每家收單、錢包或本地支付方式的 API 都不一樣,因此需要 adapter。
Adapter 負責:
- 將平台內部請求轉成外部 API 格式。
- 將外部 response 轉成內部標準格式。
- 處理 timeout、retry、錯誤碼。
- 保存外部 reference id。
11. 核心資料模型
Merchant
Merchant
- id
- name
- status
- country
- defaultCurrency
- riskLevel
- payoutSchedule
- createdAt
ApiKey
ApiKey
- id
- merchantId
- keyHash
- mode
- scopes
- lastUsedAt
- revokedAt
API key 不應明文保存,只保存 hash。
PaymentIntent
PaymentIntent
- id
- merchantId
- merchantOrderId
- amount
- currency
- status
- captureMethod
- clientSecretHash
- metadata
- createdAt
- updatedAt
Charge
Charge
- id
- paymentIntentId
- amount
- currency
- status
- processor
- processorReference
- authorizedAt
- capturedAt
Refund
Refund
- id
- chargeId
- amount
- currency
- status
- reason
- processorReference
- createdAt
WebhookEndpoint
WebhookEndpoint
- id
- merchantId
- url
- enabledEvents
- signingSecret
- status
WebhookEvent
WebhookEvent
- id
- merchantId
- type
- objectId
- payload
- deliveryStatus
- attemptCount
- createdAt
12. 付款授權、請款與入帳
信用卡交易通常包含:
- Authorization:向發卡銀行確認這筆金額可授權。
- Capture:實際請款,讓商戶取得款項。
- Settlement:卡組織與收單進行清算。
- Payout:支付平台把款項撥給商戶。
自動請款
電商常見流程:
authorize + capture immediately
付款成功後,訂單可以進入 paid。
手動請款
飯店、租車、預授權常見流程:
authorize now
capture later
例如先授權 5000 元,最後只請款 4200 元。
平台內部 Ledger
支付平台通常也有自己的 ledger:
Customer payment received +1000
Processing fee -30
Merchant pending balance +970
Payout to merchant -970
這讓平台可以追蹤每筆錢的來源與流向。
13. 退款、取消與爭議款
Cancel
取消通常發生在尚未 capture 前。
PaymentIntent authorized
-> cancel
-> authorization released
Refund
退款通常發生在已 capture 後。
Charge captured
-> create refund
-> refund processing
-> refund succeeded
退款可能是:
- 全額退款
- 部分退款
- 多次部分退款
後端必須檢查:
- 累積退款金額不能超過已請款金額。
- 交易狀態是否允許退款。
- 幣別是否一致。
- 是否已產生爭議款。
Dispute / Chargeback
爭議款是消費者向發卡銀行提出異議。平台需要:
- 通知商戶。
- 收集證據。
- 提交證據給卡組織或收單。
- 根據最終結果調整商戶餘額。
14. API 對接細節
以下 API 為教學版設計,用來理解 Stripe / PayPal 類 API 的對接方式。
建立 PaymentIntent
商戶後端呼叫:
POST /v1/payment_intents
Authorization: Bearer sk_test_xxx
Idempotency-Key: order_10001_create_payment
Content-Type: application/json
{
"amount": 1999,
"currency": "usd",
"merchantOrderId": "order_10001",
"captureMethod": "automatic",
"paymentMethodTypes": ["card"],
"metadata": {
"cartId": "cart_abc"
}
}
回應:
{
"id": "pi_123",
"amount": 1999,
"currency": "usd",
"status": "requires_payment_method",
"clientSecret": "pi_123_secret_abc"
}
前端只拿 clientSecret,不拿 secret API key。
前端確認付款
前端使用支付 SDK:
const result = await paymentSdk.confirmPayment({
clientSecret,
paymentElement,
returnUrl: "https://merchant.example.com/payment/return"
});
if (result.error) {
showPaymentError(result.error.message);
}
這段程式的重點不是語法,而是資料流:卡片資料交給支付平台 SDK 處理,不進入商戶後端。
查詢 PaymentIntent
GET /v1/payment_intents/pi_123
Authorization: Bearer sk_test_xxx
{
"id": "pi_123",
"status": "succeeded",
"latestCharge": "ch_123"
}
PayPal 類建立 Order
POST /v2/checkout/orders
Authorization: Bearer <access_token>
PayPal-Request-Id: order_10001_create
Content-Type: application/json
{
"intent": "CAPTURE",
"purchase_units": [
{
"reference_id": "order_10001",
"amount": {
"currency_code": "USD",
"value": "19.99"
}
}
],
"application_context": {
"return_url": "https://merchant.example.com/payment/success",
"cancel_url": "https://merchant.example.com/payment/cancel"
}
}
回應會包含 approval URL:
{
"id": "paypal_order_123",
"status": "CREATED",
"links": [
{
"rel": "approve",
"href": "https://www.paypal.com/checkoutnow?token=paypal_order_123"
}
]
}
前端導向 approval URL,消費者在 PayPal 完成確認後回到商戶網站。
Capture PayPal Order
POST /v2/checkout/orders/paypal_order_123/capture
Authorization: Bearer <access_token>
PayPal-Request-Id: order_10001_capture
{
"id": "paypal_order_123",
"status": "COMPLETED",
"purchase_units": [
{
"payments": {
"captures": [
{
"id": "capture_123",
"status": "COMPLETED",
"amount": {
"currency_code": "USD",
"value": "19.99"
}
}
]
}
}
]
}
15. Webhook 設計與驗證
Webhook 是支付整合的核心。
付款平台會在狀態變更時呼叫商戶後端:
POST /webhooks/payment-provider
Provider-Signature: t=1777130000,v1=abcdef
Content-Type: application/json
{
"id": "evt_123",
"type": "payment_intent.succeeded",
"created": 1777130000,
"data": {
"object": {
"id": "pi_123",
"merchantOrderId": "order_10001",
"status": "succeeded",
"amount": 1999,
"currency": "usd"
}
}
}
Webhook 驗證流程
- 取得原始 request body。
- 讀取 signature header。
- 使用 webhook signing secret 重新計算 HMAC。
- 比對簽章。
- 檢查 timestamp 是否在容許時間窗內。
- 檢查 event id 是否已處理。
- 寫入 event log。
- 更新訂單狀態。
- 回傳 2xx。
Webhook handler 範例邏輯
receive webhook
-> verify signature
-> if event already processed, return 200
-> store event
-> switch event.type
payment_intent.succeeded -> mark order paid
payment_intent.payment_failed -> mark payment failed
charge.refunded -> update refund status
dispute.created -> open dispute case
-> return 200
為什麼 webhook 要冪等?
支付平台可能因為網路 timeout 重送同一個 webhook。商戶後端必須能接受重複事件,而且不會重複出貨、重複加值或重複寄送商品。
Part D:營運、安全與可靠性
16. 冪等、重試與錯誤處理
商戶 API 請求冪等
建立付款、capture、refund 都應使用 idempotency key。
Idempotency-Key: order_10001_refund_001
支付平台應保證同一個 key 重複請求時回傳相同結果。
常見錯誤分類
- Validation error:金額、幣別、欄位格式錯誤。
- Authentication error:API key 錯誤或權限不足。
- Card declined:發卡銀行拒絕。
- Insufficient funds:餘額不足。
- Requires action:需要 3D Secure 或使用者額外驗證。
- Processing error:外部網路暫時錯誤。
- Timeout:請求超時,但結果不一定失敗。
Timeout 的正確處理
如果 capture API timeout,不應立刻再送一筆不同 key 的 capture。
建議:
- 使用相同 idempotency key retry。
- 或查詢原 payment / order 狀態。
- 等 webhook 回補最終結果。
17. 對帳、結算與撥款
支付成功不代表商戶馬上拿到錢。
典型流程:
Customer pays
-> authorization
-> capture
-> platform records charge
-> network settlement
-> merchant balance becomes available
-> payout to merchant bank account
對帳資料來源
商戶應對照:
- 自己的 orders
- 支付平台 charges
- refunds
- disputes
- payouts
- bank statement
對帳常見差異
- 付款成功但 webhook 延遲。
- webhook 成功但商戶更新訂單失敗。
- 退款部分成功。
- 爭議款扣回。
- 手續費造成入帳金額與訂單金額不同。
- 匯率與跨境費用造成差異。
撥款 Payout
支付平台常會扣除:
- processing fee
- refund
- chargeback
- reserve
- tax or withholding
再把可撥款餘額轉到商戶銀行帳戶。
18. 安全與 PCI DSS 基本概念
API Key 管理
- Secret key 只放後端。
- Publishable key 可以放前端,但權限有限。
- API key 要能 rotate。
- 被洩漏的 key 要可 revoke。
- 日誌與錯誤回報不得輸出完整 key。
PCI DSS
PCI DSS 是處理卡片資料時的重要安全標準。
降低 PCI 範圍的方法:
- 使用支付平台 hosted checkout。
- 使用支付平台 card element / hosted fields。
- 不讓卡號通過商戶伺服器。
- 不保存 CVC。
- 不在 log 中記錄 PAN。
Webhook 安全
- 驗證簽章。
- 使用 HTTPS。
- 檢查 timestamp,避免 replay。
- event id 去重。
- 不把 webhook endpoint 當成公開無驗證入口。
前端安全
- 不在前端保存 secret key。
- 不信任 query string 中的 success 狀態。
- 不把 clientSecret 當作長期秘密。
- 支付完成後由後端查詢或 webhook 確認。
19. 測試策略與 Sandbox
Sandbox 測試項目
- 成功付款
- 卡片被拒
- 3D Secure 成功
- 3D Secure 失敗
- 使用者取消付款
- capture timeout
- refund 成功
- 部分退款
- webhook 重送
- webhook 順序顛倒
- API key 權限不足
測試卡號與測試帳戶
支付平台通常提供測試卡號與 sandbox 帳戶。測試時要確認:
- 測試 key 與正式 key 分離。
- 測試 webhook endpoint 與正式 endpoint 分離。
- 測試資料不會觸發真實扣款。
- CI 使用 mock 或 sandbox,不使用 production key。
Webhook 本地測試
常見作法:
local server
<- tunnel service
<- payment provider webhook
或使用支付平台 CLI 將 webhook event 轉發到本機。
20. 常見錯誤與面試重點
常見錯誤
- 前端直接呼叫 secret API。
- 後端相信前端傳來的金額。
- 只靠 redirect success 更新訂單。
- 沒驗證 webhook signature。
- webhook handler 不冪等。
- timeout 後用新 idempotency key 重送付款。
- 退款沒有檢查累積金額。
- 訂單與 payment intent 狀態沒有清楚對應。
- 沒處理
requires_action。 - 不做對帳,只相信單次 API response。
面試重點
如果面試被問「設計一個 Stripe 類支付系統」,可依序回答:
- 角色:customer、merchant、PSP、acquirer、issuer、card network。
- 商戶整合:frontend SDK、backend create intent、webhook update order。
- API:create intent、confirm、capture、refund、retrieve。
- 狀態機:requires_payment_method、requires_action、processing、succeeded、failed。
- 安全:secret key 後端保存、tokenization、PCI、webhook signature。
- 可靠性:idempotency、retry、timeout、event dedup。
- 平台內部:orchestrator、processor adapter、ledger、settlement。
- 營運:refund、chargeback、reconciliation、payout。
商戶端整合範例:完整資料流
以下是一個完整的電商付款資料流。
1. Customer clicks "Pay"
2. Frontend calls POST /orders
3. Merchant Backend creates local order with status PENDING_PAYMENT
4. Merchant Backend calls PSP POST /payment_intents
5. PSP returns paymentIntent id and clientSecret
6. Frontend uses PSP SDK with clientSecret
7. Customer enters card and completes 3DS if required
8. PSP confirms payment
9. Frontend redirects to /payment/result?orderId=order_10001
10. Merchant Backend receives webhook payment_intent.succeeded
11. Merchant Backend verifies signature and marks order PAID
12. Frontend polls GET /orders/order_10001
13. Customer sees final paid state
訂單狀態與付款狀態對應
Order PENDING_PAYMENT
<- PaymentIntent requires_payment_method
Order PAYMENT_ACTION_REQUIRED
<- PaymentIntent requires_action
Order PAYMENT_PROCESSING
<- PaymentIntent processing
Order PAID
<- PaymentIntent succeeded
Order PAYMENT_FAILED
<- PaymentIntent payment_failed or canceled
總結
第三方支付系統的重點不是單純「扣款 API」,而是把複雜的支付網路、風控、狀態機、Webhook、退款、爭議款、對帳與結算包裝成商戶可用的 API。
對商戶開發者來說,最重要的是:
- secret key 只放後端。
- 前端用支付 SDK 收集付款資料。
- 金額與訂單資料由後端決定。
- 建立付款、退款、capture 都要使用冪等鍵。
- 訂單成功以 webhook 或後端查詢為準。
- webhook 必須驗證簽章且支援重複事件。
- timeout 不等於付款失敗。
- 對帳與撥款是金流系統不可省略的一部分。