ooligo
n8n-flow

n8nによる汎用HubSpot Webhookハンドラー

Difficulty
中級
Setup time
45min
For
revops · gtm-engineer
RevOps

Stack

ポータルが送信するすべてのHubSpot WorkflowsのWebhookを受け取り、HMAC v3シグネチャを検証し、Postgresの台帳に対して重複排除し、イベントタイプ別にルーティングし、HubSpotがリトライしないほど高速にackする単一のn8nワークフローです。1つのハンドラー、1つのURL、チームが関心を持つすべてのイベント。誰も信頼せず誰も所有しない1回限りのZapのフォルダーを置き換えます。

アーキテクチャの中心は、ルーティングではありません。デデュープ台帳です。HubSpotはすべての5xxレスポンスを最大24時間リトライし、ハンドラーはある時点でダウンし、同じイベントが2〜3回届きます。HubSpotのeventIdをキーにした台帳なしでは、Slack通知を二重送信し、レコードを二重作成し、パイプラインメトリクスを破損します。台帳があれば、2回目の配信はインサートでゼロ行を返し、フローは200 OKのackに短絡します。

使うべき場面

HubSpotイベントに反応する必要があるダウンストリームシステムが3つ以上あり、イベントが重複し、現在はイベント×宛先のペアごとにZapまたはHubSpot Operations Hubのカスタムコードアクションがある場合。そのマトリクスは乗法的に増加し、誰もリファクタリングしません。1つのハンドラーで1つのSwitchノードと共有インフラストラクチャ(シグネチャ検証、デデュープ、エラーキャプチャ、リプレイ)を持つとマトリクスをイベントタイプごとに1パスに削減します。

使ってはいけない場面

HubSpotイベントのダウンストリームコンシューマーが1つだけの場合、n8nをスキップしてHubSpot Operations HubのカスタムコードアクションをHubSpot自身のリトライフレームワーク内で使用します。

厳格なレイテンシ予算(100ms以下のack必要)と大量ユースケース(毎秒100件以上のイベントが持続する)がある場合、代わりにAWS Lambda + API Gateway + DynamoDBを使用します。

小さなPostgresデータベースを運用する意欲がまったくない場合、このワークフローは適していません。

HubSpotのティアがMarketing Hub Free / Sales Hub Starterの場合、Workflowsのwebhookはそもそもありません。前提条件はOperations Hub ProfessionalまたはEnterpriseです。

セットアップ

  1. Postgresインスタンスをプロビジョニングします。apps/web/public/artifacts/webhook-handler-hubspot-n8n/_README.mdから2つのCREATE TABLE文を実行します。
  2. HubSpotデベロッパーアカウントで、アウトバウンドWebhookに署名するアプリのクライアントシークレットを見つけるか作成します。
  3. n8nインスタンスで、HUBSPOT_CLIENT_SECRETN8N_WEBHOOK_PUBLIC_BASE_URLの2つの環境変数を設定します。
  4. ワークフロー → ファイルからインポートからフローをインポートします。2つのプレースホルダーに認証情報をバインドします。
  5. ワークフローをアクティベートします。WebhookノードからプロダクションWebhook URLをコピーし、HubSpotアプリのwebhookサブスクリプションページに登録します。
  6. バンドルの_README.mdから4つの検証ケースを実行します(有効なハッピーパス、無効なシグネチャ拒否、重複イベントIDスキップ、未知のサブスクリプションタイプのフォールバック)。

フローの動作

WebhookノードはrawBody: truePOST /webhook/hubspot/eventsを受け取ります。生バイトはHubSpotのv3シグネチャが正確なリクエストボディに対して計算されるため必須です。

Verify HMAC + ParseはCodeノードで、タイムスタンプの5分リプレイウィンドウチェック、署名文字列の再構築、HMAC-SHA256計算、定数時間比較を順番に行います。

Dedupe Ledger Insertはべき等性のキーストーンです。INSERT INTO hubspot_event_ledger (...) ON CONFLICT (event_id) DO NOTHING RETURNING event_id。初回イベントはそのevent_idを返します。重複はゼロ行を返し、フローは200 OKのackに短絡します。

Switch — Event TypesubscriptionTypeをキーにします。フォールバック出力はhubspot_unhandled_eventsに書き込みます。

Respond 200 OKは台帳インサートが成功した後、ダウンストリームブランチが完了する前にackします。

コスト試算

n8nをセルフホストした小さなVM(Hetzner / DigitalOceanで月約$20〜$30)は、1日数万件のイベントを問題なく処理します。台帳の行サイズは約2〜4KBです。月30kイベントで30日間の保持で、テーブルは100MB未満に収まります。

隠れたコストはダウンストリームAPIクォータです。誤設定されたHubSpot Workflowが1時間に10,000件のイベントを送信すると、SlackのレートリミットとほとんどのAPIクォータを数分で使い切ります。

成功指標

HubSpotの発火からダウンストリームの副作用まで、p95で2秒以下のエンドツーエンドレイテンシ。第2の指標:四半期ごとにゼロの二重送信。

代替手段との比較

HubSpot Operations Hubのカスタムコードとの比較: 1〜2つの単純な宛先には優れています。3つ以上の宛先または相互イベント相関の必要がある場合は移行が適切です。

AWS Lambda + API Gateway + DynamoDBとの比較: よりスケーラブルですが、デプロイパイプラインとチームが必要です。毎秒100件を超える場合はLambdaを選択します。

イベントごとのZapの現状との比較: Zapは重複送信し、共有シグネチャ検証がなく、リファクタリングが困難です。

注意点

  • ローカルで通過しプロダクションで失敗するHMACシグネチャの不一致。 N8N_WEBHOOK_PUBLIC_BASE_URLを正確に設定します(末尾スラッシュなし、正しいスキーム、正しいポート)。
  • 5分間のウィンドウ内のリプレイ攻撃。 対策:デデュープ台帳のevent_id PRIMARY KEYがこれをno-opにします。
  • バーストでのダウンストリームAPIクォータ枯渇。 対策:ブランチごとのリトライキャップとn8nキューモード。
  • HubSpot側のスキーマドリフト。 対策:Switchノードのフォールバック出力が未知のタイプをhubspot_unhandled_eventsにパークします。
  • 実行途中のn8nワーカーのクラッシュ。 対策:saveExecutionProgress: trueを有効にします。

スタック

  • HubSpot Workflows — イベントソース。Operations Hub ProfessionalまたはEnterpriseが必要
  • n8n(セルフホスト推奨)— Webhookレシーバー、シグネチャ検証器、ルーター、ファンアウト
  • Postgres — デデュープ台帳と未処理イベントのパーキング
  • Slack — 障害アラートと例示的なディールステージブランチ
  • ダウンストリームシステム — 内部API、Salesforce、Zendesk、ウェアハウスなど

Files in this artifact

Download all (.zip)