stripeで本人確認通知(account.update)をwebhookで受ける

目次

マーケター、エンジニアを月1時間からジョインできるプラットフォーム

airteamは月1時間からマーケターやエンジニアに相談できるプラットフォーム。 雇うのはハードル高いけどプロをチームに入れたい。そんな経営者のためのサービスです。 相談にのる方も募集しています。

タスクなしだから月一時間からジョイン可能

作業はなくオンライン相談メイン。 月1時間からさっと経験者に継続的に相談できます。

多様な経験者を雇用するより何倍も早くチームに

あらゆるジャンルの経験者がいるので あなたのチームのノウハウの選択肢が広がります。

NDAはすでに締結済み、契約もスムーズ

契約の煩雑なやりとりはなく、NDAはすでに締結済み、書面のやりとりはありません。

stripe connectにて子アカウントの本人確認が完了したタイミングでユーザーにメールで伝える実装をしたのでまとめます。

やったこと

実装内容は下記になります。

  • webhookをtype connectで新しく作成
  • account.updateのみをリッスン
  • account.updateのpayouts_enabledがtrueになったら対象ユーザーにメール通知
  • testでメール送信されるかをテスト

前提

前提として下記になります

  • rails
  • stripe
  • connect使用
  • expressアカウント

webhookの設計

今回、webhookは新しく作成しています。今までinvoice.createdなど支払いに関するwebhookも受けていましたがそちらはtype directで親アカウントのeventを受け取るものだったんですが、今回のaccount.updateは子アカウントのeventになるのでtype connectにする必要があります。

一つのwebhookで二つのtypeは受け取れないので別にwebhookを作成しました。詳細な設定は下記

  • type connect
  • リッスンするのはaccount.update
  • urlはwebhook/connectなど別のもの

controllerの設計

signatureが別になるので受け取るcontrollerも別にします。webhook_connect_controllerを作成します。

class WebhookConnectController < ActionController::API

    def webhook_event
        webhook認証のコード
    
        case event.type
        when 'account.updated'
          event_account_update(data)
        else
          puts "Unhandled event type: \#{event.type}"
          puts event.type
        end
        render status: 200, json: { status: 200, message: "Success" }
    end
    
    private
    
       
        def event_account_update(data)
    
        if data[:object][:payouts_enabled]
    
          stripe_account_id = data[:object][:id]
          account_user = User.find_by(stripe_account_id: stripe_account_id)
          NotificationMailer.send_account_update_payout_enabled_to_account_user(account_user).deliver_later
    
        end
    
    end

end

controllerを作成し、ActionController::APIからの継承に変更。やっていることとしては

  • secretの確認
  • eventがaccount.updateならevent_account_updateを呼び出す
  • event_account_updateでメール送信

テスト

テストは下記で


RSpec.describe "webhook_connect_controller", type: :request do

  describe "webhook/connect" do
    let!(:user_01) { FactoryBot.create(:user) }
    include StripeEventHelpers
    let!(:account_update_params) { {
      "object": "event",
      "data": {
        "object": {
          "id": user_01.stripe_account_id,
          "object": "account",
          "payouts_enabled": true,
        }
      },
      "type": "account.updated"
      }
    }
    example "本人確認メールが送られるか" do
        expect{ post_with_stripe_signature_connect '/webhook/connect', params: account_update_params.to_json }.to have_enqueued_job.on_queue("mailers")
    end
  end

end

post_with_stripe_signature_connectはsupport配下に置いたhelperになります。

module StripeEventHelpers

    def post_with_stripe_signature(path, **options)
      post(
        path,
        headers: {
          'Stripe-Signature': generate_stripe_event_signature(options[:params])
        },
        **options
      )
    end

    def post_with_stripe_signature_connect(path, **options)
      post(
        path,
        headers: {
          'Stripe-Signature': generate_stripe_event_signature_connect(options[:params])
        },
        **options
      )
    end
  
    private

    def generate_stripe_event_signature(payload)
      time = Time.now
      secret = ENV['WEBHOOK_SECRET']
      signature = Stripe::Webhook::Signature.compute_signature(time, payload, secret)
      Stripe::Webhook::Signature.generate_header(
        time,
        signature
      )
    end

    def generate_stripe_event_signature_connect(payload)
      time = Time.now
      secret = ENV['WEBHOOK_SECRET_CONNECT']
      signature = Stripe::Webhook::Signature.compute_signature(time, payload, secret)
      Stripe::Webhook::Signature.generate_header(
        time,
        signature
      )
    end

end