- 第一部分:概念。 請先閱讀此部分。v3 是重新設計,而非重新命名:若您把舊端點一對一對應,將會與 API 產生衝突。此處花費十分鐘,將替日後省下數日時間。
- 第二部分:API。 逐一端點對照、請求範例、狀態機,以及遷移檢查清單。
api.deprecation webhook 事件以接收停用通知。
目錄。 第一部分:1.1 v3 存在的原因、1.2 物件模型、1.3 每項 capability 的就緒狀態、1.4 task 循環、1.5 金流、1.6 狀態機、1.7 慣例、1.8 黃金路徑。第二部分:2.1 customers、2.2 capabilities、2.3 tasks 與 submissions、2.4 accounts、2.5 recipients 與 destinations、2.6 quotes 與 transfers、2.7 webhooks、2.8 sandbox、2.9 舊版端點、2.10 遷移順序、2.11 陷阱檢查清單。
第一部分:概念
1.1 v3 存在的原因
v1 與 v2 演化出四種重疊的方式讓客戶達到可付款狀態:/rails、/banks、/accounts/applications,以及企業版的 rail-applications 介面,各自擁有專屬的狀態詞彙。文件收集(/documents、KYC 匯入、驗證 SDK token)則與其實際解鎖的對象脫節。v3 將全部整併為六種資源,即客戶本身加上客戶所擁有的五項資源:
1.2 物件模型
需要內化的兩項結構性規則:- Capabilities 是所有事物的閘門。 Accounts 是在
ready的 capability 下佈建;quotes 是針對 capability 定價。上線流程等同於將您需要的 capabilities 帶到ready狀態。 - Tasks 可附加於任何位置。 一個 capability、一個 account,或一筆進行中的 transfer,都可以帶有
openTaskIds。無論在何處看到它們,循環都相同:讀取 task、提交答案、等待審核、重新讀取父層。
1.3 就緒狀態依 capability 而定,而非依 customer
v1 將/rails 就緒狀態與涵蓋整個 customer 的 KYC 閘門糾結在一起。在 v3 中沒有 customer 狀態:某位 customer 在 stablecoin_transfers 上可能完全可用,而其 sepa capability 仍有未完成的 tasks。共用帳戶型的 capabilities 通常比具名型更快進入 ready,因此應對已 ready 的 capability 開始交易,而非等待全部都就緒。
若您的 v1 或 v2 程式碼是以 customer 驗證狀態驅動 UI 徽章,請重寫:
- 「他們是否可在 X 上交易?」變成 capability X
status == "ready"。 - 「他們是否需要做些什麼?」變成任何狀態為
action_required的 task(capability 通常顯示為restricted,並帶有statusReason.resolution: "complete_tasks")。 - 「我們是否在等待 Swipelux?」變成 tasks 為
in_review,capability 為pending。
1.4 Task 循環
舊有文件與 KYC 介面所做的一切,現在都是這一個循環: 重要特性:- 一個 task 帶有
requirements[],即個別的請求項目。每一項有 task 內的requirementId、命名該請求的穩定key(例如地址證明,可在您的 UI 中據此去重),以及描述所需輸入的型別化request(text、date、select、document、attestation 等)。 - 提交是經過審核把關:提交本身絕不會直接改變 capability 或 account 狀態,由審核通過才會。有一項例外:
profile答案在提交時會直接寫入 customer profile(見 2.3)。提交後,請輪詢該 task 或其父層資源。 taskRevision(taskrevision的回應值)是併發防護:若您讀取後 task 發生變化,請重新讀取並重建答案。absence是一等公民等級的答案(「我沒有這項,因為……」),請使用它,而非讓 requirements 懸而未決。
1.5 金流
payin、payout 與 stablecoin 移轉共用一種流程。沒有方向輸入,您永遠不需宣告是 payin 或 payout。進出的幣別型態會在 quote 與 transfer 上衍生一個唯讀的direction:fiat_to_stablecoin(payin)、stablecoin_to_fiat(payout),或 stablecoin_move。
1.6 每個資源一個狀態機
每個帶有狀態的資源都有自己的 enum,而每個非順利狀態都帶有結構化的原因。Accounts、applications 與 transfers 共用形狀{ code, message, actor, retryable }:accounts 與 applications 將其以 statusReason 呈現,transfers 則以 stateDetail 呈現。actor 指出必須採取行動的一方(customer、developer、provider、network、swipelux);retryable 說明重試是否有幫助。Capabilities 使用 { code, resolution, message },其中 resolution(complete_tasks、wait、contact_support、none)說明是什麼將推進該 capability。code 值是一份開放、僅追加的目錄:請根據 resolution(或 actor 加 retryable)分支處理,並對從未見過的 code 保持容忍。
本指南未逐一走過的狀態(
rejected、suspended、disabled、failed、canceled)為終端態或由支援團隊驅動;各資源的定義請參閱規格。
Transfer 詳細狀態:
1.7 慣例
在撰寫程式碼前,值得內化的冪等性規則:
- 以不同的 body 重複使用同一個金鑰,只要該金鑰仍被保留(至少 7 天),都會得到
409 idempotency_conflict,所以千萬不要規劃重複使用金鑰。每個邏輯操作產生一個全新的 UUID,並隨作業一起持久化保存。 - 重放同樣涵蓋錯誤:若原始請求以終端態 4xx 結束,以相同金鑰加上相同 body 會再次回傳相同的問題回應。
- 兩個同時攜帶相同金鑰的請求:其中一個勝出,另一個得到
409。在勝出者定案之後重試落敗者;重放將回傳原始回應。
1.8 黃金路徑
第二部分:API
2.1 Customers
建立(依
type 區分,以下為說明性欄位值,實際欄位名以規格為準):
- 建立是漸進式的:僅
{ "type": "individual" }亦是有效的建立。缺少的資訊絕不會使 customer 失效,它們會之後以 intake tasks 的形式出現在需要它們的 capabilities 上。 - 企業帶有
business加上註冊資料。v1 的 shareholder CRUD 對應到related parties,並擴展以涵蓋 director、officer 與 owner:可在建立 customer 時內嵌建立(每個都會取得穩定的rp_id),或透過專屬的 related-parties 端點管理。 - 沒有 customer
status欄位,見 1.3。 - 既有 customers 會保留:在 v1 或 v2 建立的 customers 可透過相同 id 在 v3 端點上存取。v3 讀取為一份_經過整理的檢視_,無法通過 v3 驗證的舊值會缺席回傳。在您首次 v3 寫入後,該檢視即成為永久狀態:缺席的值不會自動回來。所以請及早補全資料,規劃一次性作業以
PATCH從您自有紀錄補入完整 profile,再依賴 v3 讀取。v1 的metadata為獨立命名空間,不會沿用,請在 v3 上重新設定。 externalId是一等公民,並且在 v3 上於每個環境內在您的 customers 範圍內唯一(409 duplicate_external_id)。封存 customer 不會釋放其externalId,若打算重用,請在 DELETE 前先以 PATCH 將其清除。DELETE為封存串連(不可還原;id 永不重用)。當任何未封存的帳戶或進行中的 transfer 存在時,將被409 customer_has_active_resources封鎖並列出blockingResources[]。- PATCH 合併規則:明確的
null會清除可為空的欄位;陣列會整體取代(除了內嵌 related parties,依 id upsert);metadata鍵會合併。完整 schema 與列表過濾條件請見 OpenAPI 規格。
2.2 /rails、/banks、applications 變為 Capabilities
- 一個 capability 等於
method(ach、wire、rtp、pix、sepa、swift、spei、pse、transfers_3_0、faster_payments、sepa_instant、uaefts、card、stablecoin_transfers等)加上accountType(pooled或named,非銀行方式為null)加上directions(payin或payout)。公開的capabilityId是合格化的組合(sepa_pooled、ach_named),或對card與stablecoin_transfers使用純粹的 method 名稱。 - 每次 capability 請求會產生一個application,即
.../capabilities/{capabilityId}/applications下的每次嘗試紀錄(以及/{applicationId}/history),擁有自己的狀態(見 1.6)與statusReason。它是請求的稽核軌跡;日常請直接輪詢 capability 本身。 capabilities/supported回傳可用性(available、beta或disabled)、資格,以及提供的機構列表。銀行選擇在請求時透過可選的institutions陣列進行;不存在獨立的/banks資源。省略(或送出[])會選中所有預設機構;isDefault: true是 customer 與 capability 特定的旗標,而非全域旗標。若送出非空清單將覆寫預設值;而由銀行支持的 capability 若無適用的預設值,將回傳422 capability_institutions_required。機構 id 為不透明識別碼,請容忍新增。stablecoin_transfers於建立 customer 時自動授予,並以ready誕生(因此永遠無需請求且無法取消)。card僅限個人。- capability 上的
openTaskIds是您的「接下來要做什麼」指標。「開啟」等於action_required或in_review,且該匯總包含透過現行相依性關係達到的客戶層級共享 tasks。 cancel僅在pending或restricted且無阻礙資源時可行,否則會得到409 capability_not_cancelable,其問題主體列出blockingResources。取消後重新請求為全新的建立作業,並使用新的冪等金鑰。- 請輪詢 GET。 capability 狀態在您讀取時會刷新;輪詢
GET .../capabilities/{capabilityId}或訂閱capability.status_changed,勿快取。 - 請求一種 method 可能一次使多個相關 method 變得可用,請將 capabilities 視為需重新讀取的集合,而非您單獨追蹤的一行紀錄。
- 使用
tasks-preview在提交請求之前顯示上線所需的詢問項目。 - 驗證不是一次性的:新的 tasks 可能出現在已
ready的 capability 上(週期性或事件驅動的再次驗證)。請在整個 customer 生命週期都保持 task 循環運作,而非僅在上線期間。
2.3 Documents 與 KYC 變為 Tasks 與 Submissions
命名注記。 這些端點曾短暫以
requirements 與 fulfillments 出貨。自 2026-08-02 起,公開名稱為 tasks 與 submissions。此次更名僅涵蓋資源與端點路徑,task 內部的 requirements[] 陣列及其 requirementId 保留原名。GET /v3/customers/{customerId}/tasks,以 POST .../tasks/{taskId}/submissions 回應。
配合該循環:
- 原始檔案儲存:
POST/GET/DELETE /v3/customers/{customerId}/documents(以及/{documentId}),先以您的 API key 上傳一次,然後在 submission 答案中引用文件 id。此取代所有 upload-token 與 direct-upload 匯入。 - 全新讀取:
GET /v3/tasks(商戶範圍收件匣)、GET /v3/transfers/{transferId}/tasks、GET .../tasks/{taskId}/history、GET .../tasks/{taskId}/submissions(以及/{submissionId})。
- 答案類型:
profile、text、date、single_select、multi_select、boolean、attestation、document、resource_reference、absence。每個 requirement 的request物件會告知您它期待哪種類型。 - 一次 submission 必須回答當前輪次中每一個可執行的 requirement,並帶有您讀取到的精確
taskRevision。部分提交會被拒絕。 profile答案會直接寫入:它們會經過正常驗證路徑更新 customer profile,並立即重新評估參考同一 intake 工作的每個 capability。所有 requirements 已被滿足的兄弟 intake tasks 會自動關閉。- Requirements 可能形成替代組(
alternativeKey):提交組內任一項即可。 changes_requested會遞增remediationRound並帶有reviewFeedback。請重新讀取 task,並以全新的冪等金鑰再次提交。- 託管驗證 URL 僅出現在 customer 範圍的 task 詳細頁(
GET /v3/customers/{customerId}/tasks/{taskId}),且僅在該 session 可執行時;列表與GET /v3/tasks/{taskId}刻意不含 URL。 - 服務條款也是一種 task:
openTaskIds可能包含category: "terms_of_service"的 task,其託管接受頁面以同樣方式連結(僅 customer 範圍詳細頁)。一般 submissions 不能接受條款,而 KYC 通過絕不代表條款已接受。 - Tasks 依 capability 分別劃分範圍,因此「相同」的詢問(例如地址證明)可能每個 capability 各出現一次。請在您的 UI 中以 requirement
key去重。 - 無轉換層:向
/v1/documents發布不會解鎖 v3 capabilities。一旦 customer 進入 v3,請以 tasks 驅動所有詢問。
2.4 Accounts 與 wallets
建立,依
origin 加 type 區分。Issued 銀行帳戶取單一 method;external 銀行帳戶則取 methods 陣列(在該處送出 method 會被拒絕):
- issued 銀行帳戶上的
country為選填(每種 method 有預設值);在 external 銀行帳戶上請明確提供。錢包帳戶完全不帶國家欄位。 - issued 銀行帳戶上必填
settlement.accountId:它指出接收從該銀行帳戶存款結算資金的 issued 錢包帳戶。 - issued 帳戶會揭露
details(IBAN 或 routing 加帳號或地址)、有版本的routing(存款座標可輪替,總是以最新讀取為準呈現)、fees、balances。 - 網路:
polygon、ethereum、base、arbitrum、optimism、bsc、avalanche。 - capability 閘門僅適用於 issued 帳戶:對非 ready 的 capability 建立帳戶將以 capability 相關錯誤失敗,請先請求該 capability(見 2.2)。external 帳戶不需要 capability(也無需 customer 核准);僅接受請求 schema 與銀行資料驗證。
- issued 銀行帳戶以
provisioning誕生,details: null。輪詢該帳戶或監聽account.status_changed直到ready。 DELETE為封存,永不硬刪除。被進行中 transfers 引用的帳戶會回傳409 account_has_active_transfers。請於這些 transfer 到達終端態後重試。- v3 新增:Rules,issued 錢包帳戶上的常設指令(
POST/GET /v3/customers/{customerId}/rules、GET/PATCH/DELETE .../rules/{ruleId}),可將收到的資金自動掃入另一帳戶或錢包 destination。無 v1 或 v2 對應。
2.5 Recipients 與 destinations
v2 沒有 recipient 概念。若您目前在 v2 上並支付給第三方,這是全新介面,而非更名。
- Recipient 等於誰:
individual(名與姓)或business(公司名稱),並需要relationship(employee、contractor、vendor、subsidiary、merchant、customer、landlord、family、other)。Recipients 與 destinations 僅用於第三方。第一方付款完全不需 recipient:將該 customer 自己的一個acc_帳戶作為 quotedestinationId(見 2.6)。 - Destination 等於何處:依 method 型別化,
sepa(iban、bic 選填)、ach或wire(routing 加帳號)、swift(完整座標加選填中介行)、spei(clabe)、pse、transfers_3_0(cbu)等,加上錢包 destinations。每個 destination 有自己的狀態。請監聽destination.status_changed。 - 法幣 destinations 需在建立之前取得 recipient 的完整
address(街道、城市、郵遞區號、國家)。缺項會以422 recipient_address_required失敗。錢包 destinations 不需要地址,但需要頂層ownership(self_custodied,或為custodial並附上託管方名稱)。 - 受益人姓名的準確性很重要:收款銀行以帳戶的法定名稱進行比對。請送出精確的法定名與姓或公司名稱,而非顯示暱稱。
- 每種 method 的 destination 欄位 schema 見 OpenAPI 規格。
2.6 Quotes 與 transfers
destinationId接受acc_(customer 自有帳戶)或dst_(recipient destination)id。法幣資金的 quotes(payins)必須指向acc_帳戶,以dst_為目標則永遠代表 payout(否則回傳422 quote_direction_invalid)。- quotes 與 transfers 上的
externalId是非唯一關聯參考(讀取時回傳、列表可過濾)。每環境唯一的規則(見 2.1)僅適用於 customer 的externalId。 - Quote 只可執行一次,並在
expiresAt之前。過期的 quote 會以409 quote_expired失敗;第二次執行會得到409 quote_already_executed(問題主體帶有既有的transferId)。 - Transfer 取消尚未支援:
POST .../cancel在任何狀態下都會回傳409 transfer_not_cancelable。目前的canceledtransfers 來自未完成資金的 payin 之資金投入窗口過期,並非來自此端點。 - Payins 從
awaiting_funds開始:對付款人呈現GET .../instructions,即法幣的銀行座標加參考或備註代碼,或加密貨幣的存款地址。參考代碼是存款對帳的方式,務必顯示。 state加stateDetail提供機器可讀的子狀態;action_required表示有一個合規 task 附加(openTaskIds、GET .../tasks),請透過 submissions 回應。- 在 issued 帳戶上偵測到的入帳存款會以
origin: "inbound_deposit"的 transfers 出現(相對於"quoted")。 - 支付網路參考統一於
references下:transactionHash、traceNumber、imad、uetr、explorerUrl、returnedTransferId。
兩項遷移警告:
- Transfers 不會跨版本存取。 在 v1 或 v2 建立的 transfers 從 v3 讀取不到。列表會省略,
GET /v3/transfers/{transferId}會回傳 404。請先切換_建立_,保留 v1 讀取路徑直到那些 transfers 到達終端態,然後再移除。 - 無代幣互換。
stablecoin_move要求進出貨幣相同:USDC 換 USDT 會以422 recipient_destination_invalid失敗,並帶有currency_mismatch欄位錯誤。兩側必須為相同網路,無橋接;錢包對錢包的移轉目前僅支援零手續費投遞:平台或開發者手續費非零的 quote 會以422 amount_not_deliverable失敗。
2.7 Webhooks
事件目錄:
customer.created、customer.updated、customer.archived、capability.created、capability.status_changed、application.status_changed、recipient.status_changed、destination.status_changed、account.created、account.status_changed、account.details_changed、transfer.created、transfer.state_changed、api.deprecation。
GET /v3/webhooks/portal會回傳一個託管管理入口的 URL,供投遞記錄、重試與手動重放使用。transfer.created目前以舊有 v1 payload 結構投遞(v3 信封在 v1 webhooks 停用時啟用)。請純粹將其視為提示並 GET 該 transfer;不要以其 body 為依據建構邏輯。- 事件為提示:收到後,GET 該資源並依讀取採取行動。切勿以事件 payload 或順序建構狀態。投遞為至少一次,且可能延遲或亂序。請以事件 id 去重,並以各列表的包含式
updatedAfter過濾器復原漏掉的事件。 - 訂閱
api.deprecation,即版本停用的機器通道。 - 目前沒有
task.*事件:提交後請輪詢 task 或其父層。
2.8 Sandbox
同一 base URL;sandbox API key 會決定環境。
v3 sandbox 完整模擬審核循環:建立 task、對其提交、
review 到 accepted 或 rejected、觀察 capability 解鎖。可在上線前先排練您的補救 UX。sandbox 建立的 tasks 與請求 capability 時出現的常規 intake tasks 都能以此方式審核;如同正式環境,不會觸發 task webhooks,請輪詢(見 2.7)。
2.9 無 v3 替代的舊有端點
以下端點沒有 v3 替代。多數維持在 v1 上不變(繼續使用您的既有呼叫);兩項直接退役(見「處置」):
其他所有公開 v1 或 v2 端點都出現在上面的對應表中。
2.10 建議的遷移順序
每一步可以獨立出貨;v1 或 v2 與 v3 可對同一批 customer 併行運作。在正式環境重複之前,請針對每一步以您的 sandbox key(見 2.8)排練。1
基礎架構
對所有會產生副作用的請求(POST、PATCH、PUT、DELETE;sandbox 端點除外)加上
Idempotency-Key;金額以字串表示;準備游標分頁輔助函式。2
Webhooks
依事件註冊 v3 端點,包括
api.deprecation。v1 的單一端點設定是獨立介面,請維持原狀;兩者將併行運作直到步驟 9 的排放期。3
Profile 補全
以您手上的完整 profile 呼叫
PATCH /v3/customers/{id}(v1 收集的資料少於 v3 揭露的),並重新設定 metadata。請刻意將這一步作為每個 customer 的第一次 v3 寫入:它會在整理後檢視變為永久狀態之前先將其填滿(見 2.1)。4
讀取
將 customer、capability 與 account 讀取指向 v3;依 1.3 重寫 customer 狀態邏輯。僅在步驟 3 之後,未補全的讀取才會缺少舊版不合規的欄位。
5
上線寫入
以
POST /v3/customers 建立;請求 capabilities 而非 /rails、/banks 或 applications;建立 task 循環(最大量的全新 UI 工作,tasks-preview 有助於預先顯示詢問)。從此時起,對於由 v3 驅動的 customers,停止呼叫 /v1/documents,那不會解鎖 capabilities(見 2.3)。6
Accounts
透過 v3 發行;將 imports 轉移為
origin: external。7
Payouts
Recipients 加 destinations,然後 quote 與 transfer。
8
Payins
Quote、transfer、instructions;繼續呈現參考代碼。
9
排放
Transfers 不會跨版本(見 2.6)。請保留 v1 或 v2 讀取路徑,以及供在那邊建立的 transfers 使用的 v1 webhook 端點;雙讀直到它們到達終端態,再移除舊用戶端與 v1 webhook 設定。
2.11 陷阱檢查清單
- 每個邏輯操作使用全新 UUID,隨作業一起持久化,於重試時重用;絕不使用相同金鑰配合已變更的 body(
409 idempotency_conflict)。sandbox 端點不需該標頭。 - 在任何其他 v3 寫入之前,補全既有 customers(
PATCH完整 profile、重新設定metadata,它不會沿用);首次 v3 寫入會使整理後檢視變為永久狀態。 -
externalId於每環境唯一,且封存不會釋放它;若打算重用,請在DELETE前先以PATCH清除。 - 沒有 customer
status欄位,請依 capability 導出就緒狀態。 -
action_required與in_review都代表存在未完成的 task。 - Submissions 經過審核把關(提交不等於解鎖),且必須以精確的
taskRevision回答每一個可執行 requirement。若不符,請重新讀取並重建。 - 沒有
task.*webhook,每次提交後請輪詢 task(或其父層)。 -
changes_requested的重試等於重新讀取 task、給出全新答案、使用全新的冪等金鑰。 - 對
/v1/documents發文絕不會解鎖 v3 capability;一旦 customer 使用 tasks,請以 tasks 驅動所有詢問。 - 新的 tasks 可能出現在已
ready的 capability 上,請在上線後也保持 task 循環運作,而非只在上線期間。 - Capability
cancel僅在pending或restricted且無阻礙資源時可行(409 capability_not_cancelable);取消後重新請求為全新的建立,並使用全新冪等金鑰。 - Capability 必須為
ready才能在其下發行帳戶或針對其定價。 - Quote 只有一側有金額;無方向欄位;在
expiresAt之前正好執行一次(409 quote_expired或409 quote_already_executed)。 - Stablecoin 移轉僅支援相同貨幣、相同網路(USDC 轉 USDT 會
422失敗);錢包對錢包僅支援零手續費投遞。 -
DELETE為封存,永不硬刪除。Account 刪除會被進行中 transfers 封鎖(409 account_has_active_transfers);Customer 刪除還會被任何未封存帳戶封鎖(409 customer_has_active_resources,blockingResources[]會列出它們)。 - v1 或 v2 transfers 對 v3 讀取不可見(列表會省略,GET 回 404),請雙讀直到排放完畢,再移除舊路徑。
- 存款
routing與指示可能輪替,永遠以最新 GET 呈現,並永遠顯示參考代碼。 - Webhooks 只是提示;GET 才是真相,請以事件 id 去重,並以
updatedAfter復原漏掉的事件。