Stripe を使って SaaS の価格改定を短期間で実現する方法

国際的な経済環境やインフレ傾向、さらに為替円安の進行など、SaaS ビジネスにおける固定費用の値上がりが各所で相次いでいます。そのため、多くの SaaS で価格改定は避けて通れない課題となっています。当社で提供するサービス Amimoto においても、サービスの持続的な提供のため、価格改定の実施を決定しました。

本記事では、実際に Stripe を活用して価格改定を実装した経験をもとに、既存顧客への影響を最小限に抑えながら、段階的な価格改定を実現した方法を詳しく解説します。

価格改定における 3 つの選択肢

現在提供しているサービスの料金を変更する際、事業者は 3 つの方法を選べます。

それぞれの特徴やメリット・デメリットを簡単に確認してみましょう。

レガシープラン方式: 既存の契約を維持する方法

最も開発作業や顧客コミュニケーションのコストを低くできる方法が、このレガシープラン方式です。この方式では、すでに契約中の顧客については価格改定を行いません。Stripe 上で新しい商品または料金を作成し、価格改定の実施後は新しい料金を利用してサブスクリプションを作成するように実装します。価格改定における実装や事前準備が大変と言われる理由の1つが既存顧客・契約への対応やコミュニケーションであるため、短期間かつ少ない準備や工数で済ませる必要がある場合に選ばれることが多い方法です。

この方法のメリットは作業内容のシンプルさですが、一方で複数の契約・料金プランが同時並行で提供されることによる複雑さをもたらします。サービスが提供する機能と料金プランのマッピングは提供中の全てのプランに対して実施する必要があります。また、カスタマーサクセスチームやサポートチームなどが顧客にアップセルやクロスセルを提案する場合に、旧プランか新プランかの確認や対応するプランの確認作業などが発生します。

そしてこの方式における最大の問題は、価格改定による売り上げ増加効果が非常に限定的となることです。新規顧客やプラン変更でのみ新しい価格での売り上げに変わるため、現在の顧客から発生する売り上げはほとんど変化しません。そのため、調達元の価格改定や為替の影響などによるコストプッシュ型の価格改定を意図している場合には、おすすめできません。

追加料金方式: 将来的な再調整に備える方法

2つ目の方法では、サブスクリプションの項目を、本体の価格と値上げになる部分の価格に分割します。この場合、値上げとなる分の金額は「サービス調整費」や「サーチャージ」といった名前の料金または商品となります。この方法のメリットは、サービス本体の価格を維持することができることです。サービスや商品を提供する上で利用するプロダクトや原材料の価格が中短期間で変動しやすい場合や、動的に金額を変更させたい場合、クッションとなる価格だけを調整することで変更を迅速に展開できるようになります。

一方、サブスクリプションの数量が1つから2つに変わることにより、 API 組み込みや Stripe の機能の使い方が変わってしまうことがある点には注意が必要です。例えば Stripe のカスタマーポータルは複数の商品を契約しているサブスクリプションや従量課金プランを含むサブスクリプションのプラン変更が実行できません。そのため、カスタマーポータルを利用して顧客向けのマイページを提供している場合は、プラン変更フローだけ別途開発が必要となります。カスタマーポータルの制限事項詳細については Stripe のドキュメントをご確認ください。

また、全顧客のサブスクリプションを更新するバッチ処理が必要となります。更新日を固定するか、次回の契約サイクルからにするかによっても実装方法が異なりますので、既存顧客の価格改定に関するスケジュールは事前にきっちり調整しておきましょう。

本体価格変更方式: シンプルかつ不可逆な変更方法

最後の方法は、現在利用している商品・料金を新しいものに変更する方法です。この場合、一般的なプラン変更フローを同じような処理フローで新しい価格に移行することができます。そのため設計や実装プランが比較的シンプルにできるメリットがあります。

ただし、この方法の場合、一度価格を変更すると元に戻すことが困難になります。また、全顧客のサブスクリプションを更新するバッチ処理が必要となります。更新日を固定するか、次回の契約サイクルからにするかによっても実装方法が異なりますので、既存顧客の価格改定に関するスケジュールは事前にきっちり調整しておきましょう。

Amimoto では「追加料金方式」を採用

デジタルキューブでは、2025年3月の価格改定において追加料金方式を選択しました。これは価格改定の主たる理由に為替レート等の外部要因が含まれることもあります。カスタマーポータルの機能制限がある方式ではありますが、Amimoto ではサブスクリプション管理や請求履歴表示をアプリケーション内に独自実装していました。そのため、 Stripe 側の仕様による影響を受けにくい作りになっていたことも要因として挙げることができます。

価格改定における3つの作業

Amimoto における価格改定に関する開発作業は、大きく分けて 3 つのステップがありました。まずは将来的な価格変更に備えた「価格のコード化作業」、そして「追加料金方式によるサブスクリプション管理機能のアップデート」、最後に「既存顧客の契約更新」です。

Step1: Terraform による料金プラン管理基盤の構築

サービス維持調整費は今後も変動する可能性があることを考慮し、効率的なプラン管理が必要でした。そこで、Infrastructure as Code の考え方を料金プラン管理にも適用することにしました。

まず、既存の Stripe プランを Terraform で管理できるようにする作業から始めます。 Terraform で Stripe のリソースを管理できる Provider を導入し、商品・価格を .tf ファイルで定義します。その後、 `terraform import` コマンドを利用して現在 Stripe 上にあるデータを取り込みました。

# 既存プランのimport例
terraform import stripe_product.basic_plan prod_xxxxxxxxxxxxx
terraform import stripe_price.basic_plan_monthly price_xxxxxxxxxxxxx

既存のプランを terraform import で取り込み、terraform plan で変更が発生しない状態まで調整を繰り返します。その後、追加料金分のデータについても Terraform に定義を追加しました。

resource "stripe_price" "basic_plan_adjustment_fee" {
  product     = stripe_product.adjustment_fee.id
  unit_amount = 500
  currency    = "jpy"
  recurring {
    interval = "month"
  }
  lookup_key = "basic_plan_adjustment_fee"
  metadata = {
    base_price_lookup_key = "basic_plan_monthly"
  }
}

lookup_key と metadata を使って、メインプランと調整費の紐付けを定義しています。この設計が後の自動化処理で重要な役割を果たします。また、Terraform の Stage 機能を活用することで、テスト環境と本番環境それぞれでのステート管理なども実現させています。

Step2: 追加料金方式によるサブスクリプション管理機能のアップデート

商品・料金データの登録が完了したので、次はアプリケーションコードを更新します。アプリケーション側の変更は最小限に抑えることを目指しました。実装した変更点は以下の4つです。

  1. Subscription create/update での自動追加処理
  2. 料金表示 API での合計金額計算
  3. 申し込み画面での金額表示改善
  4. マイページでの料金内訳表示

サブスクリプションを作成する時の処理例を示します。

// 料金検索の実装
async function findAdjustmentFee(basePriceLookupKey) {
  const prices = await stripe.prices.list({
    lookup_keys: [`${basePriceLookupKey}_adjustment_fee`],
    active: true,
  });
  
  if (prices.data.length === 0) {
    // 調整費が設定されていないプランの場合
    return null;
  }
  
  return prices.data[0];
}

// subscription作成時の処理
async function createSubscription(customerId, basePriceId) {
  const items = [{ price: basePriceId }];
  
  // 基本料金の情報を取得
  const basePrice = await stripe.prices.retrieve(basePriceId);
  
  // JPY建てプランの場合のみ調整費を追加
  if (basePrice.currency === 'jpy') {
    const adjustmentFee = await findAdjustmentFee(basePrice.lookup_key);
    if (adjustmentFee) {
      items.push({ price: adjustmentFee.id });
    }
  }
  
  return await stripe.subscriptions.create({
    customer: customerId,
    items: items,
  });
}

フロントエンドチームの負荷を下げるため、合計金額の計算は API 側で行うようにしました。実装済みのフィルター関数を再利用できたことも、この判断を後押ししました。

lookup_keysとmetadataで料金をマッピング

メインプランとサービス維持調整費の紐付け・自動割り当てには、lookup_keysmetadataを活用しました。まず調整費の lookup_key{基本プランのlookup_key}_adjustment_fee 形式で命名しています。そして追加料金となる料金の metadata には、対応する基本プランの料金に設定された lookup_key を保存しています。

このように設計することで、システム側の処理系統を可能な限りシンプルかつ将来のプラン変更に耐えられる構造でアップデートすることができました。

また、申し込み時の料金表や最終確認画面に合計金額を表示する処理においても、同様のマッピング処理を利用しています。これによって合計金額や調整費についても、現行の API から取得できるようになり、フロントエンドアプリケーション側の変更箇所を最小限に抑えています。

Step3: 既存顧客の契約更新

価格改定においてより慎重に準備や実装を行う必要がある部分は、既存顧客の契約を更新する仕組みです。今回の価格改定では、改定を行った日以降の契約更新タイミングで新価格に切り替わることが決まっていました。そのため「ある特定の日に一括でサブスクリプションを更新する」のではなく、「現在のサイクルが終わったタイミングで、プランを変更する」仕組みが必要となります。

このような特定のサイクルに応じて契約内容を変更する仕組みを実装するには、Stripe の Subscription Schedule API を使います。この API を利用することで、既存のサブスクリプションや新しいサブスクリプションの契約スケジュールを設定することができます。

const schedulePhase = await stripe.subscriptionSchedules.create({
   from_subscription: subscription.id,
});
await stripe.subscriptionSchedules.update(schedulePhase.id, {
  end_behavior: 'release',
  phases: [
    {
      items: currentItems,
      iterations: 1, // 現在のサイクルまで
    },
    {
      items: [...currentItems, { price: adjustmentFeeId }],
      // 次のサイクルから調整費を追加
    }
  ],
  metadata: {
    company_planned: "true",
    plan_type: 'price_adjustment_application',
  }
});

metadata に plan_type: 'price_adjustment_application' を設定することで、価格改定用の schedule であることを識別できるようにしました。

Subscription Schedule を価格改定で利用する時の注意点

サブスクリプションを更新する際、Subscription Schedule API の使い方には少し注意が必要です。1つ目はスケジュールの作成を create と update の 2 段階で実施する必要があることです。既存のサブスクリプションからスケジュールを作成する場合に利用する from_subscription パラメーターと、実際の更新スケジュールを設定する pharses  パラメーターを併用することができませんので、必ず 2 ステップにわけた実装にしましょう。

また、 tax やトライアルなど、サブスクリプションの items に設定されている値をできるだけ明示的に pharses へ引き継ぐ必要があることにも注意が必要です。テストフェーズにおいて、消費税に関するパラメータの設定を忘れてしまい、バッチにてスケジュールを設定したサブスクリプション全てにおいて、消費税を徴収しない状態になる問題が見つかりました。実際の作業時にはパラメータの設定を再確認し、念の為の更新したサブスクリプションの内容を目視で確認するなどの対応を実施しています。

最後に、重要なポイントとして、「スケジュールによる価格改定が実施される前に、顧客がプランを変更した場合」のテストケースを要件に含めるようにしましょう。これは Subscription Update API によるプラン更新を行う場合、事前に作成した Subscription Schedule を明示的に取り消す必要がある為です。Subscription Schedule は、 Subscription API によるプランの更新などの影響を受けません。そのため、設定した価格改定スケジュールが完了して新しい料金になる前に、ユーザーが別のプランに契約を変更した場合、スケジュールされていた年月日になった時点でプラン変更前の価格に巻き戻されてしまいます。これを回避するため、 Stripe Webhook でサブスクリプションの更新イベントを監視し、更新されたサブスクリプションに価格改定等で設定されたスケジュールがないかをチェックする必要があります。もしスケジュールが存在する場合は、 Subscription Schedule Release API を呼び出してスケジュールを解放しましょう。

// Webhookでの自動release処理
async function handleSubscriptionUpdate(event) {
  const subscription = event.data.object;
  const previousAttributes = event.data.previous_attributes;
  
  if (isPlanChanged(subscription, previousAttributes)) {
    if (subscription.schedule) {
      const schedule = await stripe.subscriptionSchedules.retrieve(
        subscription.schedule
      );
      
      if (isTargetSchedule(schedule)) {
        await stripe.subscriptionSchedules.release(schedule.id);
      }
    }
  }
}

この時、Release ではなく Cancel の API を利用すると、サブスクリプションごとキャンセルされてしまいます。必ず Release する API を利用しましょう。

AI による開発とテストの効率化

今回の実装では、Cursor と Stripe Documentation MCP を積極的に活用しました。これにより、API とスクリプト処理系の実装を実稼働2週間以下で完了できました。特に Stripe API の仕様確認やサンプルコードの生成において、大幅な時間短縮を実現できました。複雑な subscription schedule API の仕様も、MCP を通じて効率的に理解できたのは大きかったです。

また、 Stripe のダッシュボードに搭載されているデバッグツール( Stripe ワークベンチ )を事前調査や実装テストでは最大限活用しました。ワークベンチを利用することで、 API リクエスト内容やレスポンス、関連するリソースなどを1画面でまとめてチェックすることができ、トラブルが起きた時のリカバリーなども簡単に行えました。

この他、 Stripe のテストクロックを利用した時間のシミュレーションやテストデータの一括作成・削除などをまとめて行える MCP サーバーを個人開発しています。

これによって API や CLI 、ダッシュボードなどを行ったり来たりするのではなく、「テストクロックとテスト顧客データを 6 件作って」や「テストクロックの時間を1ヶ月進めておいて」のようにチャットベースで Stripe 上のデータ操作やシミュレーションが実施できました。

まとめ

サービスの価格改定において、どのようなモデルや切り替え方式を選ぶかは技術的な制約だけでなく、ビジネス的なゴールにも影響を与えます。そのため、それぞれの方法が持つメリット・デメリットを理解することが、価格改定によるビジネスゴールを達成するための第一歩です。

また、 Stripe のようにサブスクリプション管理やテストのための API / ツールが豊富なサービスを利用することも、スムーズな価格改定を実現する上で重要といえるでしょう。今回1ヶ月たらずという短いスケジュールかつ、アプリケーションの保守管理などの並列作業を処理しながらも大きなトラブルを起こさずに価格改定を実現できたことは、 Stripe のような高機能なサービスを活用した恩恵のおかげともいえます。もちろん生成 AI や AI コーディングツールの活用も大きな効率化要素でした。これもドキュメントを検索する MCP サーバーが公式から提供されていたことや、各生成 AI サービスがそもそも Stripe に詳しかったこともあるといえます。

価格改定は避けて通れない課題ですが、技術的な工夫により顧客体験を損なうことなく実現できることを示せたのではないでしょうか。同様の課題に直面している方の参考になれば幸いです。

Stripe を活用したオンライン決済システム導入をサポートします

株式会社デジタルキューブは Stripe 公式パートナーとして、自社サービス開発で培った経験を活かし、Stripe を用いた決済システムの導入を支援します。多言語対応の決済フォーム実装、モバイル支払い対応、柔軟な従量課金システム構築など、ユースケースに合わせた活用方法の提案から、専用ダッシュボードの開発まで幅広くサポートします。

SaaS ダッシュボード開発や EC サイトへの Stripe 決済導入など、様々な導入実績があります。 API の呼び出しだけで決済機能を実装できる Stripe の利点を最大限に活かしたシステム構築をお手伝いします。

参考資料


Recommend Articles

おすすめの記事