> ## Documentation Index
> Fetch the complete documentation index at: https://docs.waffo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# チェックアウトセッションの作成

> チェックアウト用に商品バージョン、価格、通貨を固定する

商品バージョン、価格、通貨を固定するチェックアウトセッションを作成します。これは単発商品とサブスクリプション商品の両方のチェックアウトフローの最初のステップです。

一般的なフローは以下の通りです。

1. マーチャントがチェックアウトセッションを作成（サーバーサイド）
2. フロントエンドに `checkoutUrl` を返す
3. customer がリンクをクリックしてホスティングされたチェックアウトページに移動
4. customer が請求情報を入力し、税額をプレビューし、注文を完了

```
POST /v1/actions/checkout/create-session
```

**認証：** API Key または Store Slug

## リクエストボディ（API Key）

| フィールド                     | 型       | 必須  | 説明                                                                                                                                                                                                                                                                         |
| ------------------------- | ------- | --- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `productId`               | string  | Yes | 商品 ID（Short ID フォーマット `PROD_xxx`）                                                                                                                                                                                                                                          |
| `currency`                | string  | Yes | ISO 4217 通貨コード（例：`USD`、`EUR`、`JPY`）                                                                                                                                                                                                                                        |
| `priceSnapshot`           | object  | No  | セッション作成時に価格を上書き（API Key のみ、以下参照）                                                                                                                                                                                                                                           |
| `withTrial`               | boolean | No  | トライアル期間を有効にする（サブスクリプション商品のみ）                                                                                                                                                                                                                                               |
| `buyerEmail`              | string  | No  | チェックアウトページで customer のメールを事前入力                                                                                                                                                                                                                                             |
| `billingDetail`           | object  | No  | 請求情報を事前入力（以下参照）                                                                                                                                                                                                                                                            |
| `successUrl`              | string  | No  | 決済成功後のリダイレクト URL を上書き                                                                                                                                                                                                                                                      |
| `expiresInSeconds`        | number  | No  | セッション TTL（秒単位、デフォルト：`2700` = 45 分、API Key のみ）                                                                                                                                                                                                                              |
| `darkMode`                | boolean | No  | チェックアウトページのダークモードを有効にする                                                                                                                                                                                                                                                    |
| `metadata`                | object  | No  | セッションに添付するカスタムキー値ペア                                                                                                                                                                                                                                                        |
| `orderMerchantExternalId` | string  | No  | マーチャント業務側の注文識別子（最大 128 文字）                                                                                                                                                                                                                                                 |
| `language`                | string  | No  | チェックアウトの言語（IETF BCP 47）。サポートされる列挙値のいずれかである必要があります：en, pt-BR, es-MX, id-ID, vi-VN, ru-RU, en-KE, es-PE, es-CO, es-CL, zh-Hant-TW, zh-Hant-HK, th-TH, ja-JP, en-NG, ko-KR, en-HK, zh-Hans-HK, pl-PL, tr-TR, zh-Hans, ms-MY。チェックアウトページのデフォルト言語を設定します。customer はページ上で切り替えられます。 |

## リクエストボディ（Store Slug）

| フィールド           | 型       | 必須  | 説明                                                                                                                                                                                                                                                                         |
| --------------- | ------- | --- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `productId`     | string  | Yes | 商品 ID（Short ID フォーマット `PROD_xxx`）                                                                                                                                                                                                                                          |
| `currency`      | string  | Yes | ISO 4217 通貨コード                                                                                                                                                                                                                                                             |
| `buyerEmail`    | string  | No  | customer のメールを事前入力                                                                                                                                                                                                                                                         |
| `billingDetail` | object  | No  | 請求情報を事前入力（以下参照）                                                                                                                                                                                                                                                            |
| `successUrl`    | string  | No  | 決済成功後のリダイレクト URL を上書き                                                                                                                                                                                                                                                      |
| `darkMode`      | boolean | No  | チェックアウトページのダークモードを有効にする                                                                                                                                                                                                                                                    |
| `language`      | string  | No  | チェックアウトの言語（IETF BCP 47）。サポートされる列挙値のいずれかである必要があります：en, pt-BR, es-MX, id-ID, vi-VN, ru-RU, en-KE, es-PE, es-CO, es-CL, zh-Hant-TW, zh-Hant-HK, th-TH, ja-JP, en-NG, ko-KR, en-HK, zh-Hans-HK, pl-PL, tr-TR, zh-Hans, ms-MY。チェックアウトページのデフォルト言語を設定します。customer はページ上で切り替えられます。 |

<Note>
  Store Slug 認証では、クライアントサイドからの価格改ざんやセッション操作を防止するため、`priceSnapshot`、`expiresInSeconds`、`metadata`、`orderMerchantExternalId`、`withTrial` はサポートされません（黙って無視されます）。
</Note>

<Note>
  **ID 命名規約**：同じフラット双キー名（checkout 側の `orderMerchantExternalId`、返金チケット側の `refundTicketMerchantExternalId`）が、リクエストボディ、webhook ペイロード、そしてその値を保持する全ての GraphQL 型を通じて使用されます — checkout 作成時に書き込んだ値は `Order`、`Payment`、`Refund`、webhook ペイロードのいずれからも同じフィールド名で読み戻せます。
</Note>

## Price Snapshot オブジェクト

| フィールド         | 型       | 必須  | 説明                                       |
| ------------- | ------- | --- | ---------------------------------------- |
| `amount`      | string  | Yes | 表示フォーマット文字列としての価格（例：`"29.00"` = \$29.00） |
| `taxIncluded` | boolean | Yes | 金額に税が含まれているかどうか                          |
| `taxCategory` | string  | Yes | 税計算用のカテゴリ（例：`saas`、`digital_goods`）      |

## Billing Detail オブジェクト

| フィールド          | 型       | 必須   | 説明                                          |
| -------------- | ------- | ---- | ------------------------------------------- |
| `country`      | string  | Yes  | ISO 3166-1 alpha-2 国コード（例：`US`、`JP`、`DE`）   |
| `isBusiness`   | boolean | Yes  | 法人購入かどうか                                    |
| `postcode`     | string  | No   | 郵便番号                                        |
| `state`        | string  | 条件付き | `US` と `CA` で必須（例：`CA`、`NY`、`ON`）           |
| `businessName` | string  | 条件付き | `isBusiness` が `true` の場合に必須                |
| `taxId`        | string  | 条件付き | EU 諸国で `isBusiness` が `true` の場合に必須（VAT 番号） |

## セッションロック

チェックアウトセッション作成時に以下の値がロックされ、セッションの有効期間中は変更できません。

`productVersionId`、`productName`、`priceInfo`、`storeName`、`billingPeriod`、`withTrial`、`theme`、`buyerEmail`、`billingDetail`

**メールアドレスの正規化**：すべてのメールフィールド（`email` / `buyerEmail` / `contactEmail`）はサーバー側で `trim().toLowerCase()` により正規化されてから保存・キャッシュ・下流呼び出しに使用されます。`Foo@Bar.COM` と `foo@bar.com` は同一アカウントとして扱われます。

## リクエスト例

<CodeGroup>
  ```typescript SDK theme={"system"}
  import { WaffoPancake, CheckoutSessionProductType } from "@waffo/pancake-ts";

  const client = new WaffoPancake({
    merchantId: process.env.WAFFO_MERCHANT_ID!,
    privateKey: process.env.WAFFO_PRIVATE_KEY!,
  });

  const session = await client.checkout.createSession({
    storeId: "STO_2D5F8G3H1K4M6N9P",
    productId: "PROD_7J3K5L8M2N4P6Q9R",
    productType: CheckoutSessionProductType.Onetime,
    currency: "USD",
    buyerEmail: "customer@example.com",
    language: "en",
    successUrl: "https://example.com/thank-you",
  });

  console.log(session.sessionId);   // "cs_550e8400-e29b-41d4-a716-446655440000"
  console.log(session.checkoutUrl); // "https://checkout.waffo.ai/..."
  console.log(session.expiresAt);   // "2026-01-22T10:30:00.000Z"
  ```

  ```bash cURL (API Key) theme={"system"}
  curl -X POST https://api.waffo.ai/v1/actions/checkout/create-session \
    -H "Content-Type: application/json" \
    -H "X-Merchant-Id: MER_2D5F8G3H1K4M6N9P" \
    -H "X-Timestamp: 1711800000" \
    -H "X-Signature: BASE64_RSA_SIGNATURE" \
    -d '{
      "storeId": "STO_2D5F8G3H1K4M6N9P",
      "productId": "PROD_7J3K5L8M2N4P6Q9R",
      "productType": "onetime",
      "currency": "USD",
      "buyerEmail": "customer@example.com",
      "language": "en",
      "successUrl": "https://example.com/thank-you"
    }'
  ```

  ```bash cURL (Store Slug) theme={"system"}
  curl -X POST https://api.waffo.ai/v1/actions/checkout/create-session \
    -H "Content-Type: application/json" \
    -H "X-Store-Slug: my-store-abc123" \
    -H "X-Environment: test" \
    -d '{
      "productId": "PROD_7J3K5L8M2N4P6Q9R",
      "productType": "onetime",
      "currency": "USD"
    }'
  ```

  ```python Python theme={"system"}
  import requests

  response = requests.post(
      "https://api.waffo.ai/v1/actions/checkout/create-session",
      headers={
          "Content-Type": "application/json",
          "X-Merchant-Id": "MER_2D5F8G3H1K4M6N9P",
          "X-Timestamp": "1711800000",
          "X-Signature": "BASE64_RSA_SIGNATURE",
      },
      json={
          "storeId": "STO_2D5F8G3H1K4M6N9P",
          "productId": "PROD_7J3K5L8M2N4P6Q9R",
          "productType": "onetime",
          "currency": "USD",
          "buyerEmail": "customer@example.com",
          "language": "en",
      },
  )

  data = response.json()["data"]
  print(data["checkoutUrl"])
  ```
</CodeGroup>

## 成功レスポンス (200)

```json theme={"system"}
{
  "data": {
    "sessionId": "cs_550e8400-e29b-41d4-a716-446655440000",
    "checkoutUrl": "https://checkout.waffo.ai/my-store-abc123/checkout/cs_550e8400-e29b-41d4-a716-446655440000",
    "expiresAt": "2026-01-22T10:30:00.000Z"
  }
}
```

## レスポンスフィールド

| フィールド         | 型      | 説明                                                     |
| ------------- | ------ | ------------------------------------------------------ |
| `sessionId`   | string | Checkout Session ID（`cs_` + UUID フォーマット、Short ID ではない） |
| `checkoutUrl` | string | customer をホスティングされたチェックアウトページにリダイレクトするための完全な URL       |
| `expiresAt`   | string | セッションが期限切れになる ISO 8601 タイムスタンプ                         |

## エラー

> **リトライポリシー**：4xx は一切リトライしない — リクエストを修正してから再送信。5xx は指数バックオフでリトライ（5s 開始、最大 3 回）。

| ステータス | `errors[0].message`                                                                     | 意味                                         | 推奨処理                              |
| ----- | --------------------------------------------------------------------------------------- | ------------------------------------------ | --------------------------------- |
| 400   | `Missing or invalid header: x-context-environment`                                      | environment ヘッダーが欠落、または `test` / `prod` 以外 | ヘッダーを修正して再送信                      |
| 400   | `Invalid JSON body`                                                                     | リクエストボディが有効な JSON ではない                     | ボディを修正して再送信                       |
| 400   | `Missing required fields: productId, currency`                                          | `productId` または `currency` が欠落             | ボディを修正して再送信                       |
| 400   | `Invalid currency format: "X". Must be 3 uppercase letters (e.g., "USD", "EUR", "JPY")` | 通貨コードが 3 文字の大文字ではない（ISO 4217）              | 有効な ISO 4217 コードを使用して再送信          |
| 400   | `Invalid billingDetail`                                                                 | 請求情報のバリデーションに失敗（例：US で `state` が欠落）        | billingDetail を修正して再送信            |
| 400   | `Invalid language, must be one of: en, pt-BR, … ms-MY`                                  | `language` がサポートされる列挙値のいずれでもない             | サポートされる `language` を使用するか省略してください |
| 400   | `Expected format: PROD_xxx, got "..."`                                                  | `productId` Short ID のデコード失敗               | `productId` のフォーマットを修正して再送信       |
| 400   | `orderMerchantExternalId must not be empty`                                             | 指定後 trim で空になる                             | フィールドを省略するか、空でない値を指定              |
| 400   | `orderMerchantExternalId must be at most 128 characters`                                | 値が 128 文字を超過                               | 128 文字以内に短縮                       |
| 400   | `Currency X is not supported for this product`                                          | 商品が要求された通貨の price snapshot を持たない           | 商品がサポートする通貨を使用                    |
| 401   | `Unauthorized`                                                                          | API Key 署名が無効、または Store Slug が認識されない       | 認証ヘッダーを確認                         |
| 403   | `Store is not active`                                                                   | ストアステータスが `active` でない                     | 先にストアを有効化                         |
| 403   | `Store is not approved for production payments`                                         | ストアが `prod` 環境承認を得ていない                     | `test` 環境を使用するか、ストア承認を取得          |
| 403   | `Product does not belong to this store`                                                 | 商品が訪問中のストアに属していない                          | 商品/ストアの組み合わせを確認                   |
| 404   | `Store not found`                                                                       | スラッグに一致するストアがない                            | スラッグと environment を確認             |
| 404   | `Product not found`                                                                     | 商品が存在しない                                   | `productId` を確認                   |
| 404   | `Product not found or not active for this environment`                                  | 該当 environment で商品の active バージョンがない        | この environment 用に商品バージョンを有効化      |
| 500   | `Internal server error`                                                                 | サーバ側の予期しない障害                               | 指数バックオフでリトライ（5s 開始、最大 3 回）        |

<Tip>
  デフォルトのセッション TTL は 45 分（2700 秒）です。API Key 認証を使用する場合、`expiresInSeconds` でカスタマイズできます。セッションは作成時に商品バージョンと価格をロックするため、価格変更は既存のセッションに影響しません。
</Tip>
