LoginSignup
2
0

SaaSで「プランごとに利用できる機能を制御する」機能を、Stripeだけで実装する方法

Posted at

SaaSプロダクトにおける機能や権限の管理は複雑で手間がかかりがちです。専用のDBテーブルや管理ロジック、そしてサーバー側とフロントエンドの実装が必要になる上、価格改定や新プランの提供開始などで定期的に動きを変更する必要が生まれます。この記事では、2024年にStripeが発表したEntitlements APIを活用して、これらのプラン別アクセス権限管理機能を効率的に実装する方法を紹介します。

SaaSプロダクトにおける機能アクセス権限管理の課題

SaaSプロダクトでは、顧客ごとに異なる料金プランやサブスクリプションに応じて、利用可能な機能を切り替える必要があります。さらに、新サービスの追加や価格の改定などが行われる度に、機能へのアクセス権限の管理ロジックを変更しなければなりません。

これらの管理を自社で行うには、以下のような機能やシステムが必要となります。

  • 権限管理システム
  • プランや製品と権限のマッピング
  • ユーザー情報とプラン・権限のデータ連携
  • 価格改定や新プランの追加に伴うシステム改修

これらの開発や運用保守には、少なくないリソースが必要です。そのため、プロダクトのコア機能から注力が逸れがちになり、システムが肥大化し、保守性が低下するなどの問題を生じさせます。

Entitlements APIで実現する機能アクセス権限管理の外部化

StripeのEntitlements APIを利用することで、機能へのアクセス権限管理を製品の外部に委託することができます。

  1. 料金・商品情報と一緒に「アクセス権限( エンタイトルメント )」情報もStripeで定義・保存します
  2. 商品とアクセス権限を関連付けることで、プランごとに利用できる権限のマッピングを行います
  3. 関連付け済みの商品を利用してサブスクリプションを作成するだけで、その顧客がアクセスできる権限を更新できます
  4. Stripe上の顧客ID(cus_xxx)を利用して、その顧客が持つアクセス権限の一覧を取得できます
  5. 利用可能な機能が変更された場合は、webhookでリアルタイムに通知されます

つまり、サービス側では利用可能な機能の一覧を参照するだけで良くなります。

Entitlements APIで、アクセス権限を顧客に付与する方法

それでは実際にアクセス権限の付与を行ってみましょう。ここからはStripe WorkbenchとStripe CLIを利用して設定を行います。

Stripe Workbenchについて
Stripe Workbenchは、2024/05時点でベータ版提供の機能です。そのため、以下のURLからベータ版機能を有効化する必要があります。

https://dashboard.stripe.com/workbench

Step1: 提供するプランと機能(アクセス権限)を設計する

まずは「どんな製品をいくらで提供するか」や「どのようなアクセス権を付与すべきか」の設計を行いましょう。例えばウェブサイトやアプリケーションのホスティングサービスでは、多くの場合有料プランでのみ独自ドメインの設定ができます。また、LLMをベースとしたAIチャットアプリケーションでは、上位プランでのみ利用できるモデルが用意されています。今回は有料のオンラインメディアサイトを例にして、以下のようなモデルを用意しました。

商品名 価格 権限
Free 0円 無料記事閲覧
Personal 980円/月 無料記事閲覧 / 有料記事閲覧
Business 4,980円/月 無料記事閲覧 / 有料記事閲覧 / ビジネスレポート閲覧

今回の例は、1ユーザーが1つのプランを契約する体系を想定したモデルです。そのため、上位プランの商品にも下位プランで提供する機能へのアクセス権限を登録するように設計しました。もしホスティングサービスのCDNオプションのような、複数のプランを組み合わせて契約するモデルでは、次のような設計も考えることができます。

商品名 価格 権限
Hobby 980円/月 Webサーバー1台
Business 1980円/月 Webサーバー1台 / DBサーバー1台
CDN Option 980~円/月 (従量課金) CDN 1ディストリビューション
Backup Option 980円/月 10バックアップ

モデルの設計ができましたので、実装に落とし込みましょう。

Step2: Stripe上に商品・料金とエンタイトルメントを登録する

先ほど作成したモデルに応じて、商品や料金などの情報をStripeに登録します。まずはページ下にある黒いバーをクリックしましょう。クリックすると、Stripeの新しい開発支援ツール「Workbench」が立ち上がります。

スクリーンショット 2024-05-21 14.34.11.png

Workbenchでは、APIキーやAPIリクエストログ・エラーログそしてWebhookのイベントログなど、Stripeの組み込みや運用保守に必要な情報をまとめて見ることができます。また、StripeのAPIをブラウザ上でテストするStripe Shell機能も用意されており、この記事ではこのStripe Shellを利用して作業を行います。Stripe Shellを起動するため、Workbench上部にあるタブの、Shellをクリックしましょう。

スクリーンショット 2024-05-21 14.34.32.png

Stripe Shellが起動しました。ここではStripe CLIをブラウザ上で実行できるだけでなく、StripeのAPIやAPIがサポートするパラメータを確認しながら動作テストまで行うことができるAPI Explorer機能も利用できます。ページ右側にあるAPI Explorerの、Resourceをクリックしましょう。

スクリーンショット 2024-05-21 14.34.43.png

利用できるAPIリソースを表示・検索できるUIが表示されます。ここでproductを検索フォームに入力し、Productsを選択してください。Stripe上で商品情報を管理するためのProducts APIが選択された状態となります。

スクリーンショット 2024-05-21 14.38.50.png

Products APIで利用するメソッドを指定するため、Resource右側にあるMethodを選択しましょう。今回は新しく商品を登録しますので、createと検索フォームに入力して、Createメソッドを選択します。これでStripeに商品登録を行うAPIをテストする準備ができました。

スクリーンショット 2024-05-21 14.39.06.png

API ExplorerのParametersにこのAPIで利用できるパラメーターが表示されています。ここに商品や料金の情報を入力することで、商品と料金をまとめて登録することができます。

スクリーンショット 2024-05-21 14.42.10.png

今回は以下の内容でフォームを入力しましょう。

name value
name Free
default_price_data[currency] jpy
default_price_data[unit_amount] 0
default_price_data[recurring][interval] month

入力が終わると、次のような表示になります。

スクリーンショット 2024-05-21 14.46.01.png

また、ページ下部にはAPI Explorerで設定した値がStripe CLIのパラメータとして表示されています。表示されているStripe CLIコマンドをコピーすることで、手元の環境で実行させたり、Wikiや社内チャットにコマンドを共有することもできます。

スクリーンショット 2024-05-21 14.46.33.png

もしAPI Explorerの操作がうまくいかない場合は、下のコマンドをコピーしてShellに貼り付けてください。

stripe products create --name="Free" \
 -d "default_price_data[currency]=jpy" \
 -d "default_price_data[unit_amount]=0" \
 -d "default_price_data[recurring][interval]=month" 

コマンドを入力した状態で**[Enterキー]を押すか、ページ右下のRun**ボタンをクリックすることでコマンドが実行されます。

スクリーンショット 2024-05-21 14.48.55.png

コマンドを言語別のSDKに変換する
API ExplorerでテストしたAPIリクエストを実装に反映させるのはとても簡単です。API Explorer下部にあるPrint SDK requestリンクをクリックすると、その右側に表示されている言語で同じ内容のAPIリクエストを送信するコードが出力されます。

スクリーンショット 2024-05-21 14.51.15.png

残りの2商品についても、Stripe Shellで登録しましょう。以下にコマンドを用意しましたので、コピーアンドペーストで実行してください。

stripe products create --name="Business" \
 -d "default_price_data[currency]=jpy" \
 -d "default_price_data[unit_amount]=4980" \
 -d "default_price_data[recurring][interval]=month" 
stripe products create --name="Personal" \
 -d "default_price_data[currency]=jpy" \
 -d "default_price_data[unit_amount]=980" \
 -d "default_price_data[recurring][interval]=month" 

ダッシュボードの商品カタログページに、3商品が表示されていれば、登録成功です。

スクリーンショット 2024-05-21 14.53.06.png

Step3: 商品へアクセス権限(エンタイトルメント)を登録する

商品と料金の設定ができましたので、続いて商品ごとの権限設定を行いましょう。Stripeでは、顧客に付与するアクセス権限はプロダクト単位で管理します。それぞれの権限は、Featureリソースとして登録する必要があり、それをProductに紐づける形です。

スクリーンショット 2024-05-21 14.57.15.png

機能をEntitlements Featuresとして登録する

まずはFeatureリソースを作成しましょう。API Explorerで以下の値を入力して、3つの権限を登録しましょう。ResourceはEntitlments Features、 MethodはCreateを利用します。

スクリーンショット 2024-05-21 15.06.09.png

無料記事閲覧 有料記事閲覧 ビジネスレポート閲覧
name 無料記事閲覧 有料記事閲覧 ビジネスレポート閲覧
lookup_key free_posts paid_posts biz_reports

またはStripe Shellに以下の3コマンドをコピーアンドペーストしてもOKです。

stripe entitlements features create --lookup-key="free_posts" --name="無料記事閲覧" 
stripe entitlements features create --lookup-key="paid_posts" --name="有料記事閲覧"
stripe entitlements features create --lookup-key="biz_reports" --name="ビジネスレポート閲覧"

エラーメッセージが表示されなければ、登録成功です。

スクリーンショット 2024-05-21 15.07.11.png

続いて登録した機能を各商品に紐づけましょう。

登録した機能を、商品に紐づける

商品を通してユーザーにアクセス権限を付与するには、商品と機能の関連付けが必要です。これもStripeではAPIを利用して実施します。紐付けには、商品IDが必要です。ダッシュボードの商品カタログページで、付与したい商品の詳細ページに移動しましょう。

スクリーンショット 2024-05-21 14.53.06.png

Workbenchを開いた状態で、商品の詳細ページに移動すると、画面右下にprod_から始まる文字列が表示されます。
スクリーンショット 2024-05-21 15.11.11.png

これをクリックすると、今アクセスしているページのリソース内容をJSONで確認できる「Inspect」タブに移動します。これを利用して、GUIで作成したリソースなどのパラメータを確認することができ、デバッグやAPIリクエストへの落とし込みなどがスムーズに行うことが可能となります。

スクリーンショット 2024-05-21 15.11.48.png

[Inspect]で表示されている商品IDをコピーして、[Shell]タブに戻りましょう。API Explorerを開いて、ResourceはProduct Features、 MethodはCreateを選択しましょう。Path argumentsidに、コピーした商品IDを保存します。

スクリーンショット 2024-05-21 15.17.13.png

続いて紐づける機能IDについては、stripe entitlements features listコマンドで一覧表示できます。一覧で表示されますので、idにあるfeat_から始まるIDをコピーしておきましょう。

スクリーンショット 2024-05-21 15.17.27.png

コピーしたIDを、API Explorerで表示中のパラメータentitlment_featureに設定しましょう。これで商品と機能を紐付けするリクエストの準備ができました。

スクリーンショット 2024-05-21 15.18.48.png

あとは生成されたStripe CLIコマンドを商品へ登録する機能ごとに実行するだけです。

stripe product_features create "Freeの商品ID" --entitlement-feature="無料記事閲覧の機能ID"

stripe product_features create "Personalの商品ID" --entitlement-feature="無料記事閲覧の機能ID"
stripe product_features create "Personalの商品ID" --entitlement-feature="有料記事閲覧の機能ID"

stripe product_features create "Businessの商品ID" --entitlement-feature="無料記事閲覧の機能ID"
stripe product_features create "Businessの商品ID" --entitlement-feature="有料記事閲覧の機能ID"
stripe product_features create "Businessの商品ID" --entitlement-feature="ビジネスレポート閲覧の機能ID"

全てのコマンドを実行すると、紐付け完了です。stripe product_features list prod_から始まる商品IDを実行することで、商品ごとに設定されている機能を見ることができます。

スクリーンショット 2024-05-21 15.23.43.png

ここまでで商品ごとのアクセス権限設定と、顧客がサブスクリプションを開始するための前準備が完了しました。

Step4: 顧客を登録し、サブスクリプションを作成する

商品側の設定が完了したので、顧客とサブスクリプションデータを作成してみましょう。ページ上部にあるサブスクリプション作成ボタンをクリックして、作成フォームを表示されましょう。

スクリーンショット 2024-05-21 15.24.58.png

フォームにテスト用のメールアドレスを入力し、先ほど作成した商品のどれか1つをサブスクリプションの詳細に設定します。その後、支払いに利用するクレジットカードを、4242424242424242などのテスト用カード番号で登録して、作成を完了させましょう。

スクリーンショット 2024-05-21 15.26.07.png

サブスクリプションが新しくダッシュボードに表示されていれば、作成成功です。ここの実装方法は、Entitlement APIを利用していない場合と同じです。そのため、Stripe CheckoutやStripe Elementsを利用した場合の実装も、このステップでは追加の作業はありません。

Step5: 顧客にアクセス権限が付与されているかを確認する

サブスクリプションが作成できましたので、顧客にアクセス権限が付与されているかを確認してみましょう。アクセス権限の確認には、顧客のIDが必要です。サブスクリプション一覧ページから、[顧客を表示]ボタンをクリックすることで、顧客情報詳細ページに移動できます。

スクリーンショット 2024-05-21 15.27.49.png

詳細ページのURLやUIなどで、cus_から始まる顧客IDをコピーしましょう。あとはStripe Shellでこの値を利用したコマンドを実行するだけです。

スクリーンショット 2024-05-21 15.29.50.png

stripe active_entitlements list \
--customer="cus_から始まる顧客ID" 

このコマンドを実行すると、サブスクリプションへ設定した商品に対応したアクセス権限が取得できます。

スクリーンショット 2024-05-21 15.33.31.png

このAPIレスポンスで、アクセス権限の名前まで取得したい場合は、expandパラメータを追加しましょう。

stripe active_entitlements list \
+ -d "expand[0]=data.feature" \
 --customer="cus_から始まる顧客ID"

スクリーンショット 2024-05-21 15.35.32.png

アプリケーションの組み込みでは、lookup_keyに設定したキーを利用して表示や処理の制御を行います。 下のHonoを利用したAPIでは、biz_reportsのキーを持つエンタイトルメントを付与されていない顧客は、プランアップグレードを促すメッセージが表示されます。

app.get('/cus', async c => {
    const stripe = new Stripe('sk_test_xxx')
    const requiredKey = 'biz_reports'
    const entitlements = await stripe.entitlements.activeEntitlements.list({
        customer: 'cus_xxxxA'
    })
    const paidPostFeature = entitlements.data.find(ent => {
        return ent.lookup_key === requiredKey
    })
    if (!paidPostFeature) {
        const { data: features } = await stripe.entitlements.features.list({
            lookup_key: requiredKey
        })
        c.status(429)
        return c.json({
            message: `このページにアクセスするには、「${features[0].name}」権限が必要です。プランをアップグレードしてください。`
        })
    }
    return c.text("Welcome to paid post page!")
})

Step6: サブスクリプションを解約して、アクセス権限を喪失することを確認する

最後に付与したアクセス権限を、解約やダウングレードで喪失できるかを確認しましょう。ダッシュボードでサブスクリプションを解約操作してください。

スクリーンショット 2024-05-21 15.43.33.png

解約処理が成功したのを確認してから、再びその顧客に付与されたアクセス権限の一覧を取得しましょう。

stripe active_entitlements list \
--customer="cus_から始まる顧客ID" 

他にサブスクリプションを契約していない場合、レスポンスが空の配列に変わります。

スクリーンショット 2024-05-21 15.45.15.png

これによって、プラン変更時に起こるアクセス権限の変化にも、Stripe内のデータを参照するだけで対応できるようになります。

[Advanced Tips] バックエンドで権限変更のワークフローを動かす方法

インフラの構成変更やシステムの設定変更など、サービスによっては権限の喪失や付与に連動したワークフローを実行することがあります。このような権限の変化についても、StripeのWebhookイベントを利用することで、シームレスに連携できます。

プランの変更や解約などに伴う権限の変化に対応するには、新しく追加されたentitlements.active_entitlement_summary.updatedイベントを利用します。このイベントには、「対象の顧客ID」や「変更前と現在の権限設定」などの情報が含まれています。

{
  "object": {
    "object": "entitlements.active_entitlement_summary",
    "customer": "cus_OYXmEvKfYDp7DA",
    "entitlements": {
      "object": "list",
      "data": [],
      "has_more": false,
      "url": "/v1/customer/cus_OYXmEvKfYDp7DA/entitlements"
    },
    "livemode": false
  },
  "previous_attributes": {
    "entitlements": {
      "data": [
        {
          "id": "ent_test_61QSA7cL7mjHYxePl41IDF6qBhttt65Y",
          "object": "entitlements.active_entitlement",
          "feature": "feat_test_61QS9o4tAnK9ATPJX41IDF6qBhttt7Cq",
          "livemode": false,
          "lookup_key": "paid_posts"
        },
        {
          "id": "ent_test_61QSA7cYW9h6XG8zt41IDF6qBhttt27s",
          "object": "entitlements.active_entitlement",
          "feature": "feat_test_61QS9nd2kxnCe1ksR41IDF6qBhttt6Ui",
          "livemode": false,
          "lookup_key": "free_posts"
        }
      ]
    }
  }
}

このデータを利用することで、「previous_attributesにしかない権限がある場合、それに関連したリソースやDBを変更するワークフローを実行する」といった設定ができます。

まとめ

新しく発表されたEntitlement APIを利用することで、プランごとにユーザーへ付与するアクセス権限の管理についてもStripeで管理できるようになります。すでに権限管理をIDPサービスや独自のDBで管理している場合でも、Webhookイベントを利用することで権限の付与や喪失をリアルタイムで反映させることが可能です。

新しいサービスのローンチとPMFをより高速に実現させるため、ぜひサブスクリプションにStripeをご利用ください。

Document:

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0