本頁涵蓋所有 webhook 事件,橫跨多個平台範疇(交易活動、存款、元件流程,以及 OAuth 帳戶連結),而非屬於單一功能。
運作方式
- 在開發者平台為你的應用程式註冊一個 webhook URL。
- 選擇要監聽的事件類型(或訂閱全部)。
- 當符合的事件發生時,Fluz 會以 HTTP
POST將簽名的 JSON 載荷送到你的 URL。 - 你的伺服器驗證簽章、以
2xx回應並處理該事件。
依應用程式類型的 Webhooks
事件如何導向到你的應用程式,取決於你的應用程式模型。私人應用程式 — 你的自有帳戶
Webhooks 會針對你的自有帳戶的活動觸發。你所擁有的帳戶上任何交易、拒絕或存款,都會觸發在你的應用程式上註冊的 webhooks。 常見使用情境: 當虛擬卡交易被授權或結算時發送通知;即時拒絕警示;監控你的消費帳戶上的存款與餘額變化。公共應用程式(OAuth) — 代表使用者行動
Webhooks 會針對已授權你的應用程式之帳戶的活動觸發。當使用者透過 OAuth 授與你的應用程式存取權時,他們的事件會導向到你註冊的 webhooks——前提是該使用者的 OAuth 授權包含所需的範圍(scopes)。不論使用者是透過你的直接 API 串接,還是透過嵌入式元件進行互動,皆適用;關鍵在於使用者與你的應用程式之間存在 OAuth 關係。 常見使用情境: 知道使用者已將其帳戶連結(或重新連結)到你的應用程式;監控已連結帳戶的虛擬卡消費;即時拒絕通知;追蹤存款完成;接收 KYC 與 KYB 狀態更新。元件應用程式
元件應用程式是特殊的公共應用程式。事件的導向方式相同(基於 OAuth 關係),此外,元件應用程式還支援如轉帳完成與禮品卡購買等元件專屬事件。事件類型
只有當你的應用程式——以及對於公共/OAuth 應用程式而言,個別使用者的 OAuth 授權——持有所需的範圍(scopes)時,Fluz 才會投遞事件。沒有必需範圍的事件(例如OAUTH_USER_LINKED)會投遞給任何已訂閱的公共/OAuth 應用程式。
交易事件
涵蓋完整的交易生命週期。適用於所有應用程式類型。存款事件
KYC 與 KYB 事件
適用於公共/OAuth 與元件應用程式。與OAUTH_USER_LINKED 類似,這些事件在私人應用程式中沒有對應——它們只會對透過 OAuth 關係連結的帳戶觸發,且僅在你的應用程式(與使用者)的 OAuth 授權包含所需的範圍時投遞。
資金來源事件
僅限測試環境
FUNDING_SOURCE_STATUS_UPDATE 目前僅在測試(staging)環境中投遞。正式環境尚未發出此事件;在正式推出之前,正式環境的應用程式不會收到此事件,屆時本頁也會隨之更新。LIST_PAYMENT 的 OAuth 使用者,或私人應用程式所屬帳戶下的任何使用者。
這三種情況都由同一種事件類型涵蓋;請依
changeType(ADDED、UPDATED、DELETED)分流,而非依事件名稱。使用者的 Fluz 現金餘額並非資金來源,永遠不會產生此事件。
此事件是由資金來源本身的變更所發出,因此無論變更是在哪裡進行——Fluz 行動應用程式、網頁應用程式,或嵌入式元件——都會觸發。
OAuth 事件
適用於公共/OAuth 與元件應用程式。OAUTH_USER_LINKED 僅投遞給公共/OAuth 應用程式——私人應用程式訂閱者不會收到。由於它沒有範圍需求,你會對每個與你的應用程式連結或重新連結的使用者收到此事件,無論他們授與了哪些範圍。可用於建立或更新你本地的已連結使用者紀錄、擷取授與的範圍集合,並透過 externalReferenceId 對應你自己的使用者識別碼。
元件專屬事件
適用於使用者透過 Fluz 嵌入流程互動的元件與 OAuth 串接。📘 命名注意:WIDGET_DEPOSIT_COMPLETE與WIDGET_WITHDRAW_COMPLETE描述的是客戶↔應用程式之間的「轉帳」;DEPOSIT/WITHDRAW的用語是歷史沿用。請將「deposit」視為「客戶 → 應用程式」,「withdraw」視為「應用程式 → 客戶」。
設定 webhooks
1. 開啟開發者平台
前往 開發者平台 並選擇你的應用程式。2. 開啟 Webhooks 區段
- OAuth 應用程式: OAuth 分頁 → Webhook URLs。
- 元件應用程式: Widget 分頁 → Webhook URLs。
- API / 私人應用程式: 應用程式設定中的 Webhook URLs 區段。
3. 新增 webhook URL
點擊 Add new URL 並輸入你的 HTTPS 端點(例如,https://api.yourapp.com/webhooks/fluz)。
4. 選擇事件
選擇你想接收的事件類型。5. 儲存
點擊 Create Webhook。你的端點會立即開始接收事件。管理 webhooks
- 多個端點 — 每個應用程式可以註冊多個 webhook URL。
- 變更訂閱事件 — 刪除該 webhook,並以新的事件選擇重新建立。
- 移除 webhook — 點擊其旁的 Remove。該 webhook 會立即封存並停止接收事件。
接收 webhooks
請求格式
每個 webhook 都以 HTTPPOST 傳遞,包含以下標頭:
主體為 JSON 物件,且每個載荷都包含
eventType 欄位來識別事件。
端點需求
- 僅限 HTTPS — 僅使用 HTTP 的端點會在註冊時被拒絕。
- 能公開存取 並可接受
POST請求。 - 在 30 秒內以
2xx回應。 非2xx回應或逾時會觸發重試。 - 驗證每個請求的 HMAC 簽章。
驗證簽章
每次投遞都包含X-HMAC-Signature 標頭——以你應用程式的 API 金鑰,對原始 JSON 主體計算出的 HMAC-SHA256 雜湊值。請在信任任何載荷前,一律先行驗證。
⚠️ 請針對原始請求主體驗證。 對 Fluz 傳送的完全相同位元組計算 HMAC——不要以已解析的 JSON 重新序列化。重新字串化可能會重排鍵值順序或變更空白字元,導致有效簽章驗證失敗。以下範例會擷取原始主體,原因即在此。
Node.js (Express)
Python (Flask)
回應 webhooks
你的端點必須:- 在 30 秒內以
2xx狀態回應。 - 迅速回應——先確認,然後再非同步處理。
- 能透過 HTTPS 存取。你的端點不得:
- 回應重新導向(
3xx)。 - 對有效的 webhooks 回應
4xx/5xx(這會觸發重試)。
重試政策
一旦你的端點恢復,新的事件會自動恢復投遞。若要重新傳送已耗盡重試的事件,請聯絡支援並提供相關的
X-Event-ID。
冪等性與順序
Webhooks 可能會被投遞多次,且不保證投遞順序。- 使用
X-Event-ID標頭進行去重。將已處理的 ID 儲存(正式環境使用 Redis 或資料庫),對已處理的事件跳過不處理。 - 依資料排序而非到達順序。 若順序很重要,請依載荷中的時間戳(
createdAt、updatedAt、transactionDateTime)與事件 ID 排序。
識別應用程式與使用者
- 使用者:
userId為 Fluz 使用者 ID。對於 OAuth/元件事件,externalReferenceId對應到你在 OAuth 流程中的「你自己的」使用者識別碼。 - 應用程式: 交易載荷包含
connectedAppId與connectedAppName。若你將多個應用程式導向同一端點,請依connectedAppId分流。對於OAUTH_USER_LINKED,應用程式以appId識別。
載荷參考
每個載荷都包含eventType。欄位可用性會依事件而異;為了前向相容,處理器應忽略未識別的欄位。
📘 關於status值的說明。 對已建立/已更新的交易,status欄位為PENDING、SETTLED或FAILED之一。被拒的交易會帶有DECLINED(或FAILED)的status。本頁較早的草稿曾顯示COMPLETED為一種狀態——實際上不會發出該值;請使用SETTLED來判定交易已最終完成。
交易已建立(TRANSACTION_CREATE)
對任何新交易觸發——虛擬卡購買、存款、轉帳等。
交易已更新(TRANSACTION_UPDATE)
當交易的狀態或細節變更時觸發——例如,待處理授權轉為結算。
TRANSACTION_CREATE 相同之處沿用,另包含 updatedAt(ISO 8601)標示變更發生時間。userId、connectedAppId、connectedAppName 與 TRANSACTION_CREATE 中一致,以便你能在整個生命週期中一致識別使用者與應用程式。status 轉為 SETTLED 即代表先前待處理的交易已經定案。
isReversal 在此處與 TRANSACTION_CREATE 中意義相同。見撤銷與退款。
交易被拒(TRANSACTION_DECLINE)
當交易被拒時觸發。包含結構化的拒絕原因,供你的應用程式採取行動。
依交易狀況可能會出現其他選用欄位(例如
merchantId、merchantCity、merchantState、merchantCountry、cardDisplayName、virtualCardProgram、channel、bankAccountNickname、bankAccountLastFour)。用不到的可以忽略。
串接單筆購買的事件
一筆虛擬卡購買通常會產生不只一個交易事件。有兩個欄位可以將它們串在一起:referenceId是 Fluz 的購買 ID。該筆授權、其結算、任何額外的結算分段,以及該筆購買的任何退款,都會帶有相同的值。請依此欄位分組。transactionId用於識別單一帳務紀錄。待處理授權與其結算會共用同一個值,因為結算是以同一筆紀錄的TRANSACTION_UPDATE傳送。任何 Fluz 另外記錄的項目,都會有一個新的transactionId。
範例:一筆 8.54 的授權以
transactionId A 的 TRANSACTION_CREATE 到達,status: PENDING。商家請款 8.56。你會收到 A 上的 TRANSACTION_UPDATE,帶有 status: SETTLED 與 amount: -8.54,接著是新 transactionId B 的 TRANSACTION_CREATE,帶有 status: SETTLED 與 amount: -0.02。這三筆事件都帶有 referenceId: "11323677"。這筆購買的淨扣款金額,是同一個 referenceId 下、每個 transactionId 最新金額的加總:-8.56。
由此衍生出以下規則:
- 以
transactionId作為紀錄的鍵值,但依referenceId對帳。一筆帶有status: SETTLED且沒有先前待處理事件的TRANSACTION_CREATE是正常的:它是你已在同一個referenceId下持有的購買的額外分段或退款。 - 當授權從未被請款、保留被釋放時,你會收到兩個事件:一筆將待處理購買更新為
SETTLED的TRANSACTION_UPDATE,以及一筆帶有相同referenceId與正數amount的Virtual Card Return。兩者相互抵銷為零。請將這組事件視為待處理金額的釋放,而非一筆已完成的購買。 - 若商家將退款以新交易(而非針對原始授權)的形式提交,該筆
Virtual Card Return可能不帶有referenceId。請以virtualCardId、amount與商家進行比對。
撤銷與退款
撤銷會在任何資金被請款前釋放授權保留。持卡人的可用餘額會回升,但沒有資金曾經離開,也沒有資金回來。退款則發生在請款之後:資金已經移動,商家再將其退回。isReversal 用來區分兩者:
只要此欄位存在,請優先使用它而非
transactionType。各發卡機構對這些事件的標記並不一致,因此某發卡機構用於商家退款的類型值,可能是另一家發卡機構用於收款前撤銷的類型值,僅憑類型無法判斷資金是否真的移動。
Virtual Card Return 事件同樣帶有此欄位:已釋放的保留為 true,商家退款為 false。仍有少數退回事件不帶有此欄位;對於這些事件,請改用 referenceId 與原始授權來區分。
哪個事件會帶有撤銷標記,取決於被撤銷的是什麼:
- 卡片驗證作廢會記錄為其自身的交易,因此會以帶有負數
amount的TRANSACTION_CREATE到達,之後再更新。這是商家用來確認卡片有效性的小額測試,我們會立即將其作廢。它們會帶有isReversal: true。 - 收款前保留的釋放,會以獨立交易的形式到達,
transactionType為Virtual Card Return,amount為正數,並帶有該筆購買的referenceId。原始購買會同時更新為SETTLED,因此兩者相互抵銷為零。無論保留是由 Fluz 或發卡機構釋放,該筆退回都會帶有isReversal: true。 - 商家退款同樣會以
transactionType為Virtual Card Return的形式到達,並帶有isReversal: false。若存在referenceId,請以此比對原始購買;否則請以virtualCardId、amount與商家進行比對。
對帳金額
請以amount 對帳。它是該事件實際移動的 USD 金額,因此不論一筆購買有多少結算分段或退款,同一個 referenceId 下、每個 transactionId 的最新 amount 加總,就是該筆購買的淨額。
originalCurrencyAmount 不能用同樣的方式加總。它是發卡機構針對該事件回報的請求金額。在退款事件中,這是該次退款前仍在保留中的金額,因此會重複先前事件已經帶有的數值,加總會造成重複計算。
範例:一筆 39.69 的授權,其保留分兩個步驟釋放,例如訂單有部分品項缺貨,其餘品項稍後才釋放。
amount 的加總為 0.00,因為沒有任何金額被請款。originalCurrencyAmount 的數值描述的是每個步驟當下的保留金額,而不是實際移動的資金。
存款完成(DEPOSIT_COMPLETE)
當從資金來源至消費帳戶的存款完成時觸發。
OAuth 使用者已連結(OAUTH_USER_LINKED)
當使用者完成與你的應用程式的 OAuth 連結時觸發——包含首次連結與後續更新(例如使用者以不同範圍重新授權)。僅適用於公共/OAuth 與元件應用程式。接收此事件不需要任何範圍。
由於
OAUTH_USER_LINKED 會在重新連結/更新時再次觸發,請將其視為 upsert:首次收到時建立已連結使用者,之後每次投遞時刷新已儲存的範圍集合。
KYC 啟動(WIDGET_KYC_INITIATION)
當使用者開始身分驗證時觸發。僅適用於公共/元件應用程式。
轉帳完成 — 客戶至應用程式(WIDGET_DEPOSIT_COMPLETE)
當使用者向你的應用程式轉入資金時觸發。
轉帳完成 — 應用程式至客戶(WIDGET_WITHDRAW_COMPLETE)
當你的應用程式向使用者轉出資金時觸發。
禮品卡購買(WIDGET_PURCHASE_GIFT_CARD)
當透過元件完成禮品卡購買時觸發。
userId(Fluz 使用者 ID)、accountId(Fluz 帳戶 ID)、externalReferenceId(你在 OAuth 流程中的使用者識別碼),以及在適用時的 amount。
KYC 狀態更新(KYC_STATUS_UPDATE)
當已連結使用者的 KYC 狀態變更時觸發。僅適用於公共/OAuth 與元件應用程式;需要 VERIFY_KYC 範圍。每個載荷共享一個通用外層;verificationData 物件的結構由 verificationType 區分,見下方各類型所示。
- SSN
- Documents
- System
當狀態變更源自於基於 SSN 的驗證時發出。
legalAddress 若存在(僅 SSN 與 DOCUMENTS 類型),其結構為 { streetAddressLine1, streetAddressLine2 (optional), city, state, postalCode, country }。
KYB 狀態更新(KYB_STATUS_UPDATE)
當已連結企業的 KYB 狀態變更時觸發。僅適用於公共/OAuth 應用程式;需要 REGISTER_BUSINESS 範圍。
資金來源狀態更新(FUNDING_SOURCE_STATUS_UPDATE)
當使用者新增、重新命名或移除資金來源——銀行帳戶、銀行卡,或 PayPal 帳戶時觸發。需要 LIST_PAYMENT 範圍。目前僅限測試環境——正式環境尚未投遞。
只有當此載荷中的欄位確實發生變化時,才會觸發
UPDATED——重新命名來源或狀態變更會觸發,但例行的內部記錄維護不會。
移除資金來源並不會刪除該筆紀錄,而是將其標記為未啟用,因此 DELETED 事件會帶有終態的 status(INACTIVE、DISABLED 或 REMOVED),而不是缺少紀錄。請依 changeType 判斷來源是否已經移除。
此載荷中永遠不會包含完整的卡號或銀行帳號。
最佳實務
- 快速回應,稍後處理。 立即回傳
200,並以非同步方式處理事件,以避免逾時與不必要的重試。 - 驗證每個請求。 在處理前,使用你的 API 金鑰,針對原始主體驗證
X-HMAC-Signature。 - 以事件 ID 去重。 追蹤
X-Event-ID,以處理重試或重複的投遞。 - 將類 enum 欄位視為開放字串。 新的
transactionType、channel與declineCategory值可能隨時間出現;只針對你在意的值進行分支處理,並容忍未知值。 - 對
OAUTH_USER_LINKED採用 upsert。 每位使用者可能觸發不只一次;每次都刷新已儲存的範圍集合,而非假設只會在首次連結時觸發。 - 以
fundingSourceId為鍵值識別資金來源。 同一種事件類型涵蓋所有三種變更;請依changeType分流,並依changedAt為同一來源的事件排序。 - 接受未知欄位。 載荷可能隨時間新增欄位;請忽略無法辨識的欄位,而非直接失敗。
- 監控你的端點。 對連續的非
2xx回應發出警示——在 5 次嘗試失敗後,該事件的投遞就會被放棄。
疑難排解
需要協助?
- 技術問題: 檢查你的端點日誌並連絡支援,提供
X-Event-ID。 - 範圍問題: 參閱 Application Scopes 與 Decline Codes。