webhook-platform-design について
プラットフォームチーム向けのアウトバウンド Webhook 設計スキルです。イベント、署名、配信保証と再試行、サブスクリプション、障害調査を扱い、構築か導入かの判断も支援します。
主な機能
- 01イベント分類とカタログ設計
- 02ペイロード形式とスキーマのバージョン管理
- 03署名方式の設計
- 04配信保証、再試行、デッドレター処理
- 05サブスクリプションと配信調査
活用シーン
- 01新しい Webhook プラットフォームの計画
- 02配信と再試行の契約策定
- 03購読者向け調査と再送機能の設計
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ samber/ developer-platform-skills --skill webhook-platform-designインストール後、Claude Code で/webhook-platform-designを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/evals.jsonreferences/event-taxonomy-and-payload-design.mdretry-policy-vendor-comparison.mdsigning-scheme-reference.mdsubscription-lifecycle-comparison.md詳細
Webhook プラットフォームの設計
送信 Webhook プラットフォームの設計者として、イベントの内容、署名方法、配信の保証と再試行、サブスクリプションの作成と終了、そして配信されなかったイベントをインテグレーターがデバッグする方法を含め、プラットフォームが顧客のサーバーにイベントを通知する仕組みを設計します。
Svix は実際の課題を次のように示しています。「HTTP POST の送信は簡単です。大規模に確実に送信するのは簡単ではありません。」この2つの文の間にある差、つまり低速なコンシューマーの分離、バックオフ付きの再試行、デッドレター処理、署名、リプレイ保護を、このスキルで設計します。
このスキルを含むすべてのサーフェスを対象とした一貫性レビューは、samber/developer-platform-skills@public-api-design-review の担当です。このスキルが担当するのは Webhook サーフェス自体の設計です。他のインテグレーションサーフェスの形態と比べて、そもそも Webhook が構築すべきサーフェスなのかどうかは、samber/developer-platform-skills@api-integration-surface-strategy が判断します。
メモリ(推奨): メモリをファイルに保存する場合は、developer-platform-context.md の使用を検討してください。別のメモリシステムを使用している場合は、そちらを利用してください。このファイルは参考資料であり、必須要件ではありません。異なるタスクの情報は別々のセクションに分けてください。完了したタスクは削除してください。タスクには日付を記載し、プロジェクト全般のコンテキストには日付を記載しないでください。同じタスクでも、インタビューでの回答が異なる場合があります。
確認事項
設計を始める前に、次の質問をしてください。回答はまとめて求めてください。これは戦術的な設計タスクであり、戦略インタビューではありません。
- 新規構築ですか、それとも既存システムの改修ですか?改修の場合は、現在のイベント一覧、再試行の挙動、署名方式、利用可能な配信ログを求めてください。
- 規模の桁はどの程度ですか。購読先のエンドポイント数は数十、数千、それ以上のどれくらいで、イベントのピーク発生率は毎秒何件ですか?(ファンアウトの分離方法や FIFO を検討できるかどうかに影響します)
- どのようなコンシューマーが連携しますか。エンタープライズインテグレーター、一般的な API 開発者、ノーコードワークフローツール、またはそれらの混在ですか?(次のセクションを参照してください)
- 工数の上限とデータに関する制約は何ですか。配信インフラに割り当てられるエンジニアリングリソース(人員、常設のオンコール体制、運用予算)はどの程度ですか。また、顧客のイベントデータがサードパーティのプロセッサーを経由しても構いませんか?(「自社構築か購入か」を参照)
- 期限と効果の見込みはどうですか。Webhook をいつまでに出荷する必要があり、短期的な機能リリースなのか、それとも今後何年にもわたって成長するプラットフォームのインテグレーションサーフェスなのか、どちらですか?
- 求められているものの中に、実際にはインタラクティブなクライアント向けストリーミング(ライブダッシュボード、チャット)はありますか?それは GraphQL サブスクリプション/WebSocket の領域であり、Webhook と競合するものではなく、補完するものです。Webhook が担うのは、イベント発生時にコンシューマーがオフラインの可能性がある状況での、永続性のあるサーバー間配信です。サブスクリプションが担うのは、多少のロスが許容される状況での、1秒未満のクライアント向けプッシュです。プラットフォームが両方を提供するのは、十分に妥当な選択です。
質問4〜5が含まれているのは、自社構築か購入かの選択肢と再試行の選択肢が、効果が出るまでの期間、耐久性、工数の面で大きく異なるためです。これらが分からなければ、どちらの優先順位も決められません。厳しい出荷期限があれば、マネージドインフラと短めの再試行期間が有力になります。長期的に成長するサーフェスを目指すなら、自分たちで運用し、調整するパイプラインが有力になります。
ハーネスに永続メモリがある場合は、配信契約の中核となる決定事項(保証、順序の位置づけ、再試行スケジュール、ACK タイムアウト、重複排除 ID の場所、署名方式)を保存してください。そうすれば、後続の実行(新しいイベントタイプ、再試行ポリシーの変更、ドキュメントの確認など)で契約を一から導き直すのではなく、既存の契約を起点にできます。
利用者の習熟度
Webhook の利用者は、製品を購入した人を問わずサーバーです。設計は利用者の習熟度に応じて分けます。多くのユーザー層の分け方とは異なり、各層は包含関係にありません。それぞれに独自の要件が加わります。
- エンタープライズのインテグレーター - 配信契約を文書で求めます。保証のセマンティクス、再試行スケジュール、署名仕様、応答確認のタイムアウトが必要です。FIFO や、共有シークレットを保持する代わりに公開鍵で検証する非対称署名も求めます。
- 一般的な API 開発者 - ドキュメントやポータルを使ってセルフサービスで利用します。生の本文にまつわる落とし穴に対処する検証用スニペット、重複排除のための安定したイベントごとの ID、ハンドラーが 1 時間動作しなかった場合にダッシュボードから再配信できる機能が必要です。
- ノーコードの利用者(ワークフロー自動化ツール) - 受信 URL を中心に考え、「実装に取りかかる前に、実際のペイロードを 1 つ見せてほしい」と考えます。署名仕様を読むことはありません。説明文よりも、テストイベントの送信や最近の配信を確認できる機能をはるかに重視します。
該当するすべての層に対応してください。エンタープライズのインテグレーターに十分な設計でも、テストイベントと配信ログがなければノーコードの利用者には対応できません。
自社開発か購入か
ステップ 1 の前に決めてください。ステップ 4〜6 を実装するのか、設定するだけで済むのかが決まります。選択肢は 3 つあり、次の順に並んでいます。
- 労力:
自社開発 > セルフホスト可能なオープンソースの webhook ゲートウェイ > マネージド送信インフラ - 価値(初日から動作する配信パイプライン):
マネージド > セルフホスト可能なゲートウェイ > 自社開発 - 制御性(データの保存場所、カスタムセマンティクス):
自社開発 == セルフホスト可能なゲートウェイ > マネージド- どちらもイベントデータを自社のインフラに保持します。自社開発では、はるかに高いコストと引き換えにカスタムセマンティクスも実現できます。 - コンプライアンスコスト:
マネージド > セルフホスト可能なゲートウェイ == 自社開発- マネージドでは DPA とデータ保存場所のレビューが必要です。後から方針を変更すると、契約書類の再作成と稼働中のエンドポイントの移行が発生します。ほかの 2 つは、どちらもイベントデータを同等に自社のインフラに保持します。 - 効率:
マネージド > セルフホスト可能なゲートウェイ > 自社開発 - デフォルトの選択肢:マネージド送信インフラ。Webhook が製品そのものではなく、製品の機能である場合はこちらを選びます。Svix/Hookdeck/Convoy クラスのベンダーが該当します(これらの名称は具体例であり、必須要件ではありません。エコシステム内に同等のサービスがあれば、それも評価してください)。Svix が公表している、自社で機能を再現する場合の見積もりは、数週間ではなく数年単位のエンジニア工数です。3〜5 人のエンジニアが 6〜12 か月必要で、常設のオンコール体制も求められます。具体的な数字はベンダー側の利害を考慮して受け止めてください。実装自体は数人月程度に収まり、その大半はレビューと負荷テストです。一方、常設のオンコール体制は縮小できず、自社開発を最もコストの高い選択肢にしています。
- コンプライアンス上、サードパーティ経由の通信が認められない一方、ソフトウェアは運用できる場合は、セルフホスト可能なゲートウェイに移行します。 この場合、マネージドの選択肢は順位を下げるのではなく、選択肢から削除します。質問 4 の回答が「顧客のイベントデータをサードパーティの処理業者経由で送信してはならない」であれば、最後に順位付けするのではなく、選択肢から除外します。コンプライアンス上の理由で最下位に置かれただけの選択肢は、期限が迫ると作業範囲として再び持ち上がります。その際、除外の根拠となった法務レビューを経ずに復活してしまいます。再度候補に加える条件は、DPA の締結と、そのベンダーを対象とするデータ保存場所の方針が整っていることです。
- 自社開発は、リソース不足になりやすい選択肢です。制御性は最も高く、労力も最大で、効率を比較するすべての段階で劣ります。Webhook の配信そのものが販売する製品である場合、またはサードパーティ経由の通信とサードパーティのコードの両方が認められない場合に選びます。どの選択肢を選んでも、ステップ 1〜7 の設計上の判断はすべて必要です。インフラを購入すれば機構は手に入りますが、分類体系、契約、ドキュメントまで用意されるわけではありません。
- この順位付けはデフォルトであり、絶対的なルールではありません。ヒアリングの内容に照らして順位を付け直してください。厳しいリリース期限があればマネージドが有利になります。すでに大規模な耐久性のあるキューを運用している自社チームがあれば、見積もりよりもはるかに安く自社開発でき、労力の順位は逆転します。
ワークフロー
- イベントの分類体系とカタログを定義します。
- ペイロードのエンベロープとスキーマのバージョニング方針を設計します。
- 署名方式を採用します。
- 配信契約を定めます:保証、再試行ポリシー、デッドレター処理。
- サブスクリプションのライフサイクルをモデル化します。
- デバッグ環境を構築します:ログ、再生、テストイベント。
- 5 要素の評価基準に沿ってすべてを文書化します。
各ステップについて、以下に順番に説明します。
1. イベントの分類体系とカタログ
- イベントにはオブジェクトとアクションのパターンを使って名前を付けます:
resource.action。アクションは過去形にします(invoice.payではなくinvoice.paid)。区切り文字にはドットを使い、識別子は[a-zA-Z0-9_.]に制限します。これは Standard Webhooks の推奨事項であり、Stripe の規約でもあります。本番環境のプラットフォームでは、区切り文字や識別子を置く場所が異なるため、ローンチ時に規約を 1 つ選び、決して混在させないでください。GitHub のように、イベント名をヘッダーと本文のフィールドに分割すると、イベントを示す単一の文字列がなくなるため、避けてください。 - カタログが契約となります。すべてのイベントタイプについて、出荷前に安定した名前、説明、ペイロードスキーマを用意します。サブスクライバーはカタログ名で受信対象を選ぶため、文書化されていないイベントタイプは実質的に購読できません。
- 各イベントを 5 つの設計原則に照らして確認します:自己完結性、不変性(フィールドは追加し、用途は変更しない)、追跡可能性、実用性、デバッグ可能性。
- サブリソースのイベントを親イベントにも伝播させるかどうかを明示的に決めます(Stripe の答えは「伝播させない」です。
customer.subscription.updatedが発生しても、customer.updatedは発生しません)。どちらの方針を選ぶにせよ、明記してください。ここが曖昧だと、サブスクライバーが独自に解釈することになります。
ベンダーごとの命名規則の比較と、設計原則のチェックリストの適用例については、references/event-taxonomy-and-payload-design.md を参照してください。
2. ペイロードのエンベロープとスキーマのバージョニング
- エンベロープをどこに置くか、意図的に選択します。メタデータをすべて JSON 本文に含める方法(Stripe)と、メタデータを HTTP ヘッダーに置き、本文にはリソースデータのみを含める方法(GitHub、Shopify、Standard Webhooks)があります。ヘッダーと本文を分ける設計では、イベントを忠実に再生するために、配信ログでヘッダーと本文を両方記録する必要があります。後付けではなく、最初からその前提でログを構築してください。
- 全量ペイロードと軽量ペイロードのどちらにするかを、主要な設計軸として選択します。全量ペイロードはリソースの状態を埋め込みます。軽量ペイロードは識別子を含み、API からの取得を前提とします。Standard Webhooks は、ペイロードを小さく保ち、通常は約 20kb 未満にすることを推奨しています。軽量ペイロードはバージョニングの問題も回避できます。API のバージョンが上がっても、通知の形式は変わりません。
- 2 つのスキーマバージョニング方針のどちらかを、意図的に選びます。各 Webhook エンドポイントの API バージョンを固定し、そのバージョンに応じたペイロードを生成する方法(Stripe のモデル)、またはイベントタイプ自体をバージョニングする方法です。後者では、破壊的変更ごとに新しいタイプ名を付け、それ以外の変更は追加のみとします(Svix/Standard Webhooks のモデル)。両方の方針が意図せず混在することが失敗の原因です。API バージョンが上がっても、サブスクライバーがすでに保存しているイベントペイロードの形を、通知なく変更してはなりません。
- 標準仕様のレイヤー構造を理解します。これらは競合するものではなく、それぞれ異なるレイヤーを担います。Standard Webhooks は署名と配信ヘッダーを、CloudEvents はエンベロープを、AsyncAPI と OpenAPI 3.1 の
webhooksセクションは記述を対象とします。送信イベントは受信 API と同じ OpenAPI ドキュメントに記載してください。CloudEvents を採用するのは、すでに CloudEvents に対応しているイベントメッシュと相互運用する必要がある場合に限ります。
エンベロープの選択肢の詳細、Stripe の軽量ペイロードとスナップショットを併用する移行パターン、標準仕様の対応関係については、references/event-taxonomy-and-payload-design.md を参照してください。
3. 署名方式
署名方式、つまり何にどのように署名し、利用者がどう検証するかは、あなたが決めます。署名鍵の発行、保管、ローテーションのインフラは、兄弟プロジェクトの samber/developer-platform-skills@api-auth-key-management が担当します。
- 独自の方式を考案するのではなく、Standard Webhooks 仕様を採用します。この分断された領域において、主要な API プラットフォームで実際に採用されている(自己申告による)標準に最も近いものです。各配信には、
webhook-id、webhook-timestamp、webhook-signatureの 3 つのヘッダーを含めます。 - 署名の生成:
{id}.{timestamp}.{raw_body}に対して HMAC-SHA256 を実行し、base64 エンコードしたうえで、アルゴリズムのバージョンを前置します(v1,...)。タイムスタンプに署名することで、リプレイ攻撃を防げます。受信側は、タイムスタンプが許容範囲(仕様の推奨値は 5 分)外の配信を拒否します。本文のみを対象とする署名(GitHub や Shopify の方式)では、いつまでも有効なため、傍受されたリクエストは無期限にリプレイされる可能性があります。 - 漏洩した鍵をスキャナーで特定できるよう、シークレットにプレフィックスを付けます。対称 HMAC シークレットには
whsec_、非対称 ed25519 の秘密鍵/公開鍵にはwhsk_/whpk_を使用します(署名 ID はv1a)。共有シークレットを保持すべきでない利用者向けに、非対称署名を提供します。両端を自分で管理できない場合は、非対称署名が推奨されます。 - ゼロダウンタイムのローテーションを設計に組み込みます。
webhook-signatureヘッダーには、スペース区切りで複数の署名を含められるため、ローテーション期間中は古いシークレットと新しいシークレットを同時に検証できます。有効なシークレットが 1 つだけのプラットフォームでは、購読者は先に失効させてからデプロイする必要があり、その間、配信に失敗します。 - 署名のドキュメントでは、連携の失敗の主な原因となる、利用者側の次の 3 つの落とし穴を必ず説明します。
- 通知のみを処理するハンドラーであっても、例外なくすべてのリクエストを検証します。
- JSON パーサーに渡す前に、生の本文に対して検証します。
- Webhook ルートはセッション認証ミドルウェアの対象外にします。Webhook はセッションではなく、署名によって認証されるためです。
署名の構成例、非採用の主要な 4 方式との比較、ローテーションのフローについては、references/signing-scheme-reference.md を参照してください。
4. 配信契約:保証、再試行、デッドレター
- 少なくとも1回の配信を明示的に約束し、意図的な選択として説明します。確認応答があるまで再試行するため、処理後に200を返す前にクラッシュしたサブスクライバーには、イベントが2回届きます。「厳密に1回」とは決して主張しないでください。この市場における「厳密に1回」という主張はすべて、少なくとも1回の配信に重複排除ツールを組み合わせたものです。その誠実な形を最初から提供しましょう。イベントごとに安定したID(同じイベントの再試行では同じ値)を付与し、重複排除の推奨事項を文書化します。後からIDを追加しても、IDなしで構築済みのサブスクライバーには役立ちません。
- 順序保証に関する方針を明示します。順序はベストエフォートであり、保証されないのが適切なデフォルトです。再試行と並列ワーカーによってイベントの順序は入れ替わります。また、順序を厳密に保証すると、失敗した配信によってエンドポイントごとのキュー全体がブロックされます。主要なプラットフォームはいずれも、デフォルトではFIFO以外の方式を採用しています。順序の入れ替わりを構造的に許容できないコンシューマー向けにのみ、FIFOを明示的なオプトインとして提供します。サブスクライバーには、タイムスタンプから順序を推測しないよう警告してください。
- 永続キューを介してリクエスト処理経路と配信を切り離し、エンドポイントごとに分離します。遅いサブスクライバーや障害のあるサブスクライバーによって、ほかのサブスクライバーへの配信が遅れてはなりません。このファンアウトの分離こそ、プラットフォームが自社のエンジニアリングチームに提供する中核的な価値です。
- 再試行ポリシーを選びます。実際のプラットフォーム間で最も大きな違いが生まれるのはここです。
- 実装負荷:
エンドポイントごとに設定可能なスケジュール+サーキットブレーカー > 固定の数日規模のスケジュール+DLQ+自動無効化 > 固定の数時間規模のスケジュール > 手動再配信のみ - 価値(人手を介さず復旧できる配信数):
設定可能+サーキットブレーカー > 固定の数日規模 > 固定の数時間規模 > 手動再配信のみ - 効率:
固定の数日規模のスケジュール > 固定の数時間規模のスケジュール > 設定可能+サーキットブレーカー > 手動再配信のみ - デフォルトの段階:およそ1日にわたる固定の指数バックオフスケジュールです。これはSvixが採用している方式(約27.5時間で8回試行)で、Stripeもこれに近い方式(最長3日間)です。Shopifyの4時間で8回という設定は、短い側の基準になります。総期間は切りのよい数字ではなく、実際のサブスクライバー障害の継続時間を基準に設定します。デプロイは数分で済みますが、停止は数時間続くことがあります。バックオフは必ず指数方式にしてください。一定間隔での再試行は、苦戦しているエンドポイントに負荷をかけ続けます。
- エンドポイント数が十分に増え、継続的に失敗するエンドポイントがパイプラインに大きな負荷を与えるようになった場合、またはエンタープライズのコンシューマーと配信SLAを交渉するようになった場合は、設定可能なスケジュールとサーキットブレーカー(再開前に半開状態でプローブするConvoy方式)に引き上げます。価値は高いものの実装負荷も高いため、この2つの条件を満たしたときに優先度が上がる選択肢です。
- 手動再配信のみ(GitHubのモデル:自動再試行なし)は、名前を付けて避けるべきアンチパターンです。GitHubで機能するのは、配信一覧と再配信APIに加えて、「独自に照合処理を実装する」ための明確なドキュメントが提供されているからです。APIなしで自動再試行だけをなくすのは、信頼性の低い配信を提供するにすぎません。
- この順位付けはデフォルトであり、絶対的なルールではありません。インタビューを踏まえて順位を見直してください。ノーコードのコンシューマーが中心なら、誰も使わない設定可能性の価値は下がります。決済水準の信頼性が求められるドメインなら、長めの配信期間とサーキットブレーカーの優先度が上がります。
- 実装負荷:
- サブスクライバーの応答を、すべて同じものとして扱わず分類します。
- 2xxは確認応答として扱い、再試行を停止します。ShopifyとGitHubの慣例に従い、確認応答はおよそ10秒以内に受け取ることを想定します。
- 「ハンドラーの処理が遅い」状態と「ハンドラーでエラーが発生した」状態は区別します。作業をキューに入れてすぐに応答するサブスクライバーは、まさに推奨すべき実装です。
- 429では、独自のバックオフ曲線よりも
Retry-Afterヘッダーを優先します。これに対応している送信側は少なく、差別化要因になります。 - 再試行不能な4xx(408と429を除く)は、そのままデッドレターキューに送ります。恒久的な失敗を再試行するのは予算の無駄であり、攻撃のように見えます。
- デッドレターキューに送るのは、次の2つの場合に限ります。
- 再試行予算を使い切った場合。
- 再試行不能なエラー種別が発生した場合。 調査と再生のため、ヘッダーを含むすべてのコンテキストとともに、デッドレターイベントを7~30日間保持します。障害が長引いた場合は、エンドポイントを自動的に無効化し、メールまたはダッシュボードなど、サブスクライバーに別経路で通知します。壊れているのはWebhookチャネルそのものだからです。
- 重要度の高いイベント種別を利用するコンシューマーには、APIと定期的に照合することを推奨します。これは回避策ではなく、ベンダーが推奨する運用方法です。配信について、少なくとも1回/ベストエフォートという実際の保証より強い保証があるかのように示すよりも、ドキュメントでこの期待を伝えるほうが誠実です。 references/retry-policy-vendor-comparison.md を参照してください。記載されている6つのベンダーの再試行スケジュール、タイムアウト値、自動無効化の動作、サーキットブレーカーのリファレンス設計がまとめられています。
5. サブスクリプションのライフサイクル
-
サブスクリプション(エンドポイント登録)を、完全な CRUD を備えた、状態を持つ第一級オブジェクトとしてモデル化してください。登録をファイア・アンド・フォーゲットにしてはいけません。次の3つの明示的な状態を設けます。
- active(有効)
- paused(一時停止) - 設定を失わずに、サブスクライバーが開始する停止
- disabled(無効) - 継続的な障害の後に、プラットフォームが開始する停止
インフラに重点を置く3つのベンダーは、このより詳細なモデルに収束しています。enabled/disabled の二値モデルは、プラットフォームが最初に導入する簡素な形ですが、やがてそれでは足りなくなります。顧客が作成したサブスクリプションが正当に到達できる状態だけを公開し、内部専用の状態は API 境界で拒否してください。
-
フィルタリングの2つの軸は独立させてください。イベントタイプ(カタログに対するもの)と、受信者/チャネルのスコープです。フィルターが設定されていないエンドポイントはすべてを受信することを明記してください。
-
新しく作成したサブスクリプションの開始位置(新しいイベントのみ、または保持されているバックログ)と、プラットフォーム側のインシデント後にサブスクリプションを再開する位置の両方を明示してください。この2つは異なっていても問題ありません。サブスクリプションを削除すると、リプレイ/配信状態が失われることを明確に記載してください。同じ名前で作り直しても新規に開始されます。リセット目的で削除したサブスクライバーは、バックログを気付かないまま失ったり、二重にリプレイしたりする可能性があります。
-
設定変更が反映されるまでの遅延は想定内の動作として記載してください(サブスクリプションの編集が配信経路に反映されるまで1~2分かかるのは正常です)。インテグレーターがこれをバグとして報告しないようにします。
6つのベンダーにおける状態/フィルタリング/リプレイの比較と、ステートマシンのケーススタディについては、references/subscription-lifecycle-comparison.md を参照してください。
6. デバッグ機能
この市場では、セルフサービスのコンシューマーポータルはあれば望ましいものではなく、最低限必要なものです。署名検証のドキュメントがない場合と同様に、「ポータルなし」を指摘してください。ポータルには次の機能が必要です。
- 配信ログ:エンドポイント、イベントタイプ、ステータスで絞り込みでき、試行ごとにリクエストヘッダー、本文、レスポンスコード、所要時間を確認できます。エンベロープのメタデータがヘッダーに分割されている場合(手順2)、ログにもそれを保存する必要があります。保存しなければ、リプレイの内容が正確になりません。
- リプレイと再試行は別の操作 - Hookdeck の用語をそのまま採用してください。この市場では両者が同じ意味で使われていますが、ドキュメントでは区別する必要があります。再試行 は同じイベントの新たな配信試行で、リプレイ は元のイベントを新しいイベントとして再取り込みすることです。単一イベントと範囲指定のリプレイを提供してください。大規模なリプレイ期間には、費用を確認してから実行できるようにしてください。大量のバックログのリプレイはコストのかかる操作であり、サブスクライバーが意図していない可能性があるためです。
- テストイベントのトリガー:イベントタイプごとのスキーマに基づいて「サンプルイベントを送信」する操作を設け、インテグレーターがハンドラーコードを1行も書く前に、現実的なペイロードを確認できるようにしてください。これは、ノーコードツールのキャッチURLがコンシューマー側で果たす役割と同じです。サンドボックス環境(偽データ、テストモードのキー)でのテストトリガーは、関連スキル
samber/developer-platform-skills@api-test-mode-designの担当です。このスキルでは、配信側のボタンと、それが送信するサンプルペイロードを扱います。 - 障害の可視化:配信を使い果たしたイベントをキューの行としてではなく、調査すべきインシデントとして可視化してください。エンドポイントとステータスコードごとにグループ化し、通知も行います。「200を返した後にクラッシュする」ブラックホールについて記載してください。確認応答を返してから例外を発生させるハンドラーは、配信に成功したと通知したことになります。デバッグ機能からその内部を確認することはできません。
各ベンダーが実際に提供しているポータルとテストツールの内容については、ベンチマークとして references/subscription-lifecycle-comparison.md を参照してください。
7. ドキュメント
ローンチ前に、優れたドキュメントの評価に使われる次の5項目のルーブリックに照らして、Webhook ドキュメントを評価します。
- 実行可能なスニペットを使った署名検証。
- スキーマとペイロードのサンプルを含むイベントカタログ。
- 再試行ポリシー。「バックオフして再試行します」ではなく、正確なスケジュール。
- トラブルシューティングと障害復旧。
- テストツール。
配信契約は、明確で見つけやすい文で明記します。
- 配信保証(少なくとも1回)。
- 順序に関する位置づけ。
- 再試行スケジュール。
- ACK タイムアウト。
- 重複排除 ID を格納するヘッダーまたはフィールド。
これらのいずれかを暗黙のままにすると、サブスクライバーの思い込みになり、やがてサポートチケットにつながります。配信を制御するものと同じ仕様(OpenAPI 3.1 の webhooks セクション)からイベントカタログを公開し、ドキュメントとペイロードが知らないうちに食い違わないようにします。
障害モード
アンチパターンのチェックリストです。それぞれが監査で直接指摘される項目です。
- 配信一覧と再配信 API がなく、照合ドキュメントも同時に提供していないのに、自動再試行がゼロ。
- ドキュメントのどこかで「完全に一度だけ配信」と主張している。
- ベストエフォートであることを明記せず、順序を暗黙のうちに保証している(またはサブスクライバーの思い込みに委ねている)。
- 再試行間隔が一定である。または、再試行できない 4xx レスポンスを予算を使い切るまで再試行している。
- タイムスタンプのない、本文だけに対する署名(リプレイ攻撃を防げません)。
- 有効な署名シークレットが1つだけで、ローテーションのたびに失効してからデプロイする必要がある。
- 同じイベントの再試行で共通の、安定したイベント ID がない。
- エンベロープにはヘッダーにメタデータがあるのに、配信ログには本文しか保存していない。
- API バージョンの引き上げによって、既存のサブスクライバーがすでに保存しているイベントペイロードの形が、気づかれないうちに変わる。
- サブスクリプションを削除して再作成すると、リプレイ位置が知らないうちにリセットされる。
- 遅くても正しく処理するハンドラー(キューにすばやく登録し、すばやく ACK する)を、タイムアウトと「すばやくキューに登録する」というアドバイスが文書化されていないために障害扱いしてしまう。
- 利用者向けポータルがない(ログ、リプレイ、テストイベントがない)。
測定
二つのバイナリゲートです。両方を通過するまで設計を反復します。
- 契約の完全性:配信保証、順序に関する位置づけ、再試行スケジュール、ACK タイムアウト、重複排除 ID の格納場所を、それぞれ明示的に文書化します。5つの事実がすべて揃っている必要があります。1つでも欠けていればゲートを通過できません。記載がない項目はどれも、インシデントにつながるサブスクライバーの思い込みになるためです。
- ドキュメントのルーブリック:ローンチ前に5項目すべてを揃えます。1項目でも欠けていればゲートを通過できません。
運用指標を整備し、合格基準との比較ではなく、傾向として監視します。
- エンドポイントごとの配信成功率。プラットフォームの主要な健全性指標です。
- デッドレター率。急増は、バックグラウンドでの一時的な再試行とは異なり、エンドポイントが継続的に障害状態にあることを示します。
- 障害が発生したエンドポイントの検知までの時間。自動無効化/通知のウィンドウによって上限が決まります。最初の1か月のデータからベースラインを設定し、外部のしきい値ではなく、そのベースラインに対する改善を目指します。
呼び出し例
- 「請求 API に Webhook を追加します。イベントカタログ、署名、再試行ポリシーをゼロから設計してください。」
- 「Webhook システムがイベントを3回連続で再試行してから破棄するため、顧客が配信を受け取れないことが続いています。再試行とデッドレターポリシーを再設計してください。」
- 「エンタープライズ顧客から、Webhook の署名方式と順序保証の有無について質問されています。顧客に提示できる配信契約を作成してください。」
参考資料
-
references/event-taxonomy-and-payload-design.md - ベンダー間の命名規則、エンベロープの配置に関する分岐、簡潔なペイロードと完全なペイロード、スキーマのバージョン管理に関する各派閥、標準規格の概要。
-
references/signing-scheme-reference.md - Standard Webhooks の構築例、採用していない方式との比較、ローテーションのフロー、ドキュメント作成時に役立つ利用者向けの注意点チェックリスト。
-
references/retry-policy-vendor-comparison.md - 6 つのベンダーが公開している再試行スケジュール、タイムアウト、自動無効化の動作、デッドレターとサーキットブレーカーのパターン。
-
references/subscription-lifecycle-comparison.md - 6 つのベンダーにおけるエンドポイントの状態、フィルタリング、再生/バックフィル、ポータル/テストツール、およびサブスクリプションのステートマシンに関する事例研究。
-
samber/developer-platform-skills@api-idempotency-retry- API のリクエスト側における一般的な再試行と冪等性の仕組み(バックオフアルゴリズム、冪等性キー)を扱います。このスキルでは、これらの考え方をアウトバウンド配信にのみ適用します。 -
samber/developer-platform-skills@integration-error-observability- Webhook の配信ログ以外で、統合エラーが開発者にどのように表示されるかを扱います。 -
samber/developer-platform-skills@api-status-communication- 配信失敗がプラットフォーム側の問題である場合の、インシデントおよびステータスページでのコミュニケーションを扱います。 -
samber/developer-platform-skills@api-versioning-policy- ステップ 2 で選択するイベントスキーマの進化を支えるバージョン管理の仕組みを扱います。 -
samber/developer-platform-skills@api-error-design- サブスクリプション管理 API 自体のエラーの表面を扱います。 -
samber/developer-platform-skills@public-graphql-api-design- 質問 6 で挙げた、補完的なプッシュ方式である GraphQL サブスクリプションを扱います。サブ秒単位のプッシュによるファーストパーティのライブ UIと、このスキルが扱う永続的なサーバー間配信を対比しています。