# Webhook で決済イベントを処理

Webhook を使用してオフラインの支払いイベントに対応する方法は以下のとおりです。

*Webhook* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) は、Stripe からイベントを受信する HTTP エンドポイントです。

Webhook を使用すると、決済フロー外で発生する以下のような支払いイベントに関する通知を受け取ることができます。

- 成功した決済 (`payment_intent.succeeded`)
- 不審請求の申し立てが行われた決済 (`charge.dispute.created`)
- Stripe アカウントの利用可能な残高 (`balance.available`)

ダッシュボードを支払いの返金や顧客情報の更新などの 1 回限りのアクションの用途に使用できるのに対して、Webhook は決済システムを拡張したり、ビジネスに影響する重要なイベントを大量に処理するのに役立ちます。

## 独自の Webhook を構築する

お客様独自のサーバーで Webhook ハンドラを構築し、オフラインのすべての決済フローを管理できます。まず、Stripe からのリクエストを受信できるエンドポイントを公開し、CLI を使用してシステムをローカルでテストします。Stripe からの各リクエストには [Event (イベント)](https://docs.stripe.com/api/events/object.md) オブジェクトと、修正された Stripe 上のオブジェクトへの参照が含まれます。

## Webhook エンドポイントを作成

アプリケーションに新しいエンドポイントを追加します。リクエスト本文で送信されたイベントオブジェクトの `type` フィールドを確認することにより、特定のイベントに対応できます。次に、Webhook が機能していることを確認するため、標準的な出力を確認できます。

新しいエンドポイントを追加した後で、サーバを起動します。

#### Ruby

```ruby

# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
# Find your keys at https://dashboard.stripe.com/apikeys.
client = Stripe::StripeClient.new('<<YOUR_SECRET_KEY>>')

require 'stripe'
require 'sinatra'
require 'json'

# Using the Sinatra framework
set :port, 4242

post '/webhook' do
  payload = request.body.read
  event = nil

  begin
    event = Stripe::Event.construct_from(
      JSON.parse(payload, symbolize_names: true)
    )
  rescue JSON::ParserError => e
    # Invalid payload
    status 400
    return
  end

  # Handle the event
  case event.type
  when 'payment_intent.succeeded'
    payment_intent = event.data.object # contains a Stripe::PaymentIntent
    puts 'PaymentIntent was successful!'
  when 'payment_method.attached'
    payment_method = event.data.object # contains a Stripe::PaymentMethod
    puts 'PaymentMethod was attached to a Customer!'
  # ... handle other event types
  else
    puts "Unhandled event type: #{event.type}"
  end

  status 200
end
```

## Stripe CLI をインストールして設定する

[npm](https://www.npmjs.com/) で Stripe CLI をインストールします。

```bash
npm install --global @stripe/cli
```

> Windows、macOS、Linux、Docker 向けのその他のインストールオプションについては、GitHub の [Stripe CLI readme](https://github.com/stripe/stripe-cli#installation) を参照してください。

インストール後、ログインして CLI を Stripe アカウントに接続します。

```bash
stripe login
```

## Webhook をローカルでテストする

CLI を使用して、`listen` コマンドでローカル Webhook エンドポイントにイベントを転送します。

アプリケーションがポート 4242 で実行されていると仮定し、以下を実行します。

```bash
stripe listen --forward-to http://localhost:4242/webhook
```

別の端末タブで、`trigger` CLI コマンドを使用して模擬 Webhook イベントをトリガーします。

```bash
stripe trigger payment_intent.succeeded
```

`listen` タブには次のイベントが表示されます。

```bash
[200 POST] OK payment_intent.succeeded
```

サーバーを実行中の terminal タブに「PaymentIntent was successful! (PaymentIntent は正常に処理されました)」と表示されます。

## Optional: Webhook の署名を確認する

Stripe は各イベントの `Stripe-Signature` ヘッダーに署名を含めます。これにより、イベントがサードパーティーではなく Stripe によって送信されたことを確認できます。Stripe の公式ライブラリを使用して署名を確認するか、自社のソリューションを使用して[手動で署名を確認](https://docs.stripe.com/webhooks.md#verify-manually)することができます。

最初に、Webhook エンドポイントのシークレットを特定し、それを `endpoint_secret` として Webhook ハンドラに追加します。ここではローカルでのエンドポイントの構築に引き続き Stripe CLI を使用しているため、`trigger` コマンドを使用して CLI から Webhook エンドポイントのシークレットを取得します。

```bash
stripe listen
```

Webhook エンドポイントのシークレットは `whsec_` で始まり、それに一連の数字と文字が続きます。この Webhook エンドポイントのシークレットは安全に保管し、決して公開しないようにしてください。

#### Ruby

```ruby

# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
# Find your keys at https://dashboard.stripe.com/apikeys.
client = Stripe::StripeClient.new('<<YOUR_SECRET_KEY>>')

require 'stripe'
require 'sinatra'

# If you are testing your webhook locally with the Stripe CLI you
# can find the endpoint's secret by running `stripe listen`
# Otherwise, find your endpoint's secret in your webhook settings in
# the Developer Dashboard
endpoint_secret = 'whsec_...'

# Using the Sinatra framework
set :port, 4242

post '/my/webhook/url' do
  payload = request.body.read
  sig_header = request.env['HTTP_STRIPE_SIGNATURE']
  event = nil

  begin
    event = Stripe::Webhook.construct_event(
      payload, sig_header, endpoint_secret
    )
  rescue JSON::ParserError => e
    # Invalid payload
    puts "Error parsing payload: #{e.message}"
    status 400
    return
  rescue Stripe::SignatureVerificationError => e
    # Invalid signature
    puts "Error verifying webhook signature: #{e.message}"
    status 400
    return
  end

  # Handle the event
  case event.type
  when 'payment_intent.succeeded'
    payment_intent = event.data.object # contains a Stripe::PaymentIntent
    puts 'PaymentIntent was successful!'
  when 'payment_method.attached'
    payment_method = event.data.object # contains a Stripe::PaymentMethod
    puts 'PaymentMethod was attached to a Customer!'
  # ... handle other event types
  else
    puts "Unhandled event type: #{event.type}"
  end

  status 200
end
```

## Webhook エンドポイントをデプロイする

Webhook エンドポイントを本番環境にデプロイする準備ができたら、以下を実行する必要があります。

1. テストキーではなく、[本番環境の API キー](https://docs.stripe.com/keys.md#test-live-modes)を使用してください。
2. Webhook エンドポイントを[ワークベンチ](https://docs.stripe.com/workbench.md)または API で設定します。
3. ワークベンチでエンドポイントを設定するには、[Webhook タブ](https://dashboard.stripe.com/workbench/webhooks)に移動します。
4. **送信先を追加**をクリックして、Stripe API のバージョンと、Stripe に送信させたい特定のイベントを入力します。**続行**をクリックし、使用可能な送信先タイプのリストから**Webhook エンドポイント**を選択します。**続行**をクリックし、エンドポイントの URL、オプションの名前、オプションの説明を入力します。**送信先を作成する**をクリックします。
5. アプリケーションの Webhook エンドポイントシークレットを、エンドポイントの Workbench の宛先詳細ビューに表示されている新しいシークレットに置き換えます。

これで、アプリケーションで本番イベントを受け入れられるようになりました。Webhook エンドポイントの設定については、[Webhook Endpoint](https://docs.stripe.com/api/webhook_endpoints.md) API のドキュメントで詳細をご確認ください。サンドボックスでのテスト方法については、[開発ガイドを参照してください](https://docs.stripe.com/webhooks.md)。
