LoginSignup
8
8

More than 1 year has passed since last update.

Stripe Checkoutで商品の発送を伴う決済ページ・フローを構築する方法とカスタマイズ

Last updated at Posted at 2023-01-31

Stripe Checkoutを利用して、リダイレクト型の決済ページを簡単に構築することができます。

この記事では、Stripe Checkoutを利用して、通販サイトのような「商品の発送を伴う決済」を提供する方法を紹介します。

配送を伴う決済(ECサイトなど)で必要な設定

通販サイトのような「商品の発送を伴う決済」を提供する場合、注文フローの中で決済情報に加えて「配送に関する情報」も入力・選択してもらう必要があります。

商品の発送に必要な情報の例

  • お客様の氏名
  • お届け先の住所
  • お届け先の電話番号(配送業者によっては省略も可能)
  • 配送方法(速達便・通常便など)

配送に関する情報を、Stripe Checkoutで収集する方法

Stripe Checkoutを利用して決済フローを提供している場合、次のようなフローでこれらの配送情報を集めることができます。

お客様の氏名と、配送先住所を入力できるようにする

まずは配送先住所を入力できるようにしましょう。

Create a Checkout Session APIの、shipping_address_collectionパラメータを利用します。

    await stripe.checkout.sessions.create({
      mode: 'payment',
      line_items: [{
        price: 'price_xxxx',
        quantity: 1
      }],
+      shipping_address_collection: {
+        allowed_countries: ['JP']
+      },
      success_url: 'https://example.com',
      cancel_url: 'https://example.com'
    })

ここでは、「配送可能な国」を2文字のコードで指定します。

日本国外でも配送を行う場合には、該当する国コードを追加してください。

この3行を追加することで、配送先住所を指定できるようになります。

スクリーンショット 2023-01-31 15.58.38.png

電話番号を入力できるようにする

配送のための送り状に電話番号を設定する場合、Checkoutのパラメータを1つ追加します。

    await stripe.checkout.sessions.create({
      mode: 'payment',
      line_items: [{
        price: 'price_xxxx',
        quantity: 1
      }],
+      phone_number_collection: {
+        enabled: true,
+      },
      shipping_address_collection: {
        allowed_countries: ['JP']
      },
      success_url: 'https://example.com',
      cancel_url: 'https://example.com'
    })

phone_number_collection.enabledtrueに設定することで、住所入力フォームに電話番号の入力欄が追加されます。

スクリーンショット 2023-01-31 16.03.09.png

なお、配送業者や伝票の作成方法によっては、お届け先の電話番号の入力が必須ではありません。

配送方法・配送料金を設定する

配送方法や「いつ頃に届くか」などの情報も追加しましょう。

まず、ダッシュボードの配送料金から、新規追加で登録しましょう。

スクリーンショット 0003-12-18 3.15.31.png

送料無料の場合は、0円で作成します。

作成された配送料金のIDを、Create a Checkout Session APIの引数に追加します。


    await stripe.checkout.sessions.create({
      mode: 'payment',
      line_items: [{
        price: 'price_xxxx',
        quantity: 1
      }],
+      shipping_options: [{
+        shipping_rate: 'shr_xxxxx'
+      }],
      phone_number_collection: {
        enabled: true,
      },
      shipping_address_collection: {
        allowed_countries: ['JP']
      },
      success_url: 'https://example.com',
      cancel_url: 'https://example.com'
    })

配送方法が1種類の場合は、商品の小計合計の間に、配送料金予定配送日が表示されます。

スクリーンショット 2023-01-31 16.08.38.png

配送方法を複数登録した場合は、顧客が料金や予定配送日を見て選択できる画面が表示されます。

スクリーンショット 2023-01-31 16.11.43.png

配送料金の設定やAPIについての詳細

「配送に関する注意事項・追加情報」を表示する

「離島や私書箱宛への発送の場合、お届けに追加の日数がかかることがあります」など、配送に関する補足情報を表示したいケースもあります。

その場合は、custom_text.shipping_address.messageパラメータを追加しましょう。


    await stripe.checkout.sessions.create({
      mode: 'payment',
      line_items: [{
        price: 'price_xxxx',
        quantity: 1
      }],
      shipping_options: [{
        shipping_rate: 'shr_123456789',
      }, {
        shipping_rate: 'shr_xxxxxxxxx',
      }],
+      custom_text: {
+        shipping_address: {
+          message: '離島や私書箱宛への発送の場合、お届けに追加の日数がかかることがあります',
+        },
+      },
      phone_number_collection: {
        enabled: true,
      },
      shipping_address_collection: {
        allowed_countries: ['JP']
      },
      success_url: 'https://example.com',
      cancel_url: 'https://example.com'
    })

この設定で、住所入力フォーム下部にテキストメッセージを追加表示できます。

スクリーンショット 2023-01-31 16.16.27.png

Checkout で Stripe によって生成されたテキスト、Stripe との契約、Stripe のポリシー、適用される法律に基づく義務に違反したり、あいまいさを生むカスタムテキストの作成に、この機能を使用することは禁止されています。

追加の提案やカゴ落ちリスクを減らすための追加設定

この他にも売上を増やすためのクロスセルや、カートの中身を編集できるようにすることでカゴ落ちのリスクを減らすことなどがCheckoutでは可能です。

カートの中身を変更できるようにする

消耗品など、複数個購入することが多い商材の場合、数量を変更するためにカートページに戻るステップが発生しやすくなります。

このステップを無くすために、Checkoutの用意する決済ページ上で数量の変更を可能にできます。

    await stripe.checkout.sessions.create({
      mode: 'payment',
      line_items: [{
        price: 'price_xxxx',
        quantity: 1,
+        adjustable_quantity: {
+          enabled: true,
+          minimum: 1,
+          maximum: 5,
+        }
      }],
...

これでCheckoutの決済ページから数量の変更ができるようになります。

スクリーンショット 2023-01-31 16.23.16.png

在庫に関する注意
決済が完了するまで、顧客がどの数量で注文したかをシステムが知ることができません。
maximumの数量が在庫より多くならないようにすること」に注意しましょう。

場合によっては、maximumの数量分を在庫DBで仮押さえする必要があります。
そのケースでは、決済完了後のWebhookイベントにて、注文されなかった数量の在庫を解放しましょう。

ダッシュボードからクロスセルの設定を行う

Stripeダッシュボードの商品設定画面から、商品の追加購入の提案(クロスセル)が行えます。

スクリーンショット 2023-01-31 16.28.15.png

ここで設定した商品は、Checkoutの決済ページにも表示されます。

スクリーンショット 2023-01-31 16.29.03.png

詳細な設定方法や、Payment Linksでの始め方については、以下の記事をご覧ください。

割引・クーポンコードの設定を行う

セールや顧客優待など、様々なケースで商品の割引オファーを行うことがあります。

Checkoutの場合、以下のパラメータを追加することでクーポンコードの入力を受け付けます。

    await stripe.checkout.sessions.create({
      mode: 'payment',
      line_items: [{
        price: 'price_xxxx',
        quantity: 1,
      }],
+      allow_promotion_codes: true,
...

スクリーンショット 2023-01-31 16.31.25.png

限定オファーメールなどで、「クーポンコードの事前設定」を行う

限定オファーのメールやSMS / LINEメッセージなど向けに、クーポンコードを既に設定した状態で決済フローを始めることもできます。

    await stripe.checkout.sessions.create({
      mode: 'payment',
      line_items: [{
        price: 'price_xxxx',
        quantity: 1,
      }],
+      discounts: [{
+        promotion_code: 'promo_xxxx' // プロモーションコードの「ID」を入れましょう
+      }],
...

こちらの設定の場合、クーポンによる割引が設定された状態で決済フローが始まります。

スクリーンショット 2023-01-31 16.34.42.png

パラメータの併用はNG
allow_promotion_codesdiscountsは併用できませんのでご注意ください。

併用した場合、以下のエラーがAPIから返ってきます。

{
    message: 'You may only specify one of these parameters: allow_promotion_codes, discounts.',
    param: 'allow_promotion_codes',
}

有料のオプションを活用する

この他にも有料の機能を利用して、決済フローや注文後のやり取りを便利にすることもできます。

Stripe Taxを使って、消費税の徴収を自動化する

軽減税率の対象商品が商材に混ざっている場合、商品ごとに税率の設定・計算が必要です。

Stripe Taxを利用すると、事前に商品ごとに税率を設定しておくことで、複数の税率の商品注文があった場合にも、徴収額の計算や決済ページの表示をStripe側に任せることができます。

    await stripe.checkout.sessions.create({
      mode: 'payment',
      line_items: [{
        price: 'price_xxxx',
        quantity: 1,
      }],
+      customer_update: {
+        shipping: 'auto'
+      },
+      automatic_tax: {
+        enabled: true,
+      },

スクリーンショット 2023-01-31 16.41.50.png

カスタムドメインを設定する

checkout.example.comのように、所有しているドメインを利用して決済用のサブドメインを設定できます。

スクリーンショット 2022-04-02 16.44.54.png

AWSのRoute 53で設定する方法を紹介していますので、こちらもお試しください。

カスタマーポータルで領収書のPDFをDLできるようにする

注文履歴や領収書の発行をStripe側に任せることも、有料オプションを利用することで可能です。

    const session = await stripe.checkout.sessions.create({
      mode: 'payment',
      line_items: [{
        price: 'price_xxxx',
        quantity: 1
      }],
+      invoice_creation: {
+        enabled: true,
+      },
      success_url: 'https://example.com',
      cancel_url: 'https://example.com'
    })

このパラメータを追加することで、カスタマーポータルの請求履歴から履歴や領収書PDFのダウンロードが可能になります。

スクリーンショット 2023-01-23 10.38.05.png

注文後、配送情報や商品の個数をシステムで受け取る方法

Stripeの場合、さまざまな決済手段(クレジットカードや銀行振込、Apple Payなど)をサポートするため、決済完了後のフローはWebhookベースで行います。

Webhook APIの作り方

Stripeのドキュメントに、Webhook APIの作り方やCheckoutでハンドルするイベントの例を掲載していますので、こちらをぜひご確認ください。

checkout.session.completedイベントから、注文内容や配送情報を取得する方法

checkout.session.completedイベントからは、セッションのIDや注文者情報などが取得できます。

次の画像にある注文を例にしましょう。

スクリーンショット 2023-01-31 16.58.48.png

この場合、次のようなJSONが取得できます。

{
  "api_version": "2020-08-27",
  "created": 1675151950,
  "data": {
    "object": {
      "amount_subtotal": 5000,
      "amount_total": 3300,
      "automatic_tax": {
        "enabled": true,
        "status": "complete"
      },
      "billing_address_collection": "required",
      "cancel_url": "https://example.com",
      "created": 1675151891,
      "currency": "jpy",
      "customer": "cus_NCGybxwanHUtCc",
      "customer_creation": null,
      "customer_details": {
        "address": {
          "city": null,
          "country": "JP",
          "line1": null,
          "line2": null,
          "postal_code": null,
          "state": null
        },
        "email": "test@example.com",
        "name": "test user",
        "phone": "+8109000000000",
        "tax_exempt": "none",
        "tax_ids": []
      },
      "customer_email": null,
      "expires_at": 1675238291,
      "id": "cs_test_a1gve9F9W91peCYDDN9xObfmljhTyS82SgEurD971gyLLjg7JyzaI2PkgS",
      "metadata": {},
      "mode": "payment",
      "object": "checkout.session",
      "payment_intent": "pi_3MWEkAL6R1kGwUF41Ol6SPaQ",
      "payment_status": "paid",
      "shipping": {
        "address": {
          "city": "",
          "country": "JP",
          "line1": "千代田区千代田",
          "line2": "1-1",
          "postal_code": "100-0001",
          "state": "東京都"
        },
        "name": "John due"
      },
      "shipping_rate": "shr_1K7kp5L6R1kGwUF40CJjxc7t",
      "status": "complete",
      "success_url": "https://example.com",
      "total_details": {
        "amount_discount": 2500,
        "amount_shipping": 800,
        "amount_tax": 275
      },
      "url": null
    }
  },
  "id": "evt_1MWEkEL6R1kGwUF4zIFc3h12",
  "type": "checkout.session.completed"
}

※項目数が多いため、関係性の低い値は割愛しています。

  • data.object.shipping: 配送先住所
  • data.object.amount_total: 決済金額
  • data.object.phone: 電話番号
  • data.object.total_details: 送料・割引額・消費税などの内訳
  • data.object.payment_status: 決済が完了しているか否か(銀行振込やコンビニ決済などでは要確認)

など、data.object内から必要な情報を取得しましょう。

CheckoutのセッションIDからカートの中身を取得する

実際に注文された商品や数量については、CheckoutのセッションID(data.object.id)を利用してAPIから取得します。

if (data.type === "checkout.session.completed") {
  const lineItems = await stripe.checkout.sessions.listLineItems(data.object.id)
}

このAPIからは次のようなデータが取得できます。

{
  "object": "list",
  "data": [
    {
      "id": "li_1MWEjHL6R1kGwUF4V5Xvsdaj",
      "object": "item",
      "amount_discount": 1500,
      "amount_subtotal": 3000,
      "amount_tax": 111,
      "amount_total": 1500,
      "currency": "jpy",
      "description": "コーヒー豆",
      "price": {...},
      "quantity": 2
    },
    {
      "id": "li_1MWEjSL6R1kGwUF4DACIr7Ge",
      "object": "item",
      "amount_discount": 1000,
      "amount_subtotal": 2000,
      "amount_tax": 91,
      "amount_total": 1000,
      "currency": "jpy",
      "description": "コーヒーフィルター(布)",
      "price": {...},
      "quantity": 1
    }
  ],
}

※項目数が多いため、関係性の低い値は割愛しています。

data配列内のidquantityを利用して、在庫DBや配送系システムとの連携を行いましょう。

8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8