メインコンテンツへスキップ
商品バージョン、価格、通貨を固定するチェックアウトセッションを作成します。これは単発商品とサブスクリプション商品の両方のチェックアウトフローの最初のステップです。 一般的なフローは以下の通りです。
  1. マーチャントがチェックアウトセッションを作成(サーバーサイド)
  2. フロントエンドに checkoutUrl を返す
  3. customer がリンクをクリックしてホスティングされたチェックアウトページに移動
  4. customer が請求情報を入力し、税額をプレビューし、注文を完了
認証: API Key または Store Slug

リクエストボディ(API Key)

リクエストボディ(Store Slug)

Store Slug 認証では、クライアントサイドからの価格改ざんやセッション操作を防止するため、priceSnapshot、expiresInSeconds、metadata、orderMerchantExternalId、withTrial、changeAmount、changeCreditAmount、includePaymentMethods、excludePaymentMethods はサポートされません(黙って無視されます)。決済手段は加盟店側の商業判断(チャネル手数料・精算サイクル)であり、ブラウザからの絞り込み・拡大は認められません——Store Slug で作成された session は常にその通貨がサポートする全手段を提供します。couponId と promotionCode は例外で、無視されずに 403 を返します。購入者が自分でクーポンを選ぶことはできません。
ID 命名規約:同じフラット双キー名(checkout 側の orderMerchantExternalId、返金チケット側の refundTicketMerchantExternalId)が、リクエストボディ、webhook ペイロード、そしてその値を保持する全ての GraphQL 型を通じて使用されます — checkout 作成時に書き込んだ値は Order、Payment、Refund、webhook ペイロードのいずれからも同じフィールド名で読み戻せます。
cancelUrl はありません。 購入者がチェックアウトを閉じたり支払いを中断した場合、あなたのサイトへ戻すリダイレクトは発生しません。セッションは期限切れ(デフォルト 24 時間)となり、注文は課金なしで canceled で終了し、webhook も送信されません —— 対応は不要です。cancelUrl や returnUrl などのフィールドを送信しても黙って無視されます。チェックアウトを開いたページ側に「ストアに戻る」リンクを用意しておいてください。

Price Snapshot オブジェクト

単発商品では amount が商品価格をそのまま置き換えます。サブスクリプション商品では通常周期の価格のみを置き換え、トライアル期間の価格はセッションにロックされた商品バージョンから取得されるため、ここでは上書きできません。

Billing Detail オブジェクト

billingDetail はチェックアウトの事前入力にしか使われません。送信した国は編集可能な国セレクターの初期値になり(加盟店の値は IP 判定より優先)、購入者は変更でき、注文に記録されるのは購入者が最終的に選んだ国です。請求フィールドをロックしたり非表示にするセッションパラメータや URL パラメータはありません。決済手段は国では決まりません。商品タイプ × 通貨と includePaymentMethods / excludePaymentMethods から解決され、国は税額プレビューと表示する住所フィールドの決定にのみ使われ、購入者の支払通貨には影響しません。支払通貨は購入者が支払いページを開いた時点の IP の所在地で決まります。現地通貨での価格表示を参照。

プラン変更モード

originOrderId を指定すると、このエンドポイントはプラン変更モードに切り替わります。返される checkoutUrl は新規購入リンクではなく、既存サブスクリプションの変更確認ページを指します —— ストア slug の後のパスセグメントが checkout ではなく change になります(…/store/{storeSlug}/change/{sessionId})。プラン変更は 2 ステップです —— このエンドポイントがリンクを発行し、customer がそのページで確認します。 プラン変更は 1 回の解約と 1 回の新規作成としてモデル化されます。変更元の注文は解約の終端状態に入り、新しい注文は通常の作成ライフサイクルを進みます。既存サブスクリプションをその場で書き換えるものではありません。 誰がリンクを発行できるか:API Key(あなたのサーバーサイド)または customer のセッショントークン。Store Slug は匿名であり、変更を帰属させられるサブスクリプションを持たないため、Store Slug 認証で originOrderId を指定すると必ず 403 を返します。

SDK でリンクを発行する

どの SDK もプラン変更に専用メソッドを用意しており、originOrderId は必須です。そのため上記の「originOrderId と同時にのみ有効」という拒否は SDK 上では表現できません:
上記の 3 つは API Key で署名するため、2 つの価格フィールドと withTrial は有効です。checkout.authenticated.createPlanChange()(TypeScript / Next.js は authenticatedPlanChange)または Checkout.Authenticated.CreatePlanChange(Go)を使うと、customer セッショントークンの付加を SDK に任せられます —— それが次節で説明する確認ページに必要なトークンです。 顧客が自分で発行する側は customer.createPlanChangeSession() を customer セッション上で呼び出します(TypeScript は client.customer(token)、Go は client.Customer(token)、Next.js は customerAction(token, "createPlanChangeSession", …))。顧客自身の資格情報で実行されるため上記 3 つの 403 判定がすべて適用され、API Key 専用フィールドはその入力型に存在しません —— プラットフォームはそれらを通知なく破棄するためです。

買い手が開くリンクの組み立て

返される checkoutUrl には買い手の資格情報も環境フラグも含まれません —— セッションはサーバーサイドの資格情報で作成されるため、その時点でプラットフォームは買い手を保証できません。素の URL を開くとプラン比較ページは表示されますが、確認ステップで「認可情報がありません」というエラーになります。両方を自分で付加してください:
クエリパラメータが先、fragment が後です。本番環境では ?test=true を外します。 トークンなしの場合、ページは買い手のメール認証にフォールバックします —— 動作はしますが遅い経路です。環境が誤っているリンクは、以前は確認ステップで Environment mismatch between request and session エラーになっていました。
changeAmount、changeCreditAmount と withTrial は API Key のみです。他の資格情報で指定した場合、新規購入時の priceSnapshot と同じ扱いで黙って無視されます —— 破棄されたことを知らせるエラーは返りません。

変更元サブスクリプションから引き継がれる値

プラン変更モードでは、以下の値はリクエストボディではなく変更対象のサブスクリプションから取得されます。 通貨も変更元サブスクリプションと一致する必要があります —— 通貨をまたぐプラン変更は拒否されます。

この変更の価格の決め方

同じ変更の価格を決める方法が 2 つあり、両者は排他です —— 同時に指定すると 400 を返します。 どちらも表示フォーマットの文字列で、単位も税基準(税込)も同じです。結果が負にならないことも共通で、対象プランの当期請求額を超える請求額は拒否され、それを超えるクレジットも拒否されます。2 つの拒否メッセージは別々なので、どちらのフィールドを下げるべきか分かります。 変更に割引が付く場合、割引はその上で計算されます:即時に適用される変更では、指定した金額が第 1 期の割引前の金額となり、購入者はそこから割引を引いた額を支払います。割引額そのものは対象プランの全額で計算し、指定した金額を上限とします:対象プラン 20.00、changeAmount: "12.00"、20% オフのコード → 割引は 4.00、購入者の支払いは 8.00 です。 同じ数値でも 2 つのフィールドでは意味が逆になるため、プラットフォームが一方を選ぶことはありません。価格の決め方に合う方を選んでください:最終金額が分かっているなら changeAmount、割引額が分かっているなら changeCreditAmount です。以下のタイミング規則にとっては、どちらを指定しても「加盟店がこの変更の価格を決めた」と扱われます。 セッション内部で保持するのは当期の請求額という 1 つの基準だけなので、指定したクレジットは発行時点の対象プランの請求額を用いて請求額に換算されます。

新プランが適用されるタイミング

changeTiming は immediate または next_period を受け付けます。省略するとプラットフォームが変更方向から導出し、方向は税抜価格の比較で判定されます。アップグレードは immediate、ダウングレードと同額切り替えは next_period がデフォルトです。
アップグレードは残り 24 時間を切っても自動で翌期に繰り下がりません。 アップグレードのデフォルトは immediate のため、次回請求まで 24 時間未満の状態で changeTiming を省略すると 400 になります —— changeTiming: "next_period" を明示的に指定してください。ダウングレードは元々 next_period がデフォルトなので、同じ条件でも影響を受けません。

確定済みの変更は同時に 1 件のみ

customer が迷っている間は、同じサブスクリプションに対して複数の変更候補を発行・提出できます。いずれかの変更が決済チャネルによって確定した時点でそのサブスクリプションは 1 件に固定され、それ以降の発行は 409 を返します。

レスポンス

レスポンスボディは新規購入モードと完全に同一です —— sessionId、checkoutUrl、expiresAt のみで、追加フィールドはありません。変更方向、導出されたタイミング、日割りクレジットのプレビューは確認ページが読むためにセッションへ書き込まれるだけで、レスポンスには返りません。結果として 2 点に注意が必要です。
  • changeTiming を省略した場合、プラットフォームがどちらを導出したかは分かりません。確実にしたい場合は明示的に指定してください。
  • 日割りクレジットは発行時点の見積りであり、提出時に実際の残日数で再計算されます。最終金額として customer に提示しないでください。
  • next_period の変更ではカード確認のため $0 の支払いレコードが作成されます。Dashboard の取引一覧ではその行にプラン価格が表示され、その下に Charged $0.00 と示されます。サブスクリプションの課金回数には含まれません。
変更が確定した後に届くものは subscription.plan_changed と 2 つのプラン変更イベント を参照してください。アップグレード・ダウングレードの customer 向けの挙動は サブスクリプション を参照してください。

割引

単発商品、新規サブスクリプション、プラン変更のチェックアウトセッションには、次の方法で割引を付けられます。couponId は promotionCode や allowPromotionCodes と同時には指定できず、両方を送ると 400 になります。 コード入力欄のデフォルト。 allowPromotionCodes を送らないリクエストでは —— 認証の種類を問わず:マーチャントの認証情報(API Key または JWT)、Store Slug(商品リンクまたはストアページ)、またはプラン変更を発行する customer または buyer のセッショントークン ——このストア・環境にセッションの商品(プラン変更では新しいプランの商品)で使えるクーポンが 1 つ以上あるときだけコード入力欄が表示されます。そのクーポンは active で、60 秒以内に期限切れにならず(redeemBy)、合計使用回数が maxRedemptions に達しておらず、商品が対象(productIds が空またはその商品を含む)である必要があります。さらに、クーポン自身のコードまたは少なくとも 1 つのプロモーションコードが active で、60 秒以内に期限切れにならず、自身の使用回数が maxRedemptions に達していない必要があります。購入者に依存するルール(対象購入者、購入者ごとの使用回数、最低金額)と固定額クーポンの通貨はここでは考慮されず、購入者がコードを入力したときに検証されます。期限切れになった直後や上限に達した直後のクーポン・コードでは、最大 5 分間コード入力欄が表示されたままになることがあります。allowPromotionCodes を送った場合はその値がそのまま使われます。couponId、商品リンクの discount_code、または allowPromotionCodes なしで promotionCode を送ったセッションではコード入力欄は表示されません。 セッション作成時の検証。 couponId または promotionCode を指定すると、購入者に依存しないルールでその場で検証されます:このストア・環境に属し、active で、60 秒以内に期限切れにならず、商品(プラン変更では新しいプランの商品)が対象であり、固定額クーポンの場合はセッション通貨の金額があること。promotionCode はストアの有効なコードと大文字小文字を区別せずに照合されます。満たさない場合は 409 を返し、errors[0].message は理由コードです(エラーを参照)。 注文確定時の検証。 購入者に依存するルール(対象購入者、購入者ごとの使用回数)、クーポンの合計使用回数、プロモーションコード自体の合計使用回数(maxRedemptions)と最低金額(minimumAmount)は、購入者が注文を確定するときに再度確認されます。満たさない場合は注文が作成されず、請求も発生せず、チェックアウトセッションは引き続き使用できます。購入者が次にできることは割引の適用方法によって異なります:購入者がコード入力欄に入力したコードは、削除して通常価格で支払うか、別のコードに変更できます。商品リンクで渡されたコードはロックされているため、購入者は discount_code を付けない商品リンクを開き直します(リンクのコードがページを開いた時点で使えない場合、そのページに「割引なしで続ける」が表示されます)。お客様が指定した couponId もロックされているため、couponId を付けずにチェックアウトセッションを作成し直してください。allowPromotionCodes: true を付けずに指定した promotionCode も同様です。すべての理由コードは割引とプロモーションを参照してください。 サブスクリプション。 新規サブスクリプションでは、クーポンの duration によって割引される請求期間の数が決まります。無料トライアルは割引されず、割引は最初の有料期間から始まります。有料トライアルは割引されます。割引とプロモーションを参照してください。 プラン変更。 プラン変更セッション(originOrderId 付き)も couponId、promotionCode、allowPromotionCodes を同じように受け付けます。変更とともに指定されたコード —— お客様が設定したもの、または購入者が入力したもの —— はサブスクリプションの現在の割引を置き換え、新しい利用として扱われます:購入者が変更を確定するときにすべてのルールが再度確認され、プロモーションコードの最低金額は新しいプランの通常価格(割引前・税抜)で判定されます。コードがない場合、現在の割引は継続できる限り新しいプランに引き継がれ、使用済みの期間はリセットされません。第 1 期の割引前の金額は、新しいプランの価格から日割りクレジットを引いた額、または changeAmount / changeCreditAmount で指定した金額です。割引は新しいプランの全額で計算し、そのあとで元のプランの残りのクレジットを差し引くため、購入者の支払いはこの金額から割引を引いた額で、0 を下回りません。これが 0 の場合、割引は第 2 期から始まります。割引とプロモーションを参照してください。
どちらの SDK も、couponId と allowPromotionCodes または promotionCode の同時指定や CPN_ プレフィックスのない couponId をリクエスト送信前に拒否します。Next.js SDK の server action は couponId と promotionCode を取り除きます —— Next.js 統合を参照してください。

セッションロック

チェックアウトセッション作成時に以下の値がロックされ、セッションの有効期間中は変更できません。 productVersionId、productName、priceInfo、storeName、billingPeriod、withTrial、theme、buyerEmail、billingDetail プラン変更モードでは、セッションは変更コンテキストも追加でロックします。変更元サブスクリプションのスナップショット、変更方向、導出されたタイミングと適用時刻、日割りクレジットのプレビュー、指定した金額(changeCreditAmount を指定した場合は換算後の請求額)、およびセッションに設定された割引です。確認ページはすべてをセッションから読むため、提出時にこれらを上書きすることはできません —— 対象プラン、タイミング、金額はリンクを発行した時点で確定します。 メールアドレスの正規化:すべてのメールフィールド(email / buyerEmail / contactEmail)はサーバー側で trim().toLowerCase() により正規化されてから保存・キャッシュ・下流呼び出しに使用されます。Foo@Bar.COM と foo@bar.com は同一アカウントとして扱われます。

リクエスト例

成功レスポンス (200)

レスポンスフィールド

エラー

リトライポリシー:4xx は一切リトライしない — リクエストを修正してから再送信。以下の 409 は種類としての例外であり、ポリシーの例外ではありません:ボディの不備ではなくサブスクリプションの状態を報告しているため、同じリクエストを再送信してもその状態が変わるまで失敗し続けます。5xx は指数バックオフでリトライ(5s 開始、最大 3 回)。
入金受付スイッチと本番承認は互いに独立した 2 つの条件です:前者はプラットフォーム側が制御する入金受付スイッチ(ストア全体の停止も、個別の決済手段のみの停止も可能)、後者は本番承認(KYB)のゲートです。prod 環境では、いずれか一方が満たされないだけで 403 になります。どちらも test 環境には適用されません。
デフォルトのセッション TTL は 24 時間(86400 秒)です。API Key 認証を使用する場合、expiresInSeconds でカスタマイズできます(推奨 1 分〜7 日間)。セッションは作成時に商品バージョンと価格をロックするため、価格変更は既存のセッションに影響しません。