コンテンツにスキップ
getnextpdf.com

Enterprise エディション

Webhook

NextPDF Enterprise は、ジョブイベントを HTTP POST 経由でテナントごとの webhook エンドポイントに配信し、各ペイロードに HMAC-SHA256 署名で署名し、指数バックオフで再試行し、恒久的に失敗した配信を検査とリプレイのためにデッドレターキューにルーティングします。このページは、観測可能な webhook の挙動とパブリックコントラクトを記述します。

このケイパビリティは NextPDF Enterprisenextpdf/enterprise)に同梱され、Enterprise ティアのライセンスエンベロープで有効化されます。そのエンタイトルメントを持たないデプロイメントでは、ケイパビリティのクラスはロードされません。エディションを比較してライセンスを取得

Webhook サーフェスは Enterprise の基本ケイパビリティであり、Enterprise パッケージがインストールされれば利用できます。機能ごとに独立したフラグはありません。

テナントは、コールバック URL、署名シークレット、およびオプションのイベントタイプのリストを登録します。空のイベントリストは「すべてのイベントにサブスクライブする」ことを意味します。登録は厳密にテナントスコープです。テナントは自身の登録のみを参照および管理でき、不一致のテナントのもとでの登録は拒否されます。登録解除は、登録を削除するのではなく無効化するため、履歴が保持されます。ディスパッチを受け取るのは、アクティブな登録のみです。

ジョブイベントがテナントに対してディスパッチされると、そのイベントタイプにサブスクライブしているアクティブな各登録が配信を受け取ります。ペイロードは標準化された JSON ドキュメントです。一意の配信識別子、ジョブ識別子、イベントタイプ、イベントデータ、RFC 3339 タイムスタンプ、テナント識別子です。配信は、JSON ボディと 4 つのヘッダーを保持する HTTP POST です。HMAC-SHA256 署名、unix 秒タイムスタンプ、配信識別子、イベントタイプです。署名は、登録のシークレットで正規のベース文字列 {timestamp}.{body} に対して計算されるため、タイムスタンプヘッダーは暗号学的にボディへ束縛されます。受信側は同じベース文字列に対して HMAC を再計算し、タイムスタンプが許容される鮮度ウィンドウの外にある配信を拒否することで、リプレイを制限します。

配信は指数バックオフを使用します。2xx レスポンスは成功です。429 以外の 4xx レスポンスは恒久的な拒否として扱われ、再試行されません。その他の失敗(5xx、429、または接続エラー)は、最大値で上限が定められた倍化遅延で、ポリシーの試行回数まで再試行されます。すべての試行が尽きると、配信は、元のペイロード、試行回数、最後のエラー、最後の HTTP ステータスとともに、インメモリのデッドレターキューに記録されます。デッドレターエントリは、リプレイ済みとしてマークできます。2 つの再試行ポリシーが同梱されます。default(5 回試行、1s ベース、5min 上限)と aggressive(10 回試行、2s ベース、10min 上限)です。

配信は、投げっぱなしの呼び出しではなく、運用サーフェスとして扱われます。失敗は意図によって分類されます。429 以外の 4xx は純粋な受信側の拒否なので、直ちに停止します。5xx、429、または接続エラーは一時的なので、上限のあるバックオフ付き再試行に値します。すべての試行を尽くした配信が黙って破棄されることは決してありません。それらは、リプレイできる検査可能なデッドレターキューに着地します。署名はタイムスタンプをそのベース文字列に束縛し、すべての宛先はエグレスゲートを通過するため、認証性とリプレイ耐性は各テナントについて構成上成り立ちます。

設計の背景: Operating NextPDF in production

Terminal window
composer require nextpdf/enterprise:^3

サポートされる統合ポイントは、webhook マネージャー(registerunregisteractiveRegistrationsdispatch)、登録値オブジェクト(subscribesTodeactivate)、ペイロード(fromJobEventtoJsontoArraysignsignedTimestamp)、配信エンジン(deliverdeadLettersclearDeadLetters)、再試行ポリシー(delayForAttemptshouldRetrydefaultaggressive)、およびデッドレターエントリ(markReplayed)です。

use NextPDF\Enterprise\Webhook\WebhookManager;
use NextPDF\Enterprise\Webhook\WebhookRegistration;
$manager->register($tenant, new WebhookRegistration(
id: $id,
tenantId: $tenant->tenantId,
url: 'https://customer.example.com/hooks/nextpdf',
events: [], // empty = subscribe to all event types
secret: $signingSecret,
));
$delivered = $manager->dispatch($tenant, $jobEvent); // count of successes

受信側の検証:

$ts = (int) $request->header('X-NextPDF-Timestamp');
if (abs(time() - $ts) > 300) {
return new Response(401); // stale timestamp: reject to bound replay
}
$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $rawBody, $sharedSecret);
if (! hash_equals($expected, $request->header('X-NextPDF-Signature'))) {
return new Response(401);
}
use NextPDF\Enterprise\Webhook\WebhookDelivery;
use NextPDF\Enterprise\Webhook\WebhookRetryPolicy;
$delivery = new WebhookDelivery(
$httpClient, $requestFactory, $streamFactory,
retryPolicy: WebhookRetryPolicy::aggressive(), // 10 attempts, 2s base, 10min cap
logger: $logger,
);
$manager = new WebhookManager($delivery, $logger);
$manager->dispatch($tenant, $jobEvent);
foreach ($delivery->deadLetters() as $dead) {
$this->scheduleReplay($dead); // inspect last error + last HTTP status
}
  • 空のイベントリストはすべてにサブスクライブします。 イベントタイプを持たない登録は、すべてのイベントを受信します。スコープするには明示的なリストを渡してください。
  • テナント分離が強制されます。 コンテキストのテナントと異なるテナント ID での登録は拒否されます。ディスパッチは、呼び出し元テナントのアクティブな登録のみを反復します。
  • 4xx(429 を除く)は終端です。 429 以外の 4xx は再試行されません。恒久的な受信側の拒否として扱われ、デッドレターキューに送られます。
  • 登録解除はソフトです。 登録解除は無効化します。レコードは保持され、ディスパッチから除外されます。
  • デッドレターキューはインメモリです。 プロセスのライフタイム内での検査とリプレイのためのものです。再起動をまたぐ永続的なリプレイが必要な場合は、自分でエントリを永続化してください。

ディスパッチのコストは、イベントにサブスクライブしているテナントのアクティブな登録の数に比例します。各配信は、署名済みベース文字列に対する 1 回の HMAC-SHA256 と HTTP ラウンドトリップです。再試行は、限定された指数バックオフ遅延を追加します。署名は O(ペイロードサイズ) です。

各ペイロードは、登録のシークレットでキーイングされた HMAC-SHA256 署名で認証され、X-NextPDF-Signature ヘッダーに sha256=<hex> として送信されます。署名は {timestamp}.{body} ベース文字列を対象とし、タイムスタンプは X-NextPDF-Timestamp ヘッダーで伝送されます。受信側は定数時間の比較で検証し、リプレイを制限するために鮮度ウィンドウの外にある配信を拒否します。宛先 URL は、すべての送信の前に中央のエグレスゲートを通過します。HTTPS が要求され、プライベート、ループバック、リンクローカル、またはクラウドメタデータアドレスに解決するホストは、リクエストなしに拒否され、デッドレターキューにルーティングされます。署名シークレットは登録ごとです。認証情報として扱ってください。署名はペイロードの完全性と起源を認証します。暗号化レイヤーではありません。受信側が見るべきでないシークレットをイベントデータに含めないでください。

  • ペイロード認証は SHA-256 を用いた HMAC、FIPS PUB 198-1 のキー付きハッシュメッセージ認証コードを使用します。OWASP ASVS 5.0 は、承認されたメッセージ認証アルゴリズムの一つとして HMAC-SHA-256 を挙げています。
  • ペイロードタイムスタンプは RFC 3339 date-time 文字列です。注: このページでは RFC 3339 を RAG コーパスから取得していません。形式はコード宣言(RFC 3339 拡張)であり、RAG 検証済みではなくコード宣言としてマークしています。
  • 登録は厳密にテナントスコープです。不一致のテナントのもとでの登録は拒否され、登録解除は履歴を保持するソフトな無効化です。
  • 空のイベントリストはすべてのイベントにサブスクライブします。ディスパッチを受け取るのは、イベントタイプにサブスクライブしているアクティブな登録のみです。
  • 各配信は、JSON ボディに、HMAC-SHA256 署名ヘッダー({timestamp}.{body} ベース文字列に対する)、unix 秒タイムスタンプヘッダー、配信識別子、イベントタイプを加えた HTTP POST です。
  • 2xx は成功です。429 以外の 4xx は恒久的な拒否です(再試行なし)。5xx、429、または接続エラーは、上限のある倍化バックオフで、ポリシーの試行回数まで再試行されます。
  • 試行が尽きると、配信は、インメモリのデッドレターキューに記録されます(ペイロード、試行回数、最後のエラー、最後のステータス)。デッドレターエントリは、リプレイ済みとしてマークできます。

このページは、外部から観測可能な挙動とサポートされるパブリック API サーフェスのみを記述しています。内部名前空間パス、ヘルパークラス、メカニズムテーブル、ランブックのファイル名、チケットプレフィックスは対象外です。

NextPDF Core(Apache-2.0)には、webhook の登録または配信サーフェスがありません。一切ありません。このケイパビリティに Core ティアの同等品はありません。

NextPDF Pro には、webhook の登録または配信サーフェスがありません。一切ありません。このケイパビリティに Pro ティアの同等品はありません。webhook マネージャー、登録、ペイロード、配信エンジン、再試行ポリシーは、nextpdf/enterprise パッケージにのみ同梱されています。

再試行ポリシー、バックオフスケジュール、デッドレター処理は、挙動レベルで記述されています。デッドレターキューは、プロセスのライフタイム内での検査とリプレイのためのインメモリです。再起動をまたぐ永続化、および内部の配信内部は、パブリックサーフェスの対象外です。

オペレーターは、コールバックエンドポイント、登録ごとの署名シークレット(認証情報として扱う)、再起動をまたぐリプレイが必要な場合のデッドレターエントリの永続化、および受信側 URL の HTTPS 姿勢を所有します。NextPDF Enterprise は署名して配信しますが、それ自体がプロセスのライフタイムを超えて登録やデッドレターを永続化することはありません。

webhook サーフェスに輸出管理の制限は適用されません。HMAC 署名はペイロードの完全性と起源を認証します。暗号化レイヤーではありません。オペレーターは、受信側が見るべきでないシークレットをイベントデータに含めてはなりません。このドキュメントは法的意見ではありません。ご自身のコンプライアンスおよび法務の助言者にご相談ください。