ECサイトや予約サービスなど、顧客が複数回商品やサービスを注文するユースケースでは、「クレジットカード情報を保存する仕組み」が重要です。2回目以降の注文で、クレジットカード情報を入力する必要がないようにシステムを構築することで、顧客が注文フローの途中で離脱する「カゴ落ち」のリスクを下げることができます。
Stripeによる「EC サイトの決済に関する調査レポート」では、「注文・決済フローが3分以上かかると、49%のユーザーが注文を諦める」との結果がでています。
https://stripe.com/jp/guides/state-of-asia-pacific-checkouts-2022#konbaziyonlu-niguan-suruzhan-lue
この記事では、Stripeを利用してクレジットカード決済を提供する場合の、「カード情報の保存方法」と「利用方法」について紹介します。
Stripeで、クレジットカード情報を2回目以降の注文に利用する方法
Stripeを利用している場合、Stripe上にカード情報を保存することができます。2回目以降の注文では、Stripeアカウント内にPayment Methodとして保存されたカード情報を利用することで、顧客にクレジットカード情報の入力を求めることなく、注文・決済を完了させることができます。
Stripeを利用した場合の購入フロー
StripeのPayment Methodを利用する場合、1回目の注文と2回目以降の注文でフローが少し変わります。
1回目の購入: 支払い情報などを、ECサイトとStripeアカウントに登録する
1回目の購入では、ユーザーはECサイトのログインアカウントを作る必要があります。作成したユーザー情報とStripe内に保存される顧客情報(Customer)や支払い情報(Payment Method)を紐づけることで、2回目以降の注文フローを効率化できます。
- ECサイトのユーザーアカウントを作成する
- Stripeの決済フォーム(ElementsまたはCheckout)を利用して、支払い情報を送信する
- ECサイトのユーザー情報と、Stripeに送信された支払い情報(Payment Method ID)や、作成された顧客情報(Customer ID)を紐づける
「注文完了後にユーザーアカウントを作成する仕組み」を用意する場合は、StripeのCustomer IDやPayment Method IDをどのようにシステム内に保存し、紐付けさせるかを検討する必要があります。
2回目以降の購入: 保存された支払い情報を利用して注文する
2回目以降の注文では、「登録済みの支払い情報」を利用して決済が行えます。ただし個人カードと家族カード・法人用カードのように、商品によって利用するカードを変更するケースや、何かしらの理由(不正利用の被害にあった・紛失したなど)で登録済みのカードが利用できなくなっている場合に備えて、「登録済みの支払い情報以外での決済」もサポートするようにしましょう。
- ECサイトのユーザーアカウントでログインする
- 登録済みの支払い情報を一覧表示し、利用する決済情報を選択する
- (新しい支払い手段を利用する場合は、1回目の購入の流れに入る)
- 選択した支払い情報を利用して決済を行う
Stripe APIで見る、支払い情報の保存方法
ここからは、Stripeを使ってどのように支払い情報の保存を行うかをみていきます。Stripe APIをcURLで呼び出すフローにて紹介しますが、実際の組み込みでは言語ごとに用意されているSDKを利用することをお勧めします。
1回目の注文フローを構築する
まずは「支払い情報を保存する」ための、1回目の注文フローを作りましょう。
Step:1 Stripeに顧客( Customer )データを作成する
Stripe上でクレジットカードなどの支払い情報を保存・利用するには、CustomerデータをStripe上に作成する必要があります。
$ curl -X POST "https://api.stripe.com/v1/customers" \
-u 'REPLACE_WITH_YOUR_SECRET_KEY': \
-d "email"="test@stirpe.com"
Customerデータを作成すると、IDを含むデータがレスポンスで取得できます。このIDをECサイト側に作成されているユーザーデータと紐づけましょう。
{
"id":"cus_P5SHoCX0um98G4",
"object":"customer",
...
}
Step2: 支払いを処理するためのデータ( PaymentIntent )を作成する
Stripeの埋め込み決済フォーム(Stripe Elements)では、支払いを処理するためにPayment Intentを作成します。Payment Intents APIへのリクエストBodyには、先ほど作成したCustomerデータや注文金額・通貨などの情報を渡しましょう。
$ curl -X POST "https://api.stripe.com/v1/payment_intents" \
-u 'REPLACE_WITH_YOUR_SECRET_KEY': \
-d "amount"=1099 \
-d "currency"="jpy" \
-d "customer"="cus_P5SHoCX0um98G4" \
-d "payment_method_options[card][setup_future_usage]"="on_session"
「支払い情報を保存するCustomerのID」と「次回以降の決済にもこの支払い情報を利用すること」を示すsetup_future_usage
パラメータを渡すことで、入力された支払い情報をStripe上に保存できるようにします。
2回目以降の注文をシステム側で処理する場合
IoT機器などを利用した自動注文など、「顧客が注文処理を行わずに決済を処理する」ケースがある場合は、setup-future-usage
の値をoff_session
に変更します。
$ curl -X POST "https://api.stripe.com/v1/payment_intents" \
-u 'REPLACE_WITH_YOUR_SECRET_KEY': \
-d "amount"=1099 \
-d "currency"="jpy" \
-d "customer"="cus_P5SHoCX0um98G4" \
- -d "payment_method_options[card][setup_future_usage]"="on_session"
+ -d "payment_method_options[card][setup_future_usage]"="off_session"
[Tips] Stripe Checkoutを利用する場合は、Checkout Session経由でPayment Intentを作成する
リダイレクト型決済フォームのStripe Checkoutを利用する場合、Payment IntentはCheckout Session経由で作成します。こちらの場合も、「次回以降の決済に支払い情報を利用すること」を示すため、setup-future-usage
をAPIのリクエストBodyに設定しましょう。
$ curl -X POST "https://api.stripe.com/v1/checkout" \
-u 'REPLACE_WITH_YOUR_SECRET_KEY': \
-d "customer"="cus_P5SHoCX0um98G4" \
-d "mode"="payment" \
-d "success_url"="https://example.com"\
-d "line_items[0][price]"="price_1OFp2iL6R1kGwUF4Cbe0C5fw"\
-d "line_items[0][quantity]"="1"\
-d "payment_method_options[card][setup_future_usage]"="on_session"
[Tips] 利用する決済手段をプログラムで制御したい場合
StripeのAPIをversion: 2023-08-16より新しいもので構築している場合、ダッシュボード上で利用する決済手段を設定できます。今回のサンプルコードでは、この機能を利用する前提になっていますが、従来通りプログラムコードで決済手段を制御するには、payment_method_types
パラメータをAPIリクエストに追加しましょう。
Payment Intens API
$ curl -X POST "https://api.stripe.com/v1/payment_intents" \
-u 'REPLACE_WITH_YOUR_SECRET_KEY': \
-d "amount"=1099 \
-d "currency"="jpy" \
-d "customer"="cus_P5SHoCX0um98G4" \
-d "payment_method_options[card][setup_future_usage]"="on_session" \
+ -d "payment_method_types[0]"="card" \
+ -d "payment_method_types[1]"="link"
Checkout Sessions API
$ curl -X POST "https://api.stripe.com/v1/payment_intents" \
-u 'REPLACE_WITH_YOUR_SECRET_KEY': \
-d "customer"="cus_P5SHoCX0um98G4" \
-d "mode"="payment" \
-d "success_url"="https://example.com"\
-d "line_items[0][price]"="price_1OFp2iL6R1kGwUF4Cbe0C5fw"\
-d "line_items[0][quantity]"="1"\
-d "payment_intent_data[setup_future_usage]"="on_session" \
+ -d "payment_method_types[0]"="card" \
+ -d "payment_method_types[1]"="link"
Step3: アプリケーションに決済フォームを埋め込む
作成したPayment IntentまたはCheckout Sessionsの情報を使って、注文フローに決済フォームを組み込みましょう。Payment Intentsでは、APIレスポンスに含まれるClient secretを決済フォーム生成します。Checkout Sessionでは、APIレスポンスにセッションURLが含まれていますので、そのURLにリダイレクトすることで実装できます。
Payment Intentsを利用する場合、まずは決済フォームを表示するHTMLを用意しましょう。
<head>
<title>Checkout</title>
<script src="https://js.stripe.com/v3/"></script>
</head>
<body>
<form id="payment-form">
<div id="link-authentication-element"></div>
<div id="payment-element"></div>
<button type="submit">注文する</button>
</form>
</div>
続いて、決済フォームを生成するためのJavaScriptコードを追加します。Stripe APIを利用してPayment Intentを生成するAPIを事前に用意して、fetch
でアプリケーションから呼び出すようにしましょう。
<script>
document.addEventListener('DOMContentLoaded', async () => {
const stripe = Stripe("pk_から始まるStripeの公開可能APIキーを入力する");
const {
clientSecret
} = await fetch("Payment Intentsを生成するAPIのURL", {
method: "Payment Intentsを生成するAPIのメソッド"
}).then(r => r.json());
});
</script>
APIレスポンスのClient secretを利用して、Stripe Elementsをセットアップします。
const {
clientSecret
} = await fetch("Payment Intentsを生成するAPIのURL", {
method: "Payment Intentsを生成するAPIのメソッド"
}).then(r => r.json());
+ const elements = stripe.elements({
+ clientSecret: "${clientSecret}",
+ appearance: {
+ theme: "stripe"
+ }
+ });
});
その後、elements.create()
を利用して決済フォーム要素を生成しましょう。 defaultValues
を利用することで、ECアプリケーションなどが事前に収集・保存している顧客情報を初期値として渡すことができます。顧客が入力する情報の量を減らすことで、よりカゴ落ちリスクを減らしたり、コンバージョン率を高めたりすることが期待できます。
const elements = stripe.elements({
clientSecret: "${paymentIntent.client_secret}",
appearance: {
theme: "stripe"
}
});
+ const linkAuthenticationElement = elements.create(
+ "linkAuthentication",
+ {
+ defaultValues: {
+ email: "stripe@exampe.com"
+ }
+ }
+ );
+ linkAuthenticationElement.mount("#link-authentication-element");
+
+ // paymentのmount
+ const paymentElement = element.create("payment",{
+ layout: "accordion",
+ defaultValues: {
+ billingDetails: {
+ email: "stripe@example.com",
+ name: "Taro Yamada",
+ phone: "09012345678",
+ address: {
+ line1: "東京都千代田区丸の内1丁目",
+ line2: "",
+ city: "渋谷",
+ state: "東京都",
+ postal_code: "100-0005",
+ country: "JP"
+ }
+ }
+ }
+ });
+ paymentElement.mount("#payment-element");
});
</script>
最後に決済を完了させる処理を追加しましょう。
paymentElement.mount("payment-element");
+ const form = document.getElementById('payment-form');
+ let submitted = false;
+ form.addEventListener('submit', async (e) => {
+ e.preventDefault();
+
+ // Disable double submission of the form
+ if(submitted) { return; }
+ submitted = true;
+ form.querySelector('button').disabled = true;
+ const {error: stripeError} = await stripe.confirmPayment({
+ elements,
+ confirmParams: {
+ return_url: `${window.location.origin}/index.html`,
+ }
+ });
+
+ if (stripeError) {
+ alert(stripeError.message);
+
+ // reenable the form.
+ submitted = false;
+ form.querySelector('button').disabled = false;
+ return;
+ }
+ });
});
</script>
これでテストのカード情報を入力するためのUIが用意できました。
Step4: テストのクレジットカード情報をフォームに入力する
実際にテストのカード情報を送信してみましょう。Stripeのテスト環境では、Stripeが用意する「テスト用の支払い情報」を利用して決済を試みることができます。
- カード番号:
4242 4242 4242 4242
など、テストケースに応じたカード番号 - 有効な将来の日付 (12/34 など)
- 任意の 3 桁 (American Express カードの場合は 4 桁) のセキュリティーコード
の3つを利用して、決済処理を完了させましょう。
決済に成功すると、Stripeダッシュボードの支払いページに成功した決済として情報が表示されます。
支払いの詳細情報ページでは、「この支払いにより、今後の on-session の支払いに pm_xxx が設定されました」とのテキストが表示されています。このメッセージがある場合、支払いに利用したカード情報などが、次回以降のon-session(顧客が注文操作を自ら行うフロー)で再利用できます。
Step5: 支払い情報を、顧客のデフォルト決済手段に設定する
次回以降の支払いに利用できる決済手段の登録が完了しました。Stripeでは「この顧客の、デフォルトで利用する決済手段」を設定することもできます。決済手段は、pm_
から始まるPayment MethodオブジェクトとしてStripeに保存されます。このPayment Methodデータを、Customerオブジェクトの「デフォルトの支払い手段」として登録させましょう。
登録は、Customerオブジェクトのinvoice_settings.default_payment_method
に設定します。顧客情報を更新するAPIを利用して更新できます。
$ curl -X POST "https://api.stripe.com/v1/customers/{customer}" \
-u 'REPLACE_WITH_YOUR_SECRET_KEY': \
-d "invoice_settings[default_payment_method]"="pm_1OHIFoEzgtKktpOykZPfaUAD"
Customerデータを取得した際に、invoice_settings[default_payment_method]
にpm_
から始まるIDが設定されていれば、設定完了です。
{
"id":"cus_P5SHoCX0um98G4",
"object":"customer",
...
"invoice_settings":{
"custom_fields":null,
"default_payment_method":"pm_1OHIFoEzgtKktpOykZPfaUAD",
},
...
}
デフォルトの支払い方法に設定する処理は、Webhookで
アプリケーションに組み込む際は、 Stripe Webhookと連携したAPIでこの処理を実行します。Webhook経由で実装することで、「支払いに成功した場合のみ設定する」のような条件付けがしやすくなります。また、決済処理を行うコードの中ではなく、専用のWebhook APIを用意することにより、「アプリケーションコードをよりシンプルにすること」や、「サブスクリプションや請求書・見積書などに対応した場合にも、この処理を追加作業なしで利用できる」などのメリットもあります。
決済が成功した時のみ処理を行う場合は、payment_intent.succeeded
イベントを利用しましょう。
これで初めて注文した顧客が、2回目以降でも同じ支払い手段を利用できるようにする準備ができました。
2回目以降の注文フローを構築する
今後は保存した支払い手段を利用して注文するフローを作りましょう。2回目以降は初回購入で登録されたPaymentMethodを使用して、決済フローを作成します。
Step0: ログインユーザー情報などから、StripeのCustomer情報を取得する
2回目以降のリピート注文を処理するには、以前の注文時に作成されたCustomerデータが必要です。そのため、ECサイトなどのユーザーDB情報を利用して、StripeのCustomerデータのID
を取得しましょう。
メールアドレスをキーにして情報を取得したい場合は、StripeのSearch APIを利用することもできます。ただしSearch APIは「1 秒あたり最大 20 件の読み取り操作」と通常のAPIよりも厳しいレート制限が設けられていることに注意が必要です。
curl -G https://api.stripe.com/v1/customers/search \
-u "REPLACE_WITH_YOUR_SECRET_KEY:" \
--data-urlencode query="email:'stripe@example.com'"
「cus_
から始まるCustomer IDを取得する」ことが目的ですので、ECサイト側のユーザーDBやmetadataなどに保存する形でも対応できます。
Step1: 登録済みのPaymentMethodを取得する
取得したCustomerのIDを利用して、デフォルトの支払い手段として設定したPayment Methodを取得しましょう。ここではCustomer IDを利用してCustomerデータを取得します。すでにSearch APIなどを利用してデータを取得している場合には、API呼び出しをスキップできます。
$ curl "https://api.stripe.com/v1/customers/cus_P5SHoCX0um98G4" \
-u 'REPLACE_WITH_YOUR_SECRET_KEY':
APIレスポンスに含まれるinvoice_settings.default_payment_mehothod
が、デフォルトの支払い手段です。pm_
から始まるPayment Method IDを取得しましょう。
{
"id":"cus_P5SHoCX0um98G4",
"object":"customer",
...
"invoice_settings":{
"default_payment_method":"pm_1OHIFoEzgtKktpOykZPfaUAD",
},
...
}
Step2: 支払い手段とCustomerを指定してPaymentIntentを作成する
登録済みの支払い手段を利用する場合でも、決済フローを開始するにはPayment Intentを作成します。今回はPaymentMethodとCustomerそれぞれのIDもリクエストパラメータに設定しましょう。
$ curl -X POST "https://api.stripe.com/v1/payment_intents" \
-u 'REPLACE_WITH_YOUR_SECRET_KEY': \
-d "amount"=1099 \
-d "currency"="jpy" \
-d "payment_method"="pm_1OHIFoEzgtKktpOykZPfaUAD" \
-d "customer"="cus_P5SHoCX0um98G4" \
-d "expand[]"="payment_method"
APIのレスポンスに含まれるPayment Intentは、status
がrequires_confirmation
になっています。これは「この支払い手段を利用して決済を行うこと」を顧客に確認する必要があることを示しています。
{
"id":"pi_3OHIT3EzgtKktpOy0hGf06Qy",
"object":"payment_intent",
"client_secret":"pi_3OHIT3EzgtKktpOy0hGf06Qy_secret_ONJxi884ITsDcMBL1TCmSedzt",
"payment_method":"pm_1OHIFoEzgtKktpOykZPfaUAD",
...
"status":"requires_confirmation",
...
}
Step3: 確認画面に、利用するカード情報を表示する
2回目以降の注文でも、最終確認画面などで「どのカードを利用して決済を行うか」を表示しましょう。ユーザーが誤ったカードを利用して注文を行うことを予防し、返金処理などのサポート問い合わせを減少できます。
PaymentIntent APIやPayment Method APIから取得したカード情報では、last4
やbrand
などの値を利用してユーザーに表示する情報を取得できます。
<ul>
<li>カードブランド: ${paymentMethod.card?.brand}</li>
<li>カード番号(下4桁): ${paymentMethod.card?.last4}</li>
<li>有効期限: ${paymentMethod.card?.exp_month} / ${paymentMethod.card?.exp_year}</li>
</ul>
Step4: Payment Intent作成時に指定したカードで、決済を実施する
設定したカード情報を利用して決済を行う場合、Stripe.jsのconfirmCardPaymentを利用します。
stripe
.confirmCardPayment('${paymentIntent.client_secret}')
.then(function(result) {
// Handle result.error or result.paymentIntent
});
カード情報を変更して決済を行う場合
Payment Intent作成時にPayment Methodを指定した場合でも、別のクレジットカードや支払い手段を利用して決済を行うことができます。
その場合、1回目の注文フローを構築するで紹介した方法と同様に、PaymentElement
を利用して決済手段を選択・入力するUIを表示します。
<form id="payment-form">
<div id="payment-element"></div>
<button type="submit">注文する</button>
</form>
<script>
const stripe = Stripe("${c.env.STRIPE_PUBLISHABLE_KEY}")
const elements = stripe.elements({
clientSecret: "${paymentIntent.client_secret}",
appearance: {
theme: "stripe"
}
})
const paymentElement = elements.create("payment", {
layout: 'accordion',
})
paymentElement.mount("#payment-element")
</script>
その後confirmPayment
を利用して決済を完了させましょう。
<form id="payment-form">
<div id="payment-element"></div>
<button type="submit">注文する</button>
</form>
<script>
const stripe = Stripe("${c.env.STRIPE_PUBLISHABLE_KEY}")
const elements = stripe.elements({
clientSecret: "${paymentIntent.client_secret}",
appearance: {
theme: "stripe"
}
})
const paymentElement = elements.create("payment", {
layout: 'accordion',
})
paymentElement.mount("#payment-element")
+ const form = document.getElementById("payment-form")
+ form.addEventListener("submit", async e => {
+ e.preventDefault()
+ const result = await stripe.confirmPayment({
+ elements,
+ redirect: "if_required",
+ })
+ console.log(result)
+ })
</script>
confirmCardPayment('Payment_Intent.client_secret')
の代わりにconfirmPayment
を実行することで、ユーザーが入力した支払い情報を利用した決済を行えます。
おわりに
Stripeを利用する場合、Payment Intent APIとStripe.jsを利用することで、一度ユーザーが決済に利用したカード情報を2回目以降の決済に備えて保存できます。2回目以降の支払いでは、StripeにPayment Methodとして保存されている決済手段のIDをPayment IntentやconfirmCardPayment
の引数に設定することで、ユーザーがカードを入力する手間を省くことが可能です。
また、3Dセキュア認証の処理や、決済に利用するカード情報の一部(下4桁のカード番号やブランド名など)をユーザーに表示する処理などの実装にも簡単に対応できます。
この記事ではcurlとJavaScriptを利用したコードサンプルで手順を紹介しましたが、皆様がお使いの言語やフレームワークにて、この記事の内容を実践してみたレポート記事やブログ投稿を作成していただけると、幸いです。
参考記事
関連する開発ドキュメント記事
紹介したAPI