# 請求する使用量を API で記録する Stripe API を使用して使用量を記録する方法をご紹介します。 Stripe で使用量を記録して、各請求期間の正しい金額を顧客に請求します。使用量を記録するには、まず[メーターを設定](https://docs.stripe.com/billing/subscriptions/usage-based/meters/configure.md)してから、メーターイベント (メーターに設定されているイベント名、顧客 ID、数値、タイムスタンプ (オプション)) を送信します。 Stripe に使用量を記録する頻度を、発生ごと、一括などで決定できます。Stripe は従量イベントを非同期に処理するため、集計された使用量は従量イベントのサマリーに集約され、次回の請求書には、最近受信した従量イベントが即時に反映されない可能性があります。 ## メーターイベントを作成する API を使用して [Meter Event](https://docs.stripe.com/api/billing/meter-event/create.md) (メーターイベント) を作成します。 ```curl curl https://api.stripe.com/v1/billing/meter_events \ -u "<>:" \ -d event_name=hypernian_tokens \ -d "payload[value]=25" \ -d "payload[stripe_customer_id]={{CUSTOMER_ID}}" ``` ### べき等 遅延やその他の問題により各イベントが重複して報告されることを防ぐには、[Idempotency Key (べき等キー)](https://docs.stripe.com/api/idempotent_requests.md) を使用します。従量イベントはすべて [ID](https://docs.stripe.com/api/billing/meter-event/create.md#create_billing_meter_event-identifier) に対応しており、リクエストで ID を指定できます。指定しなかった場合、ID は自動生成されます。 ### イベントのタイムスタンプ タイムスタンプは、必ず 35 日前から、5 分後までの範囲で指定してください (5 分間の猶予は、サーバーと Stripe のシステム間のクロックドリフトのために設けられています)。 ### 使用量の値 ペイロードの使用量の数値は、整数値のみを受け付けます。サイクル全体の使用量がマイナスの場合、Stripe では請求書のラインアイテムの使用数量を 0 として申告します。 ### レート制限 [メーターイベント](https://docs.stripe.com/api/billing/meter-event/create.md) エンドポイントでは、本番環境で 1 秒あたり 1,000 コールが許可されます。この上限を超えると予想される場合は、以下の 2 つのオプションがあります。 - Stripe に送信する前に、使用データを事前集計します。たとえば、個々のアクションごとにイベントを送信する代わりに、複数のアクションで使用量を累積し、1 つの集計イベントを定期的に送信できます。これにより、API コールの数を減らしながら、使用量全体を正確に報告できます。 - 大量のデータを扱う場合は、メーターイベントストリームで高スループットの取り込み方法を使用します。 サンドボックス環境で行われる `meter event` および `meter event stream` エンドポイントの呼び出しは、[基本制限](https://docs.stripe.com/rate-limits.md#rate-limiter)にカウントされます。 > `Stripe-Account` ヘッダーを使用して連結アカウントの代理でリクエストを行う Connect プラットフォームの場合、1 秒あたり 100 回の操作を規制値とする[通常の Stripe レート制限](https://docs.stripe.com/rate-limits.md)の対象となります。 `429` ステータスコードを監視し、指数バックオフスケジュールを使用した再試行メカニズムを実装して、リクエスト量を管理できます。 ### レート制限の引き上げによる高速処理の取り込み (API v2) [API v2](https://docs.stripe.com/api-v2-overview.md) では、メーターイベントストリームを使用して、毎秒最大 10,000 件のイベントを Stripe に送信できます。これは本番環境でのみ機能します。 毎秒 20 万件のイベントを処理する必要がある場合は、[営業にお問い合わせ](https://stripe.com/contact/sales) ください。 このエンドポイントはステートレス認証セッションを使用します。まず、[Meter Event Session](https://docs.stripe.com/api/v2/billing/meter-event-sessions/create.md) を作成して認証トークンを受け取ります。認証トークンは 15 分間のみ有効であるため、トークンの有効期限が切れ次第、新しい従量イベントセッションを作成する必要があります。 次に、返された認証トークンを使用して、[メーターイベントストリーム](https://docs.stripe.com/api/v2/billing/meter-event-stream/create.md)を指定して高スループットのメーターイベントを作成します。 > API リクエストは大量に発生するため、従量イベントストリームのリクエストは [Workbench のログタブ](https://docs.stripe.com/workbench/overview.md#request-logs)には含まれません。 `429` ステータスコードを監視し、指数バックオフスケジュールを使用した再試行メカニズムを実装して、リクエスト量を管理できます。 #### Ruby ```ruby require 'stripe' require 'date' class MeterEventManager attr_accessor :api_key attr_accessor :meter_event_session def initialize(api_key) @api_key = api_key @meter_event_session = nil end def refresh_meter_event_session if @meter_event_session.nil? || DateTime.parse(@meter_event_session.expires_at) <= DateTime.now # Create a new meter event session in case the existing session expired client = Stripe::StripeClient.new(api_key) @meter_event_session = client.v2.billing.meter_event_session.create end end def send_meter_event(meter_event) # Refresh the meter event session if necessary refresh_meter_event_session # Create a meter event with the current session's authentication token client = Stripe::StripeClient.new(meter_event_session.authentication_token) client.v2.billing.meter_event_stream.create( events: [meter_event] ) end end # Send meter events api_key = "{{API_KEY}}" customer_id = "{{CUSTOMER_ID}}" manager = MeterEventManager.new(api_key) manager.send_meter_event( { event_name: 'hypernian_tokens', payload: { "stripe_customer_id" => customer_id, "value" => '25' } } ) ``` ## メーターイベントエラーを処理する Stripe は、メーターイベントを非同期的に処理します。エラーが見つかった場合は、次のいずれかの [Event](https://docs.stripe.com/api/events.md) (イベント) を作成します。 | イベント | 説明 | ペイロードタイプ | | ----------------------------------------- | ------------------------------------------------- | -------- | | `v1.billing.meter.error_report_triggered` | このイベントは、従量に無効な使用量イベントが含まれているときに発生します。 | `thin` | | `v1.billing.meter.no_meter_found` | このイベントは、使用量イベントが不足していたり、無効な従量 ID が含まれているときに発生します。 | `thin` | > thin イベントに登録するイベントの送信先を作成するには、[開発者向け設定](https://dashboard.stripe.com/settings/developers)でワークベンチを有効にします。 ### サンプルのペイロード #### エラーレポートイベントの例 以下は、`v1.billing.meter.error_report_triggered` イベントのペイロードの例です。 ```json { "id": "evt_test_65R2GpwDsnmpzihMjdT16R2GDhI4SQdXJGRbvn7JA8mPEm", "object": "v2.core.event", "created": "2024-08-28T20:54:12.051Z", "data": { "developer_message_summary": "There is 1 invalid event", "reason": { "error_count": 1, "error_types": [ { "code": "meter_event_no_customer_defined", "error_count": 1, "sample_errors": [ { "error_message": "Customer mapping key stripe_customer_id not found in payload.", "request": { "id": "", "idempotency_key": "37c741d8-1f7e-4adc-af16-afdca1d73b37" } } ] } ] }, "validation_end": "2024-08-28T20:54:10.000Z", "validation_start": "2024-08-28T20:54:00.000Z" }, "reason": null, "related_object": { "id": "mtr_test_61R2GlpFXJ4R3L5DN41Fb82guyGVEUmO", "type": "billing.meter", "url": "/v1/billing/meters/mtr_test_61R2GlpFXJ4R3L5DN41Fb82guyGVEUmO" }, "type": "v1.billing.meter.error_report_triggered" } ``` #### 正しくない従量のエラーイベントの例 以下は、`v1.billing.meter.no_meter_found` イベントのペイロードの例です。 ```json { "created": "2024-10-01T20:42:52.203Z", "id": "evt_test_61REarcdWIsXleUiz16REahOMTSQbAhSD0fdnF9JAUdk", "object": "v2.core.event", "context": null, "type": "v1.billing.meter.no_meter_found", "data": { "developer_message_summary": "There is 1 invalid event", "reason": { "error_count": 1, "error_types": [ { "code": "no_meter", "error_count": 1, "sample_errors": [ { "error_message": "No meter was found matching event_name d2aa8cb3-3f00-44a4-b98f-3fbd1d0e93b1.", "request": { "identifier": "df5d4002-515b-4090-8fe2-a1b1f6f5b945" } } ] } ] }, "validation_end": "2024-10-01T20:42:50.000Z", "validation_start": "2024-10-01T20:42:40.000Z" }, "livemode": false, "reason": null, "related_object": {} } ``` ### エラーコード `reason.error_types.code` はエラーを引き起こしたエラーカテゴリーを示します。発生する可能性のあるエラーコードは次のとおりです。 - `meter_event_customer_not_found` - `meter_event_no_customer_defined` - `meter_event_dimension_count_too_high` - `archived_meter` - `timestamp_too_far_in_past` - `timestamp_in_future` - `meter_event_value_not_found` - `meter_event_invalid_value` - `no_meter` (`v1.billing.meter.no_meter_found` イベントタイプでのみサポートされています) ### イベントのリッスン [Webhook エンドポイントまたは別のタイプのイベント送信先](https://docs.stripe.com/event-destinations.md)を設定することで、イベントをリッスンできます。 1. Workbench の [Webhook](https://dashboard.stripe.com/webhooks) タブで**新しい送信先の作成**をクリックします。または、この[テンプレート](https://dashboard.stripe.com/webhooks/create?payload_style=thin&events=v1.billing.meter.error_report_triggered%2Cv1.billing.meter.no_meter_found)を使用して、2 つのイベントタイプを事前に選択した状態で Workbench で新しい送信先を設定します。 1. **Show Advanced Settings (詳細設定を表示)** をクリックして、**Thin** ペイロードスタイルを選択します。 1. イベントのリストから `v1.billing.meter.error_report_triggered` と `v1.billing.meter.no_meter_found` を選択します。 1. イベントを処理するハンドラを作成します。 #### Python ```python import os from stripe import StripeClient from stripe.events import V1BillingMeterErrorReportTriggeredEvent from flask import Flask, request, jsonify app = Flask(__name__) api_key = os.environ.get('STRIPE_API_KEY') webhook_secret = os.environ.get('WEBHOOK_SECRET') client = StripeClient(api_key) @app.route('/webhook', methods=['POST']) def webhook(): webhook_body = request.data sig_header = request.headers.get('Stripe-Signature') try: thin_event = client.parse_thin_event(webhook_body, sig_header, webhook_secret) # Fetch the event data to understand the failure event = client.v2.core.events.retrieve(thin_event.id) if isinstance(event, V1BillingMeterErrorReportTriggeredEvent): meter = event.fetch_related_object() meter_id = meter.id # Record the failures and alert your team # Add your logic here return jsonify(success=True), 200 except Exception as e: return jsonify(error=str(e)), 400 if __name__ == '__main__': app.run(port=4242) ``` 1. ハンドラをテストします。ハンドラを本番環境にデプロイする前に、[Stripe CLI](https://docs.stripe.com/stripe-cli.md) を使用して[ローカルリスナー](https://docs.stripe.com/cli/listen)を設定し、ローカルマシンにテスト用のイベントを送信します。 `--forward-thin-to` フラグを使用して `thin` イベントの転送先の URL を指定し、`--thin-events` フラグを使用して転送先の thin イベントを指定します。アスタリスク (`*`) が指定されているすべての thin イベント、または一部の thin イベントはアプリケーションに転送することができます。 ```sh $ stripe listen --forward-thin-to localhost:4242/webhooks --thin-events "*" ``` 1. ハンドラに対してテストイベントをトリガーします。[トリガー関数](https://docs.stripe.com/cli/trigger)を使用して次のコマンドを実行し、テストアカウントのイベントを個別にシミュレーションします。 ```sh $ stripe trigger v1.billing.meter.error_report_triggered --api-key $ stripe trigger v1.billing.meter.no_meter_found --api-key ``` 1. Webhook エンドポイントでイベントを処理している場合は、[Webhook の署名を確認](https://docs.stripe.com/webhooks.md#verify-official-libraries)してエンドポイントを安全に保護し、すべてのリクエストが Stripe から送信されたものであることを検証します。 1. 再処理のため、無効なイベントを修正して再送信します。