Skip to main content
Webhooks 讓你的應用程式在 Fluz 平台上發生事件時即時接收通知。與其輪詢變更,你只需註冊一個 HTTPS 端點,Fluz 就會在事件發生當下把資料推送給你——例如虛擬卡交易、被拒交易、完成的存款、使用者透過 OAuth 連結其帳戶,等等。
本頁涵蓋所有 webhook 事件,橫跨多個平台範疇(交易活動、存款、元件流程,以及 OAuth 帳戶連結),而非屬於單一功能。
Webhooks 適用於 Fluz 平台上的所有應用程式類型:在你自己的帳戶上運作的私人應用程式、代表其他使用者透過 API 行動的公共 OAuth 應用程式,以及嵌入式元件應用程式。

運作方式

  1. 在開發者平台為你的應用程式註冊一個 webhook URL。
  2. 選擇要監聽的事件類型(或訂閱全部)。
  3. 當符合的事件發生時,Fluz 會以 HTTP POST 將簽名的 JSON 載荷送到你的 URL。
  4. 你的伺服器驗證簽章、以 2xx 回應並處理該事件。
如果你的端點不可用或回應錯誤,Fluz 會採用指數退避最多重試5 次,之後放棄該次投遞。

依應用程式類型的 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 都以 HTTP POST 傳遞,包含以下標頭: 主體為 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 的驗證時發出。
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 次嘗試失敗後,該事件的投遞就會被放棄。

疑難排解

需要協助?