Skip to Content
概念工作階段

工作階段

CheckoutSession 是買家互動的對象 — 一個帶 TTL、單次使用的物件, 擁有託管結帳 URL。它是三個核心實體中最薄的一層;更重的工作落在 訂單Payment Intent(見下方)上。

三實體資料模型

CheckoutSession ← 1:1 → Order ← 1:N → PaymentIntent (買家) (目錄) (每次付款嘗試)
實體用途生命週期
CheckoutSession買家面向 — 有 session_keycheckout_url、TTL分鐘級(預設 30 分鐘)
Order你的目錄狀態 — 商品項目、總額、退款永久紀錄
PaymentIntent在某條鏈 / 資產上的一次付款嘗試小時級;結算或過期

你會一起建立 session 與 order(透過 POST /b2b/v1/checkout-sessions/quick)。 每次買家在結帳頁選擇資產,系統會在對應的鏈上開啟新的 PaymentIntent。 若買家在結帳中途切換資產,先前的 intent 會進入 EXPIRED,新的會 開始。

識別碼

Session 以其 session_key 識別:

cst_G-SO92J7HNWkwMHEHjD4oO1Z

URL-safe,在前綴 cst_ 之後約 24 字元(18 個隨機位元組以 base64url 編碼,無 padding)。託管結帳頁是 https://checkout.infraio.xyz/<session_key> — 請把 session key 當作該一筆結帳的 bearer 憑證對待。

生命週期 — CheckoutSession

狀態意義
ACTIVESession 已建立並開啟。結帳 URL 可用。
COMPLETED此 session 上的某個 PaymentIntent 結算。Order 此時為 PAID(或若短付則為 PARTIAL_PAID)。
EXPIREDexpires_at 在未結算下過去。Cleanup worker 翻了狀態並取消任何開啟的 Order。
CANCELED明確取消 — 買家按下「取消」或你呼叫了 cancel endpoint。

三個終態互斥且最終。如果想要重試(例如短付後),可以對同一個 Order 建立新的 CheckoutSession。

TTL

  • 預設: 30 分鐘(可透過 create 時的 expires_in 欄位設定, 單位為秒)。
  • 範圍: 伺服端不強制任何最小/最大上下限。請使用合理值 — 低於 60 秒可能讓合法買家逾時;超過 7 天會在幾乎肯定被放棄的 token 上 保留容量。請選擇一個符合買家預期決策視窗的數字。
  • 每商家預設: 可在儀表板設定,但只有舊版的兩步驟路徑 POST /b2b/v1/checkout-sessions 會遵循它。POST /b2b/v1/checkout-sessions/quick 路徑在 expires_in 省略時永遠回退到 30 分鐘,無論每商家 設定為何。如果你需要在 quick 路徑用不同預設,請在每次呼叫都明確 帶 expires_in
  • 強制執行: Lazy on read + 週期 cleanup worker。一個 expires_at 已過的 session 即使狀態欄位還沒寫入,也會被視為 EXPIRED,所以 別在恰好過期的時刻倚賴 API 讀到的狀態。

短付

若買家送出少於 session 金額,PaymentIntent 仍會以該部分金額結算, Order 轉為 PARTIAL_PAID。CheckoutSession 移到 COMPLETED (一個 PaymentIntent 已結算),不再可重複使用。

要接受短缺作為全額付款,訂單可被 resolve 為 PAID — 見 概念 → 訂單(目前無公開的 resolve API; 自助流程請改為收集差額)。要收集差額,請對同一個 Order 建立新的 CheckoutSession,以剩餘金額計算。

超付

若買家送出超過 session 金額(罕見,但手動轉帳時會發生),鏈上 scanner 會在 24 小時內擷取超付並發出商家警報。沒有自動退款 — 請透過退款 API 或儀表板手動發起。

錯誤資產付款

存款位址是依 (session, chain, asset) 三元組產生的。如果買家把 錯誤資產送到該位址,鏈上 matcher 不會辨識,PaymentIntent 會保持 開啟直到 TTL 過期。我們可以救回資金,但是 support 流程,不會自動 — 請指示買家送出結帳頁顯示的確切資產。

建立時的冪等性

POST /b2b/v1/checkout-sessions/quick 在請求 body 中接受 idempotency_key 欄位(注意:body 欄位,不是 HTTP header)。若你的 client 沒有自然 key,請為它自動產生 UUID — SDK 預設就是這樣做。

這個 key 去重的是 Order,而不是 CheckoutSession。以相同 key 重試時, /quick 會回傳 原始 order(order_id 穩定),但每次都鑄造一個 全新的 CheckoutSession — 每次都是新的 session_keycheckout_url。這是 刻意設計:一個 Order 可以背負多次結帳嘗試(見 訂單),所以重試的 /quick 會在不重複 order 的前提下給買家一個乾淨的 session。

有兩點行為與 Stripe 風格的冪等層不同 — 別被坑到:

  • body 不會被雜湊或比較。不同 的 body 重用一個 key 不會 回傳 409 — 伺服器會靜默回傳該 key 名下已存的 order,並忽略新的 body。所以請把 idempotency_key 當作單一邏輯 order 的一次性 token; 絕不要跨不同購物車回收使用。
  • 只有 Order 被去重,session 不會。 若你需要拿回 同一個 結帳 URL, 請把第一次回應裡的 session_key / checkout_url 持久化下來 — 再次 呼叫 /quick 不會回傳舊的。要列舉某個 order 名下鑄造過的每一個 session, 請用 GET /b2b/v1/checkout-sessions/by-order/:order_id

API endpoints

MethodPath備註
POST/b2b/v1/checkout-sessions/quick一次呼叫建立 order + session
POST/b2b/v1/checkout-sessions對既有訂單建立 session
GET/b2b/v1/checkout-sessions/by-order/:order_id列出某訂單的所有 session(重試歷史)
GET/checkout/:session_key公開 — 買家瀏覽器接觸的對象

完整 create 請求 body 與簽章請見快速入門

下一步