スタメンでエンジニアをしている田中です。 今回は決済プラットフォームであるStripeのサブスクリプションについて、Rubyで実際にコードを書きながら調査をしたので、そのまとめを記述していこうと思います。
目次
Stripeのサブスクリプションについて
Stripeのサブスクリプションは一度作成すると定期的に自動で決済が行われるようになります。 決済金額や支払間隔はStripeのダッシュボードから設定することが可能です。また、API経由で設定することも可能です。
サブスクリプションの作成についても、同様にAPI経由で作成することが可能となっています。本記事では、API経由でサブスクリプションを作成する方法について説明します。
準備
Stripeのgemをインストールします。
gem 'stripe'
StripeのAPIを利用する際にはapi_keyの設定が必要です。 Stripeのダッシュボードにテスト用のsecret_keyがあるので、initializer配下に以下を配置しておきましょう。
Stripe.api_key = 'secret_key'
参考: https://github.com/stripe/stripe-ruby
サブスクリプションの生成
即時にサブスクリプションの契約を行う場合はStripe::Subscription.create
を使用します。
Stripe::Subscription.create({ customer: 'customer_id', items: [ { price: 'price_id', quantity: 1, } ], default_tax_rates: ['tax_id'], })
参考: https://stripe.com/docs/api/subscriptions/create https://stripe.com/docs/billing/subscriptions/examples
テスト用のクレジットカード
Stripeでは様々なケースのテスト用のクレジットカードを用意しています。 各種ブランド・地域、3Dセキュア対応のカードや異常系を想定したカードなど様々です。 以下のページにて一覧で掲載されているので確認してみてください。 https://stripe.com/docs/testing
サブスクリプションの開始時刻の設定
即時に決済を行う場合であれば、先程説明したStripe::Subscription.create
を使用すればよいのですが、事前登録のようにサブスクリプションの開始日を未来日で設定したい場合については、以下のようにStripe::SubscriptionSchedule.create
を利用することで未来日を指定することができます。
Stripe::SubscriptionSchedule.create({ customer: 'customer_id', start_date: 1592699528, # unixtime phases: [ { plans: [price: 'price_id', quantity: 1], default_tax_rates: ['tax_id'] }, ], })
参考: https://stripe.com/docs/api/subscription_schedules/create
注意点として、サブスクリプションが有効になるタイミングと決済が行われるタイミングには1時間の時間差があります。そのため、決済時のWebhookを利用して処理をしようとする際にはこの時間差を考慮する必要があります。具体的には以下の通りです。
start_date
で指定した時刻がサブスクリプションが有効になる時刻start_date
+ 1時間後が決済が行われる時刻
参考: https://stripe.com/docs/billing/subscriptions/overview#subscription-events
トライアル期間の設定
サブスクリプションによくあるビジネスモデルとして一定期間の無料トライアル後に決済を行うケースがあります。Stripeに関しては、即時にサブスクリプションを開始する場合(Stripe::Subscription
)とサブスクリプション開始日を指定する場合(Stripe::SubscriptionSchedule
)のどちらについても、パラメータとしてtrial_end
を渡すことで対応することが出来ます。
Stripe::Subscription.create({ customer: 'customer_id', items: [{ price: 'price_id' }], default_tax_rates: ['tax_id'], trial_end: 1593268745, # unixtime })
Stripe::SubscriptionSchedule.create({ customer: 'customer_id', start_date: 1592699528, # unixtime phases: [ { plans: [price: 'price_id', quantity: 1], default_tax_rates: ['tax_id'], trial_end: 1593268745, # unixtime }, ], })
注意点としては、サブスクリプションの開始時刻を設定する場合と同様、トライアル終了後1時間後に決済が行われます。時系列としては以下のとおりです。
即時にサブスクリプションを開始する場合
trial_end
で指定した日時がトライアル終了日時となるtrial_end
で指定した日時 + 1時間後に決済が行われる
サブスクリプション開始日を指定する場合
start_date
で指定した日時がトライアル開始日時となるstart_date
で指定した日時 + 1時間後にトライアルの決済処理が行われる。しかし、トライアル期間のため0円のインボイスが作成されるtrial_end
で指定した日時がトライアル終了日時となるtrial_end
で指定した日時 + 1時間後に決済が行われる。こちらの決済ではプランに設定された金額が請求される
参考: https://stripe.com/docs/billing/subscriptions/trials
Webhookでイベントの取得
概要
RailsアプリケーションにWebhookのエンドポイントを作成することで、決済の成功・失敗やサブスクリプションの作成といったイベントの通知をStripeから受け取ることができます。本項では、ローカルでの検証方法やエンドポイントの作成方法をご紹介します。
ローカルでの検証方法
StripeではWebhookの検証のためにStripe CLIを提供しています。
以下の手順を参考にインストールしてください。
参考: https://stripe.com/docs/stripe-cli
インストール後、stripe login
を実行してStripeにログインすることで各種コマンドが実行できます。
Webhookを受け取る場合はstripe listen
コマンドで受け取ることが出来ます。
また、ローカル環境のエンドポイントの指定や取得したいイベントを指定して起動することも出来ます。
詳細は下記をご参照ください。
https://stripe.com/docs/stripe-cli/webhooks
イベント一覧
取得できるイベントの一覧は下記をご参照ください。
https://stripe.com/docs/api/events/types
エンドポイントの作成
Webhookを受け取るエンドポイントは、以下の2つの処理を行います。
- requestの検証
- イベントの種類による処理の振り分け
1に関しては、後述する署名の検証を行います。
2に関しては、イベントに応じて行いたい処理を記述してください。(例えば、決済完了処理を受け取ってデータを作成する・ユーザーのステータスを更新する等)
payload = request.body.read event = nil begin event = Stripe::Event.construct_from( JSON.parse(payload, symbolize_names: true) ) rescue JSON::ParserError => e # Invalid payload status 400 return end # Handle the event case event.type when 'payment_intent.succeeded' payment_intent = event.data.object # contains a Stripe::PaymentIntent # Then define and call a method to handle the successful payment intent. # handle_payment_intent_succeeded(payment_intent) when 'payment_method.attached' payment_method = event.data.object # contains a Stripe::PaymentMethod # Then define and call a method to handle the successful attachment of a PaymentMethod. # handle_payment_method_attached(payment_method) # ... handle other event types else # Unexpected event type status 400 return end status 200
参考: https://stripe.com/docs/webhooks/build
署名の検証
StripeのWebhookは署名の検証を行うことが出来ます。
本番環境または検証環境であればStripeのダッシュボードの「開発者」 → 「Webhook」からエンドポイントを設定すると、Webhook用のシークレットキーが発行されます。
ローカル環境であれば、Stripe CLIにてstripe listen
コマンド実行時にシークレットキーが発行されるので、そちらを設定してください。
payload = request.body.read sig_header = request.env['HTTP_STRIPE_SIGNATURE'] endpoint_secret = 'webhookのsecret_key' event = nil begin event = Stripe::Webhook.construct_event( payload, sig_header, endpoint_secret ) rescue JSON::ParserError => e # Invalid payload status 400 return rescue Stripe::SignatureVerificationError => e # Invalid signature status 400 return end
参考: https://stripe.com/docs/webhooks/signatures
まとめ
Stripeのサブスクリプションの基本的な作成から、スケジュールやトライアル、処理後のWebhookといった決済サービスを作成する上で必要なところをまとめてみました。Stripeはドキュメントもしっかりとまとめられており、開発者フレンドリーなプラットフォームだと感じました。まだまだ扱いきれていないこともあるので、今後も機会があればまとめていきたいと思います。
最後に、株式会社スタメンでは一緒に働くエンジニアを募集しています。ご興味のある方はぜひエンジニア採用サイトをご覧ください。