はじめに
BitStarのモリヤです。
BitStar Advent Calender21日目です。
現在開発中のBitStar Matchというプロダクトでは定額課金制の有料機能を提供しています。
サブスクリプション機能を実現するにあたり、以下の観点から外部サービスであるStripeを利用することとなりました。
- 決済処理実装の工数削減
- クレジットカード情報等の機密情報のシステム側での保持が不要
Stripeとは
オンライン決済処理を安全かつ簡単に導入可能にするサービス。
この記事の目的
Stripeのような外部サービスとホスト側のシステムを連携させる上で、重要な注意点があったので共有しようと思います。
ユーザーへの有料機能提供までのラグ
Webhook
Stripeは決済完了などのイベント処理を行う上でWebhookを利用することを推奨しています。
今回の場合、決済手続き開始〜ホスト側システムのデータ更新までは以下のようなフローになります。
事前準備
- Webhook用のエンドポイントをバックエンドに実装
- Stripe管理画面で作成したエンドポイントを登録
このフローを通ることで、以降にサービスへアクセスした際はユーザー情報は課金済み状態となっているため、ユーザーに有料機能を提供することができます。
.
.
.
(Webhookの処理)以降にです。
ココに問題点があります。
ホスト側サービスへのリダイレクトとWebhookの非同期性
ユーザーが"申し込む"をクリックし、決済処理が完了すると事前に登録しておいたURLに自動的にリダイレクトするようになっています。(Stripeの仕様)
事前に登録しておいたURL … サービストップ・サンクスページ・プラン利用状況ページ等が一般的
そして、このリダイレクトとWebhook CALLは非同期で行われています。
Webhook CALL前にサービスにリダイレクトされることも勿論あります。
結果、ユーザー情報が更新される前にサービスにアクセスされ「課金したのに無課金扱いされる」という状況が短期間ですが発生します。
お金を扱う機能として、この状況は致命的です。
解決策
リダイレクト先ページにStripeに対する課金情報取得の処理を仕込む。
Webhookが間に合わないなら、こちらから先にデータを取得しに行っちゃえばいいじゃない!の発想です
今回の場合は、以下のような処理を入れることにより有料機能提供までのラグが発生しないように対処しています。
- リダイレクト先にローディング画面を指定
- ローディング中、裏でStripeへの課金情報取得リクエストを実行
- 取得完了後、DBのユーザー情報を課金済み状態に更新
- 最後にプラン利用状況ページにリダイレクト
※WebhookでのDB更新・課金情報取得側でのDB更新がバッティングすることによるDuplicateエラーの発生を防ぐ考慮も別途必要です。
おわりに
Stripeは一見導入コストが低そうに見えますが、至る所にこちら側で考慮しなければならないポイントが散らばっています。
入念にパターン検証してから実装するようにしましょう。
(二重決済対策だったり…とかとか…)
BitStarでは冒頭でご紹介させていただいたBitStar Matchの開発に携わっていただける仲間を積極募集中です!
ご興味のある方はぜひ以下の募集情報をご確認ください。