<!-- Source: https://docs.infraio.xyz/zh-TW/concepts/sessions -->
<!-- Last updated: 2026-10-04 -->

# 工作階段

**CheckoutSession** 是買家互動的對象 — 一個有時效、單次使用的物件，
擁有託管結帳頁 URL。它是三個核心實體中最輕量的一層;你的多數邏輯會處理
[訂單](https://docs.infraio.xyz/zh-TW/concepts/orders)與 **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-SO92J7HNWkwMHEHjD4oO1Z
```

URL-safe,在前綴 `cst_` 之後約 24 個字元。託管結帳頁是
`https://checkout.infraio.xyz/<session_key>` — 請把 session key
當作該一筆結帳的 bearer 憑證對待。

## 生命週期 — CheckoutSession

```mermaid
stateDiagram-v2
    [*] --> ACTIVE
    ACTIVE --> COMPLETED: a PaymentIntent settles
    ACTIVE --> EXPIRED:   expires_at elapsed
    ACTIVE --> CANCELED:  buyer or merchant cancels
    COMPLETED --> [*]
    EXPIRED --> [*]
    CANCELED --> [*]
```

| 狀態 | 意義 |
| --- | --- |
| `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`。見
[概念 → 訂單](https://docs.infraio.xyz/zh-TW/concepts/orders)(無法透過 API resolve;
若要維持自助流程，請改為收集差額)。要收集差額，請對同一個 Order 建立**新的**
CheckoutSession,以剩餘金額計算。

## 超付

若買家送出超過 session 金額(罕見，但手動轉帳時會發生),InfraIO Pay
會在 24 小時內偵測到超付並通知你。超付不會自動退款，
請透過退款 API 或儀表板發起退款。

## 錯誤資產付款

每筆訂單獨立收款位址(CREATE2)是為單一 session、網路與資產產生的。
如果買家把不同的資產送到該位址，該筆付款不會被比對，PaymentIntent
會保持開啟直到 session 過期。Support 可以協助救回資金，但不會自動進行 —
請告知買家送出結帳頁顯示的確切資產。

TRON、Solana 與 TON 沒有獨立收款位址，因此這僅適用於 EVM 網路：買家直接付款到你的資金庫錢包。請見[直達錢包的網路](https://docs.infraio.xyz/zh-TW/concepts/chains#直達錢包的網路)。

## 建立時的冪等性

`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 可以背負多次結帳嘗試(見
[訂單](https://docs.infraio.xyz/zh-TW/concepts/orders)),所以重試的 `/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 與簽章請見[快速入門](https://docs.infraio.xyz/zh-TW/get-started/quickstart)。

## 下一步

- [概念 → 訂單](https://docs.infraio.xyz/zh-TW/concepts/orders) — Order 實體(你應視為履約
  真相之源的)。
- [概念 → 支援的鏈與資產](https://docs.infraio.xyz/zh-TW/concepts/chains) — 支援的網路與
  各鏈的 finality 假設。
- [Webhooks → 總覽](https://docs.infraio.xyz/zh-TW/webhooks/overview) — 每個 session 狀態
  轉換時觸發哪些事件。
