- Stripe Checkout と Webhook
- Checkout session と Webhook の紐付け
- Subscription の metadata を使う
- customer.subscription.created 以外の Webhook を使うのは?
- success_url に到達した瞬間にサービス提供するのは?
Stripe Checkout と Webhook
Stripe で Subscription を実装する時に、 Stripe Checkout というのを利用できます。
Stripe Checkout では、クレジットカード入力の画面を Stripe 側が用意してくれているので、簡単に決済画面の実装ができます。
Stripe 公式のドキュメントの Quickstart を見ると、実装のチュートリアルがあります。
決済結果等は Webhook でサーバーに送られてきます。
Stripe の Quickstart を見と、 customer.subscription.created
イベントが飛んできた時になんかやれ、って書いてあります。
基本的には、この customer.subscription.created
をもってして、決済完了&サブスクの手続きが完了したとして、アプリケーションのDBにサブスクリプション情報を保存して、サービス提供をするのが筋です。
Checkout session と Webhook の紐付け
ここで重要になるのが、Webhook で飛んできた Subscription の情報が、アプリケーション(我々が作っているもの)のどのユーザーのものなのかを特定する必要があることです。
この Quickstart の実装だと、誰が契約した Subscription なのかわからずに詰みます(多分)
私も困りました。
Subscription の metadata を使う
Subscription に限らす、Stripe のオブジェクト(決済、請求書、プラン、などのオブジェクト)には、 metadata が付与できます。
Stripe Checkout のセッションを作成するときに、subscription_data というのを渡すと、Subscription に任意のデータを付与することができます。
Stripe で Checkout session を作成するときに使っているAPIは以下です。
https://stripe.com/docs/api/checkout/sessions/create
metadata の付与の仕方ですが、PHP だとこんな感じですね。
$session = Session::create([ 'success_url' => 'http://xxxxx/success?session_id={CHECKOUT_SESSION_ID}', 'cancel_url' => 'http://xxxxx/canceled', 'mode' => 'subscription', 'line_items' => [ ['price' => 'price id を指定', 'quantity' => 1], ], 'subscription_data' => [ 'metadata' => [ 'user_id' => 'hoge', ], ], ]);
こうすると、 Webhook で届く Subscription 情報の metadata に user_id の情報が入ってくるので、どのユーザーの処理が完了したのかがわかります。
customer.subscription.created 以外の Webhook を使うのは?
customer.subscription.created 以外にも、様々な Webhook が飛んできます。
charge.succeeded だったり、checkout.session.completed だったり。
これらを組み合わせれば、サブスクリプションがどのユーザーのものか特定できそうな気がしますが、どんな順番で Webhook が飛んでくるかわかりません。(ネットワークの回線状況の問題もありますし...)
順序保証があったとしても、Webhookを処理している途中で次のWebhookが届いてしまう可能性もあるため、正確に処理しようとすると実装は複雑になります。
とすると、やはり、 subscription の作成に成功した customer.subscription.created を受け取って処理する、というのがシンプルかと思います。
success_url に到達した瞬間にサービス提供するのは?
success_url に到達した時点では、決済が正常に完了しているかわかりませんし、サブスクリプションの処理が完全に終了しているかわかりません。
やはり、 customer.subscription.created の Webhook を受け取ってサービス提供するのが無難かなと思います。