Stripeを使った生成AIチャットなどの従量課金で、「お試しクレジット」をユーザーへ付与する方法

この記事では、従量課金タイプのサブスクリプションサービスを提供する際に、ユーザーがサービスをお試しするためのクレジットを付与する方法を紹介します。日数ベースのトライアルとは異なるアプローチでの、サービス体験オファーの作り方を、この記事の内容で学ぶことができます。

## なぜトライアルではなくクレジットなのか

Stripeのようなサブスクリプションの請求管理サービスには、通常トライアル機能が用意されています。この機能を使うことで、ユーザーが事前に支払いをすることなく、サービスを試すことができます。しかし次のような性質を持つサービスの場合、日数ベースとなるトライアルとの相性が良くないこともあります。

- AIチャットサービスのように、トライアル期間にリソースを集中して利用できる場合
- 全く新しい機能のため、ユーザーがどれくらい利用するか予想しにくく、コスト計算が困難な場合

このようなケースでは、従量課金で利用できるクレジットを顧客に付与することで、想定外の利用によるコストの増加や、売上の逸失を予防することができます。

## Stripeで従量課金のクレジットを付与する方法

Stripeの従量課金サブスクリプションを利用する場合、顧客へ事前にクレジットを付与する仕組みを作ることができます。この機能を試すには、[サンドボックス機能](https://docs.stripe.com/sandboxes?locale=ja-JP)
を有効化する必要があります。**従来のテスト環境では、一部APIが動作しません**ので、ご注意ください。

https://docs.stripe.com/sandboxes?locale=ja-JP

### 従量課金のサブスクリプション料金体系を作成する

まずサブスクリプション契約に利用する料金モデルと、利用量を計測するためのメーターを作成します。もし「月額2.000円の基本料金 + 従量課金」のようなモデルを検討している場合は、料金を作成する際に`tiers`パラメータを利用して料金設定を行いましょう。


![スクリーンショット 2024-10-28 11.02.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/2ca126bf-7b0d-7203-9308-39b984a33e0e.png)


```js
const meter = await stripe.billing.meters.create({
  display_name: 'Alpaca AI tokens',
  event_name: 'alpaca_ai_tokens',
  default_aggregation: {
    formula: 'sum',
  },
  customer_mapping: {
    event_payload_key: 'stripe_customer_id',
    type: 'by_id',
  },
  value_settings: {
    event_payload_key: 'value',
  },
});
const price = await stripe.prices.create({
  currency: 'jpy',
  billing_scheme: 'tiered',
  tiers: [{
    flat_amount: 2000,
    up_to: 2000
  }, {
    unit_amount: 10,
    up_to: 'inf'
  }],
  tiers_mode: 'graduated',
  recurring: {
    usage_type: 'metered',
    interval: 'month',
    meter: meter.id,
  },
  product_data: {
    name: 'Alpaca AI tokens',
  },
})
```

作成に成功すると、ダッシュボードからも料金モデルや関連づけられたメーターの情報が確認できるようになります。


![スクリーンショット 2024-10-28 11.04.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/ef5c0646-91b8-e59c-0beb-faee3dfbb802.png)


### サブスクリプションを作成する

料金モデルの作成が完了したら、サブスクリプションを作成しましょう。この際のAPIリクエスト内容は、通常の料金体系とほぼ同じです。`quantity`の設定を行いませんので、通常の料金モデルと従量課金両方のサブスクリプション申し込み処理を作成する場合は、この点に注意しましょう。

```js
const subscription = await stripe.subscriptions.create({
    customer: customerId,
    items: [{
        price: 'price_xxx'
    }],
})
```

### 顧客のサブスクリプションにクレジットを付与する

作成したサブスクリプションに、サービスを試すためのクレジットを付与しましょう。[Credit Grants API](https://docs.stripe.com/api/billing/credit-grant/create)を利用することで、対象の顧客に対するクレジット付与処理を実行できます。次のコードでは、1,000円のクレジットを付与しています。

```js
const creditGrant = await stripe.billing.creditGrants.create({
    customer: customerId,
    applicability_config: {
        scope: {
            price_type: 'metered'
        }
    },
    category: 'paid',
    amount: {
        type: 'monetary',
        monetary: {
            value: 1000,
            currency: 'jpy'
        }
    }
})
```

実行に成功すると、次のようなAPIレスポンスが取得できます。[List credit grants API](https://docs.stripe.com/api/billing/credit-grant/list)を使うことで、Customerごとのクレジット付与履歴を取得することもできます。

```json
{
  "id": "credgr_test_61RO61wuFP6QABvzf41IDF6qBhtttEJc",
  "object": "billing.credit_grant",
  "amount": {
    "monetary": {
      "currency": "jpy",
      "value": 1000
    },
    "type": "monetary"
  },
  "applicability_config": {
    "scope": {
      "price_type": "metered"
    }
  },
  "category": "paid",
  "created": 1730080128,
  "customer": "cus_R6vkg6977e7UwT",
  "effective_at": 1730080128,
  "expires_at": null,
  "livemode": false,
  "metadata": {},
  "name": "",
  "test_clock": null,
  "updated": 1730080128,
  "voided_at": null
}
```

ダッシュボードの顧客ページにも、付与の履歴は確認できます。顧客サポート等には、まずダッシュボードの機能を使うことをお勧めします。

![スクリーンショット 2024-10-28 10.50.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/814ce5d2-dd3d-f5f5-b3e6-90415066a9ee.png)

### 利用量を登録する

クレジットの付与が成功すれば、あとは生成AIチャットなどのリソース利用量をStripeに登録するだけです。[Meter Events (v2)](https://docs.stripe.com/api/v2/billing/meter-event/create)を利用することで、Streamレスポンスを処理する中やイベントStreamなどの非同期的な処理内でもリアルタイムに利用量を登録できます。

```js
const meterEvent = await stripe.v2.billing.meterEvents.create({
    event_name: 'alpaca_ai_tokens',
    payload: {
        value: '4001',
        stripe_customer_id: customerId
    }
})
```

利用量の登録に成功すれば、サブスクリプションの次回請求内容が次のスクリーンショットのようになります。料金モデルと利用量に基づいた請求内容から、事前に付与したクレジット分の料金が差し引きされていることがわかります。

![スクリーンショット 2024-10-28 11.13.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/b8f2c2ac-9215-0c3a-bc5f-cdfb8c428e2d.png)

## トラブルシューティング
### `Error: Invalid Stripe API version`: Stripe APIバージョンの互換性エラー

[Meter Events (v2)](https://docs.stripe.com/api/v2/billing/meter-event/create) APIは利用しているStripe APIのバージョンが古いと動作しません。次のようなエラーレスポンスを取得した場合は、SDKが利用するStripe APIのバージョンを`2024-09-30.acacia`よりも新しいバージョンに変更しましょう。

```bash
Trace: Error: Invalid Stripe API version: 2024-04-10. Learn more at https://stripe.com/docs/api-v2-overview#sdk-and-api-versioning
```

```diff_javascript
const stripe = new Stripe(STRIPE_SECRET_API_KEY, {
-  apiVersion: '2024-04-10'
+  apiVersion: '2024-09-30.acacia'
})
```

https://stripe.com/docs/api-v2-overview#sdk-and-api-versioning


### `Error: Livemode of key does not match mode of account`: サンドボックスを利用していないことによるエラー

もし[サンドボックス機能](https://docs.stripe.com/sandboxes?locale=ja-JP)を利用していない場合、このAPIリクエストが次のようなエラーになります。このAPIエラーが表示された場合は、サンドボックスアカウントに切り替えて作業をやり直す必要があります。

```bash
Trace: Error: Livemode of key does not match mode of account (hint: legacy testmode keys are not supported. Please use a sandbox.)
```


## 顧客へのクレジット付与タイミングはいつにすべきか？

サービスを試してもらうためのクレジット付与タイミングは、Stripeやアプリケーションのイベントに合わせてさまざまなタイミングでトリガーできます。例えばユーザーアカウントを作成した直後に付与したい場合は、ユーザーアカウントの作成が完了した際にAPIを呼び出すことで付与できます。もしくはOkta CIC( Auth0 )やfirebase / Supabase / Amazon CognitoなどのWebhookイベント / トリガーで呼び出す方法であれば、非同期に処理することも可能です。

- ユーザーアカウント情報を使ってStripe Customerを作成
- ユーザーアカウントのDBにStripe Customer IDを保存
- クレジットを付与

この方法の場合、ユーザーがクレジットカード情報を登録する前にある程度サービスを試すことができるようになります。ただしユーザーが支払い情報を登録する前から使いすぎないようにするため、アラートを設定するなどの予防策を設定する方が安全でしょう。Stripeの[Alert API](https://docs.stripe.com/api/billing/alert/create)を使うと、設定した金額に到達したタイミングでWebhookイベント（`billing.alert.triggered`）をトリガーできます。

```js

const alert = await stripe.billing.alerts.create({
  title: 'Sample alert',
  alert_type: 'usage_threshold',
  usage_threshold: {
    filters: [
      {
        type: 'customer',
        customer: '{{CUSTOMER_ID}}',
      },
    ],
    meter: 'mtr_1234',
    gte: 100,
    recurrence: 'one_time',
  },
});
```

その他にも、ユーザーがクレジットカード情報を登録したタイミングで付与したい場合は、`payment_method.attached`イベントが使えます。サブスクリプションの申し込みを明示的に行なった際に付与するには、`customer.subscription.created`イベントを使うこともお勧めします。このようにして提供予定のサービスのユースケースや支払いサイクルに合わせたフローを実現することができます。

## まとめ

Stripeの従量課金APIを利用することで、日数ベースのトライアルやクーポン以外の方法でサービスのお試しオファーを出すことができます。Stripe Webhook / Event Destinationと組み合わせることで、ユーザーが自然なフローでサービスを試すことが可能になり、さらに必要以上のコスト支出が発生しないようにすることもできます。

クレジット機能は、「**特定の商品またはサービスを販売する**」または「**プロダクト/サービスのメンバーシップを提供する**」ユースケースを想定して提供されています。そのため、以下の用途で利用することはできません。この点についてはあらかじめご了承ください。

:::note warn
**以下の目的には使用しない**でください。

- ギフトカードを販売する
- プリペイド型電子マネーを顧客に提供する
- ウォレット機能を提供する
- サードパーティーの商品またはサービスを購入できるようにする
:::

## ドキュメント


https://docs.stripe.com/billing/subscriptions/usage-based/billing-credits

https://docs.stripe.com/billing/subscriptions/usage-based/billing-credits/implementation-guide?dashboard-or-api=api#fund-the-credit-grant