Chapter 06無料公開

Stripe WebhookのデバッグをStripe CLIで行う

hidetaka okamoto
hidetaka okamoto
2021.03.15に更新

StripeはWebhookを利用して、様々なイベントをトリガーすることができます。そしてStripe CLIを利用することで、Webhookのデバッグや開発をよりスムーズに行うことができます。

v1.5.8時点では、stripe listenstripe triggerがWebhook関連のコマンドとして用意されています。

Webhook commands:
  listen                        Listen for webhook events
  trigger                       Trigger test webhook events

stripe listenでStripのWebhookイベントをモニタリングする

stripe listenはStripe上でWebhookのイベントが発生したログを確認できるコマンドです。

stripe listenコマンド概要

% stripe listen --help
The listen command watches and forwards webhook events from Stripe to your
local machine by connecting directly to Stripe's API. You can test the latest
API version, filter events, or even load your saved webhook endpoints from your
Stripe account.

Usage:
  stripe listen [flags]

Examples:
  stripe listen
  stripe listen --events charge.captured,charge.updated \
    --forward-to localhost:3000/events

Flags:
      --connect-headers strings     
                A comma-separated list of custom
                headers to forward for Connect
  -e, --events strings              
                A comma-separated list of specific
                events to listen for. For a list of
                all possible events, see:
                https://stripe.com/docs/api/events/types (default [*])
  -c, --forward-connect-to string   
                The URL to forward Connect webhook
                events to (default: same as normal
                events)
  -f, --forward-to string           
                The URL to forward webhook events to
  -H, --headers strings             
                A comma-separated list of custom
                headers to forward
  -h, --help                        
                help for listen
  -l, --latest                      
                Receive events formatted with the
                latest API version (default: your
                account's default API version)
      --live                        
                Receive live events (default: test)
  -j, --print-json                  
                Print full JSON objects to stdout
      --print-secret                
                Only print the webhook signing
                secret and exit
  -s, --skip-update                 
                Skip checking latest version of
                Stripe CLI
      --skip-verify                 
                Skip certificate verification when
                forwarding to HTTPS endpoints
  -a, --use-configured-webhooks     
                Load webhook endpoint configuration
                from the webhooks API/dashboard

listenコマンドでイベントの発生をモニタリングする

stripe listenコマンドを実行すると、「いつ」「どのイベントが」「どのIDで」発生したかを確認できるようになります。

下のサンプルでは、2021/3/15 12:19:40びpayment_intent.createdのイベントが発生したことが確認できます。また、evt_xxxを使ってStripe Dashboardで検索を行うと、イベントの内容や受け取ったレスポンスなどの記録が確認できます。

% stripe listen 
> Ready! Your webhook signing secret is whsec_xxxxxxx (^C to quit)

2021-03-15 12:19:40   --> payment_intent.created [evt_1IV6xyDHnG67uihbNhTZyGQi]                                 

--print-jsonで詳細をJSON形式で確認する

E2Eテストやserverless invoke localなどでイベントをテストしたい場合、--print-jsonオプションをつけて監視することで、Stripeから送られてくるWebhookイベントの内容をみることができます。

% stripe listen --print-json
{
  "id": "evt_1IV7DpDHnG67uihbvtxwWKPY",
  "object": "event",
  "api_version": "2020-03-02",
  "created": 1615779361,
  "data": {
    "object": {
      "id": "pi_1IV7DpDHnG67uihbQsPJBGMl",
      "object": "payment_intent",
      "amount": 2000,
      "amount_capturable": 0,
      "amount_received": 0,
      ...

--liveで本番のイベントをモニタリングする

本番環境のイベントを追跡したい場合、--liveオプションを追加しましょう。
これで本番環境で発生したWebhookイベントをモニタリングできるようになります。

--eventsで指定のイベントのみモニタリングする

規模の大きいアプリケーションなどでは、大量のイベントの中に調べたいイベントが埋もれてしまうこともあります。そんな場合は、--events charge.captured,payment_intent.createdのようにイベント名を指定すると便利です。

% stripe listen --events charge.captured,payment_intent.created 
> Ready! Your webhook signing secret is whsec_xxxxxx (^C to quit)

2021-03-15 12:45:43   --> charge.captured [evt_1IV7NDDHnG67uihbhV4mIsBK]
2021-03-15 12:45:47   --> payment_intent.created [evt_1IV7NGDHnG67uihb5FNbkuF8]

stripe triggerでWebhookイベントをトリガーする

Webhookを開発しても、実際にイベントが発生しないと動作確認ができません。イベントが発生することを待つか、Dashboardからイベントを手動で発行することのどちらかでデバッグを行うことが多いかと思いますが、Stripe CLIを使うことでイベント発行も行うことができます。

% stripe trigger --help
Trigger specific webhook events to be sent. Webhooks events created through
the trigger command will also create all necessary side-effect events that are
needed to create the triggered event as well as the corresponding API objects.

Supported events:
  account.updated
  balance.available
  charge.captured
  charge.dispute.created
  charge.failed
  charge.refunded
  charge.succeeded
  checkout.session.async_payment_failed
  checkout.session.async_payment_succeeded
  checkout.session.completed
  customer.created
  customer.deleted
  customer.source.created
  customer.source.updated
  customer.subscription.created
  customer.subscription.deleted
  customer.subscription.updated
  customer.updated
  invoice.created
  invoice.finalized
  invoice.payment_failed
  invoice.payment_succeeded
  invoice.updated
  issuing_authorization.request
  issuing_card.created
  issuing_cardholder.created
  payment_intent.amount_capturable_updated
  payment_intent.canceled
  payment_intent.created
  payment_intent.payment_failed
  payment_intent.succeeded
  payment_method.attached
  plan.created
  plan.deleted
  plan.updated
  product.created
  product.deleted
  product.updated
  setup_intent.canceled
  setup_intent.created
  setup_intent.setup_failed
  setup_intent.succeeded
  subscription_schedule.canceled
  subscription_schedule.created
  subscription_schedule.released
  subscription_schedule.updated

Usage:
  stripe trigger <event> [flags]

Examples:
  stripe trigger payment_intent.created

Flags:
  -h, --help                    help for trigger
      --stripe-account string   Set a header
                                identifying the
                                connected account

customer.createdイベントを発行する

Dashboardからイベントを発行する時と同じように、発行したいイベント名を指定するだけで実行できます。

 % stripe trigger customer.created
Setting up fixture for: customer
Trigger succeeded! Check dashboard for event details.

stripe listenでモニタリングしている場合、customer.createdのイベントが発生したログが出力されます。

2021-03-15 12:52:53   --> customer.created [evt_1IV7U8DHnG67uihbTQSkyYg4]

stripe triggerはデータ作成も行う点に注意

stripe triggerコマンドは、現状不可能ですが、live環境向けに使うことは非推奨です。それは「実際にリソースを作成する」挙動を行うためです。

先ほどのstripe trigger customer.createdを実行したのち、Stripe Dashboardにアクセスすると、created by Stripe CLIと記されたCustomerが作成されています。

この他、payment_intentやsubscriptionなども、実際に各APIを呼び出してリソースを作成し、それによってイベントを発行する動きをしています。

下のコマンドでは、Customer / Plan / Subscriptionが作成されています。
コマンドを実行するたびにリソースが作成されますので、もし「plans.listの結果をそのまま商品一覧として表示する」ような実装をアプリケーション側でされている場合には注意してください。

 % stripe trigger customer.subscription.created
 
Setting up fixture for: customer
Setting up fixture for: plan
Setting up fixture for: subscription
Trigger succeeded! Check dashboard for event details.

stripe listenを使ってローカル環境にWebhook APIサーバーをたてる

StripeのWebhook APIをローカルで開発する際、stripe listenコマンドを利用することで、StripeからのWebhookイベントをローカル環境のAPIで受け取れるようにすることができます。

[事前準備] stripe sampleコマンドでWebhookのあるサンプルプロジェクトを作成する

実際にWebhookを作成してもよいのですが、本筋から外れますので今回はStripeが用意しているサンプルを利用します。

placing-a-holdなど、Webhookの実装が含まれているサンプルプロジェクトを選んでstripe samples createしましょう。

% stripe samples create placing-a-hold
A newer version of the Stripe CLI is available, please update to: v1.5.10
✔ Finished downloading
Use the arrow keys to navigate: ↓ ↑ → ← 
? What type of integration would you like to use: 
  ▸ using-webhooks
    without-webhooks
? What server would you like to use: 
    java
  ▸ node
    php
    python
    ruby

% cd placing-a-hold

続いてWebhook用のサーバーを立ち上げます。今回はNode.jsで作成していますので、npmコマンドを利用します。また、実際には.envファイルにStripeのAPIキーなどを追加する必要がありますが、今回はリクエストが受け取れたらOKなので省略します。

% npm install --prefix server
% cp .env.example server/.env
% npm start --prefix server
Node server listening on port 4242!

curlコマンドでAPIにアクセスできるか試しておきましょう。

% curl http://localhost:4242/webhook -XPOST --verbose
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 4242 (#0)
> POST /webhook HTTP/1.1
> Host: localhost:4242
> User-Agent: curl/7.64.1
> Accept: */*
> 
< HTTP/1.1 400 Bad Request
< X-Powered-By: Express
< Content-Type: text/plain; charset=utf-8
< Content-Length: 11
< ETag: W/"b-EFiDB1U+dmqzx9Mo2UjcZ1SJPO8"
< Date: Mon, 15 Mar 2021 02:43:28 GMT
< Connection: keep-alive
< 
* Connection #0 to host localhost left intact
Bad Request* Closing connection 0

もしアクセスできない場合は、以下のようにConnection refusedが表示されます。その場合、npm installができていないか、npm startが失敗している可能性が高いです。

% curl http://localhost:4242/webhook -XPOST --verbose
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 4242 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connection failed
* connect to 127.0.0.1 port 4242 failed: Connection refused
* Failed to connect to localhost port 4242: Connection refused
* Closing connection 0
curl: (7) Failed to connect to localhost port 4242: Connection refused

stripe listen --forward-toでStripeからのWebhookを受信する

通常localhostで稼働しているAPIにリクエストを飛ばすには、ngrokなどのサービスを使う必要があります。ですが、Stripe CLIを使っている場合、stripe listenコマンドでforwardすることができます。

npm startなどでWebhookを受信するAPIサーバーを起動させた状態で、以下のコマンドを実行します。Portが4242以外を使用している場合は、都度書き換えましょう。

% stripe  listen --forward-to localhost:4242/webhook
A newer version of the Stripe CLI is available, please update to: v1.5.10
> Ready! Your webhook signing secret is whsec_xxxxxxxxxxxxx (^C to quit)

Forwardに成功すると、CLIが待機中表示になります。

この状態で、新しくターミナル画面を追加し、stripe triggerコマンドを実行してWebhookイベントを発生させてみましょう。

% stripe trigger payment_intent.created
Setting up fixture for: payment_intent
Trigger succeeded! Check dashboard for event details.

stripe listenを実行している画面に、以下のようなログが表示されます。

2021-03-15 11:46:13   --> payment_intent.created [evt_1IV6RdDHnG67uihb8MVQQKGg]
2021-03-15 11:46:13  <--  [400] POST http://localhost:4242/webhook [evt_1IV6RdDHnG67uihb8MVQQKGg]

stripe listenの実行結果をStripe Dashboardで確認する

Stripe CLIでforwardしたWebhookの送信ログも、Stripe Dashboardから確認できます。

ただし表示場所が[Webhook の試行]ではなく[Webhook CLI 応答]ですので注意してください。

Webhookを実際に使えるようにする

先ほどのログを見ますと、HTTP 400のBad Requestがレスポンスとして出力されています。これは、Stripe Webhookを受け取る際の署名チェックに失敗しているためです。

stripe listenコマンドを実行した直後にYour webhook signing secret is whsec_xxxxxxxxxxxxxという文言が表示されます。このwhsec_xxxserver/.envファイルのSTRIPE_WEBHOOK_SECRETに設定して、再度npm startでAPIサーバーを立ち上げてみましょう。

% vim server/.env
# Stripe keys
STRIPE_PUBLISHABLE_KEY=pk_12345
STRIPE_SECRET_KEY=sk_12345

# Required to run webhook
# See README on how to use the Stripe CLI to setup
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxx

#Environment setup
STATIC_DIR=../../ client

% npm start --prefix server

Stripe Webhookの署名チェック用シークレットが正しく設定されたことで、再度stripe trigger payment_intent.createdを実行すると、WebhookのレスポンスがHTTP 200に変わります。

2021-03-15 11:56:17   --> payment_intent.created [evt_1IV6bNDHnG67uihbkrZPaKF8]
2021-03-15 11:56:17  <--  [200] POST http://localhost:4242/webhook [evt_1IV6bNDHnG67uihbkrZPaKF8]

デプロイ時はDashboardから署名チェック用シークレットを発行しよう

.envに設定したSTRIPE_WEBHOOK_SECRETは、Stripe CLIがWebhookの動作確認で利用するためのシークレットです。そのため、実際にデプロイして実行するアプリケーションには、登録したWebhook個別に発行されているシークレットを環境変数に設定するようにしましょう。

.envをそのままGitでcommitすると、シークレットキーの漏洩だけでなく、意図せぬ挙動が起きる可能性も高まりますので要注意です。