工作階段
CheckoutSession 是買家互動的對象 — 一個有時效、單次使用的物件, 擁有託管結帳頁 URL。它是三個核心實體中最輕量的一層;你的多數邏輯會處理 訂單與 Payment Intent(見下方)上。
三實體資料模型
CheckoutSession ← 1:1 → Order ← 1:N → PaymentIntent
(買家) (目錄) (每次付款嘗試)| 實體 | 用途 | 生命週期 |
|---|---|---|
| CheckoutSession | 買家面向 — 有 session_key、checkout_url、TTL | 分鐘級(預設 30 分鐘) |
| Order | 你的目錄狀態 — 商品項目、總額、退款 | 永久紀錄 |
| PaymentIntent | 在某條鏈 / 資產上的一次付款嘗試 | 小時級;結算或過期 |
你會一起建立 session 與 order(透過 POST /b2b/v1/checkout-sessions/quick)。
每次買家在結帳頁選擇資產,系統會在對應的鏈上開啟新的 PaymentIntent。
若買家在結帳中途切換資產,先前的 intent 會進入 EXPIRED,新的會
開始。
識別碼
Session 以其 session_key 識別:
cst_G-SO92J7HNWkwMHEHjD4oO1ZURL-safe,在前綴 cst_ 之後約 24 個字元。託管結帳頁是
https://checkout.infraio.xyz/<session_key> — 請把 session key
當作該一筆結帳的 bearer 憑證對待。
生命週期 — CheckoutSession
| 狀態 | 意義 |
|---|---|
ACTIVE | Session 已建立並開啟。結帳 URL 可用。 |
COMPLETED | 此 session 上的某個 PaymentIntent 結算。Order 此時為 PAID(或若短付則為 PARTIAL_PAID)。 |
EXPIRED | expires_at 在未結算下過去。任何開啟的 Order 會被取消。 |
CANCELED | 明確取消 — 買家按下「取消」或你呼叫了 cancel endpoint。 |
三個終態互斥且最終。如果想要重試(例如短付後),可以對同一個 Order 建立新的 CheckoutSession。
TTL
- 預設: 30 分鐘(可透過 create 時的
expires_in欄位設定, 單位為秒)。 - 範圍: 不強制任何最小/最大上下限。請選擇符合買家預期決策視窗的 值:低於 60 秒可能讓合法買家逾時,而開啟超過 7 天的 session 幾乎肯定 已被放棄。
- 每商家預設: 你可以在儀表板設定預設值,但只有
POST /b2b/v1/checkout-sessions(兩步驟)會遵循它。POST /b2b/v1/checkout-sessions/quick在expires_in省略時使用 30 分鐘,無論儀表板設定為何。若要在/quick使用不同預設, 請在每次呼叫都帶expires_in。 - 強制執行: 一個
expires_at已過的 session 即使狀態尚未更新, 也會被視為EXPIRED,所以別在恰好過期的時刻倚賴狀態值。
短付
若買家送出少於 session 金額,PaymentIntent 仍會以該部分金額結算,
Order 轉為 PARTIAL_PAID。CheckoutSession 移到 COMPLETED
(一個 PaymentIntent 已結算),不再可重複使用。
要接受短缺作為全額付款,訂單可被 resolve 為 PAID。見
概念 → 訂單(無法透過 API resolve;
若要維持自助流程,請改為收集差額)。要收集差額,請對同一個 Order 建立新的
CheckoutSession,以剩餘金額計算。
超付
若買家送出超過 session 金額(罕見,但手動轉帳時會發生),InfraIO Pay 會在 24 小時內偵測到超付並通知你。超付不會自動退款, 請透過退款 API 或儀表板發起退款。
錯誤資產付款
每筆訂單獨立收款位址(CREATE2)是為單一 session、網路與資產產生的。 如果買家把不同的資產送到該位址,該筆付款不會被比對,PaymentIntent 會保持開啟直到 session 過期。Support 可以協助救回資金,但不會自動進行 — 請告知買家送出結帳頁顯示的確切資產。
TRON、Solana 與 TON 沒有獨立收款位址,因此這僅適用於 EVM 網路:買家直接付款到你的資金庫錢包。請見直達錢包的網路。
建立時的冪等性
POST /b2b/v1/checkout-sessions/quick 在請求 body 中接受
idempotency_key 欄位(注意:body 欄位,不是 HTTP header)。若你的
client 沒有自然 key,請產生一個 UUID。
這個 key 去重的是 Order,而不是 CheckoutSession。以相同 key 重試時,
/quick 會回傳 原始 order(order_id 穩定),但每次都鑄造一個 全新的
CheckoutSession — 每次都是新的 session_key 與 checkout_url。這是
刻意設計:一個 Order 可以背負多次結帳嘗試(見
訂單),所以重試的 /quick 會在不重複 order
的前提下給買家一個乾淨的 session。
有兩點行為需要注意:
- 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
| Method | Path | 備註 |
|---|---|---|
POST | /b2b/v1/checkout-sessions/quick | 一次呼叫建立 order + session |
POST | /b2b/v1/checkout-sessions | 對既有訂單建立 session |
GET | /b2b/v1/checkout-sessions/by-order/:order_id | 列出某訂單的所有 session(重試歷史) |
完整 create 請求 body 與簽章請見快速入門。
下一步
- 概念 → 訂單 — Order 實體(你應視為履約 真相之源的)。
- 概念 → 支援的鏈與資產 — 支援的網路與 各鏈的 finality 假設。
- Webhooks → 總覽 — 每個 session 狀態 轉換時觸發哪些事件。