Stripeで、Elementsを利用して契約時にカード情報を入力させる形でサブスクリプションを開始した場合、「次回以降の支払いに利用する決済方法」をWebhookで指定する必要がありました。
Webhookで支払い方法を設定するサンプルコード
引用元: https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=elements#default-payment-method
if (dataObject['billing_reason'] == 'subscription_create') {
const subscription_id = dataObject['subscription']
const payment_intent_id = dataObject['payment_intent']
// Retrieve the payment intent used to pay the subscription
const payment_intent = await stripe.paymentIntents.retrieve(payment_intent_id);
const subscription = await stripe.subscriptions.update(
subscription_id,
{
default_payment_method: payment_intent.payment_method,
},
);
};
2022/06のAPIアップデートで、「Webhookを利用せずにデフォルトの支払い方法を設定する方法」が追加されましたので、紹介します。
save_default_payment_method
をsubscriptions.create
で設定する
Elementsを利用して決済情報を入力させるフローでは、以下のように「決済未完了のサブスクリプション」を事前に作成します。
const subscription = await stripe.subscriptions.create({
items: [{
price: 'price_xxx',
quantity: 1
}],
customer:'cus_xxx',
payment_behavior: 'default_incomplete',
expand: ['latest_invoice.payment_intent'],
})
res.status(200).json({
subscriptionId: subscription.id,
clientSecret: (subscription.latest_invoice as any).payment_intent.client_secret,
})
ここに新しく、save_default_payment_method
を追加しましょう。
const subscription = await stripe.subscriptions.create({
items: [{
price: 'price_xxx',
quantity: 1
}],
customer:'cus_xxx',
+ payment_settings: {
+ save_default_payment_method: 'on_subscription',
+ },
payment_behavior: 'default_incomplete',
expand: ['latest_invoice.payment_intent'],
})
res.status(200).json({
subscriptionId: subscription.id,
clientSecret: (subscription.latest_invoice as any).payment_intent.client_secret,
})
フロントエンドの実装は変更なし
フロントエンド側での追加実装は不要です。
これまでと同じく、APIで作成したサブスクリプションのclient_secretを受け取りとElement.jsのセットアップを行います。
import { Elements } from '@stripe/react-stripe-js'
import { loadStripe } from '@stripe/stripe-js'
import { useState } from 'react'
const Home = () => {
const [paymentIntentClientSecret, setPaymentIntentClientSecret] = useState('')
return (
<main>
<form onSubmit={async e => {
e.preventDefault()
const response = await fetch('/api/subscription')
const result = await response.json()
setPaymentIntentClientSecret(result.clientSecret)
}}>
<button type='submit'>購読する</button>
</form>
<section>
{paymentIntentClientSecret ? (
<Elements
options={{
loader: 'always',
appearance: {
theme: 'stripe'
},
clientSecret: paymentIntentClientSecret,
}}
stripe={loadStripe('pk_test_xxx')}
>
<SubscriptionForm />
</Elements>
): null}
</section>
</main>
)
}
あとはuseStripe
などを利用して、決済処理を行うだけです。
import { PaymentElement, useElements, useStripe } from '@stripe/react-stripe-js'
const SubscriptionForm = () => {
const stripe = useStripe()
const elements = useElements()
return (
<form onSubmit={async e => {
e.preventDefault()
if (!elements || !stripe) return;
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: 'http://localhost:3000'
}
})
console.log(error)
}}>
<PaymentElement />
<button type='submit'>定期購読を開始する</button>
</form>
)
}
Webhookを利用する必要があるケース
今回のAPIアップデートに対応することで、Webhookでデフォルトの決済方法を指定する必要はなくなります。
ですが、今後も「初回の決済に成功した場合に、システム側で処理を行う」要件が発生した場合には、Webhookを利用する必要があります。
- 銀行振込など、その場で決済成功を確認できない決済手段をサポートするケース
- 支払いの完了をもってサービスの提供を開始させたいケース
- CRM / MAなど、外部ツールやDBとデータを連携させたいケース
- etc..
これらのケースでは、以下のWebhookイベントと条件を利用したAPIの実装が引き続き必要です。
if (event.type !== 'customer.subscription.updated') return
const dataObject = event.data.object
if (dataObject['status'] == 'active') {
// 各種処理を記述
}
[PR] Stripe開発者向け情報をQiitaにて配信中!
- [Stripe Updates]:開発者向けStripeアップデート紹介・解説
- ユースケース別のStripe製品や実装サンプルの紹介
- Stripeと外部サービス・OSSとの連携方法やTipsの紹介
- 初心者向けのチュートリアル(予定)
など、Stripeを利用してオンラインビジネスを始める方法について週に2〜3本ペースで更新中です。