本文へ移動
AI Dev Lab Japan AI開発ツール、AIコーディングエージェント、M...

CodexにWebhook受信を任せる前に決めること

CodexにWebhook受信を任せる前に決めることの要点をタイトルと確認軸で示すアイキャッチ

追記: 2026年6月15日の最新情報

2026年6月15日にOpenAI APIのWebhooks公式ガイドを確認しました。OpenAIのwebhookはStandard Webhooksに沿って配信され、HTTPヘッダーにwebhook-idwebhook-timestampwebhook-signatureが含まれます。CodexにOpenAI webhook receiverを作らせる場合は、JSONを業務処理へ渡す前に署名検証を置き、signing secretを環境変数やsecret managerで扱う前提をpromptへ入れてください。

OpenAI公式ガイドは、endpointがすぐに2xxを返し、重い処理はbackground workerへ逃がす設計を推奨しています。2xxが返らない、または数秒以内に応答しない場合は最大72時間までexponential backoffで再試行され、重複配送も起こり得ます。実装時はwebhook-idをidempotency keyとして保存し、queue、dead-letter、replay手順までrunbookに含めるのが安全です。確認元はOpenAI API Webhooks guideです。

このテーマをもう少し広げて見るなら、AIエージェントの実行ログ設計: trace・tool call・承認ログを事故調査に使える形で残すOpenAI Agents SDKを業務アプリに入れる前に: tools・handoffs・guardrails・tracingの設計チェック も合わせて確認してください。Webhook受信後の処理結果、replay、承認ログを事故調査に使える形で残す設計へつなげるため。

3行まとめ

VisualWebhook受信の4点受ける前に決めます。
Verify

署名。

Dedup

重複。

Queue

非同期。

Replay

再送。

Webhookは受けられた時より、重複して遅れて届く時の設計が大事です。

  • CodexにWebhook受信を任せる時は、POST endpointを作る前に、signature verification、raw body、event id、重複配送、再送、queue、dead-letterを決めます。
  • Webhook payloadは、署名検証が終わるまで信頼できるeventではありません。secretはpromptへ貼らず、環境変数やsecret managerから読みます。
  • 受信requestの中で重い業務処理を完了させようとせず、検証、保存、enqueue、ack、非同期処理、replayの流れに分けます。

Webhookは、外部サービスから自分たちのアプリへeventが届く仕組みです。決済完了、Issue作成、メール配信結果、CRM更新、LLM job完了、社内workflow通知。受け取れれば便利ですが、受信処理は意外と壊れやすい領域です。

Codexに「Webhook endpointを作って」と頼むと、route、JSON parse、handler、DB更新まではすぐ作れます。けれど、signature verificationがない、raw bodyが壊れる、同じeventが2回来る、順番が前後する、処理中にtimeoutする、再送で二重反映される、失敗したeventを再実行できない、という問題が残りがちです。

この記事では、CodexにWebhook受信処理を任せる前に決めることを整理します。外向きのAPI連携は公開済みのCodexに外部API連携を任せる前に決めることで扱いました。ここでは、外部から届くeventを受ける側に絞ります。

この記事でわかること

Visual確認する材料実装前の整理です。
Raw body

本文。

Secret

鍵。

Event

ID。

DLQ

退避。

Codexへ渡す前に、受信、検証、保存、処理を分けます。

  • Webhook受信をCodexへ頼む前に決める7項目
  • signature verificationとraw bodyを最初に置く理由
  • secretをAIへ貼らずに検証処理を実装する方法
  • event idとbusiness keyで二重反映を防ぐ考え方
  • queue、dead-letter、replayを使った運用しやすい構成
  • 2xxを返すタイミングと、重い処理をrequestから逃がす判断
  • Codexへそのまま渡せる依頼packet
  • reviewで止めるべき危ない実装

Webhookの仕様はproviderごとに違います。Stripe、GitHub、Slack、Shopify、SendGrid、自社APIでは、署名header、payload、再送条件、timeout、event idの扱いが変わります。この記事は汎用の設計整理であり、実装時には必ず対象providerの公式Docsを確認してください。

前提知識

Visual見る一次情報providerごとの約束です。
項目内容見方
Stripe署名。
GitHubHMAC。
Retry再送。
Raw未加工。

Webhookはproviderごとに署名方法や再送の扱いが変わります。

Webhookは、外部サービスから届くHTTP requestです。外部APIを呼び出す処理とは向きが逆です。自分から取りに行くのではなく、相手が決めたタイミングで届きます。

そのため、受信側は次の前提を持ちます。

  • 同じeventが複数回来ることがある
  • eventが遅れて届くことがある
  • eventの順番が前後することがある
  • provider側の再送と、自分たちのreplayが別に存在する
  • payloadは署名検証が終わるまで信用しない
  • 受信endpointは外部から直接叩かれる入口になる

Webhookは外部から来る命令ではない

Webhookを「外部サービスから来た命令」と扱うと危険です。署名検証後のeventも、ただちに業務状態を変えてよいとは限りません。

たとえば、決済完了eventが来たから即座に権限付与するのか、注文DBの状態と照合するのか、既に処理済みなら無視するのか。ここはプロダクトの業務ルールです。Codexに任せる前に、人間が決めます。

raw bodyを壊さない

StripeのWebhook署名検証では、受信したraw bodyが必要です。GitHubのWebhook署名検証でも、payload bodyとsecretからHMACを計算し、headerと比較します。

frameworkのmiddlewareが先にJSON parseしたり、bodyを文字列化し直したりすると、署名検証が失敗することがあります。Codexへは「署名検証前にbodyを加工しない」と明記します。

受信前に決める7項目

Visual7つの決定routeを作る前の条件です。
項目内容見方
Provider送信元。
Route入口。
Secret署名。
Event種類。
Store保存。
Queue処理。
Replay再送。

Webhookは小さなPOST endpointではなく、event処理の入口です。

Webhook routeを作る前に、7項目を決めます。

項目決めること曖昧なまま起きること
providerどのサービスから受けるか署名方式が混ざる
routeendpoint URLとmethod1つのrouteに責務が集まる
secret検証用secretの置き場所promptやログへ露出する
event type処理するeventの種類不要なeventまで処理する
storeevent idとpayloadの保存重複や失敗を追えない
queue非同期処理の入口request中に重い処理をする
replay再送・再実行の手順失敗時に手作業で壊す

Codexへ渡す依頼でこれらが空欄だと、実装中に都合のよい決め打ちが入ります。Webhookは届くかどうかだけでなく、届いた後に安全に処理できるかが本題です。

providerごとにrouteを分ける

StripeとGitHubを同じWebhook routeで受ける必要はありません。signature header、event schema、retry、secretが違うため、providerごとにrouteを分けたほうがreviewしやすくなります。

event typeを絞る

受け取るevent typeは必要なものだけにします。決済なら checkout.session.completed、GitHubなら issuespull_request のように、処理対象を絞ります。不要なeventは保存だけするか、拒否するか、明示的に無視します。

reviewで見ること

差分reviewでは、指定していないevent typeを処理していないか、署名検証より前にpayloadを信用していないか、secret名がハードコードされていないかを見ます。

signature verificationを最初に置く

Visual検証順序信用する前に確かめます。
  1. 1Raw

    保持。

  2. 2Header

    取得。

  3. 3HMAC

    計算。

  4. 4Compare

    比較。

  5. 5Reject

    拒否。

署名検証前のpayloadは、まだ信頼できるeventではありません。

Webhook endpointでは、signature verificationを最初に置きます。JSON parse、DB更新、queue投入、ログ出力より先です。

GitHub Docsでは、Webhook secretを設定した場合に X-Hub-Signature-256 headerを使い、HMAC-SHA256で検証することが説明されています。Stripe Docsでも、payload、Stripe-Signature header、endpoint secretを使った署名検証が説明されています。

Codexへは、次のように指示します。

署名検証前にpayloadを業務処理へ渡さない。
raw bodyを保持したままsignature verificationを行う。
secret値はpromptへ貼らず、WEBHOOK_SECRET環境変数から読む。
検証失敗時はpayload内容を詳細にlogしない。
署名検証を通過したeventだけ保存とqueue投入へ進める。

secretはpromptへ貼らない

Webhook secretは、AIへ貼る必要がありません。必要なのは、環境変数名、provider、header名、検証方式、失敗時の扱いです。

secretをpromptへ貼ると、会話、ログ、artifact、PR commentに残る可能性があります。Codexにはダミー値と環境変数名だけ渡します。

timing safe comparisonを使う

署名比較では、単純な文字列比較ではなく、実行時間差を利用されにくい比較方法を使います。多くの公式SDKや標準libraryには安全な比較関数があります。Codexへは、公式SDKがある場合はそれを優先し、手書きする場合はtiming safe comparisonを使うよう指示します。

注意点

署名検証の失敗理由を外部に細かく返しすぎないでください。responseは短く、内部logはsecretやpayloadをmaskします。

idempotencyと重複配送を前提にする

Visual重複対策同じeventを安全に受けます。
項目内容見方
Event ID受信。
Status状態。
Business key反映。
Lock競合。

同じeventが複数回来ても、業務状態は一度だけ進むようにします。

Webhookは、同じeventが複数回来ることがあります。providerの再送、手動redelivery、自分たちのreplay、network timeoutなどが理由です。

そのため、Webhook処理はidempotentにします。同じeventをもう一度受けても、業務状態が二重に進まないことが重要です。

event idで処理済みを記録する

まず、providerが渡すevent idやdelivery idを保存します。受信時刻、provider、event type、signature verification結果、processing status、attempt、error reasonを残します。

同じevent idが来たら、既に処理済みか、処理中か、失敗済みかを見ます。処理済みなら二重処理せず、必要に応じて2xxを返します。

business keyでも二重反映を防ぐ

event idだけでは足りない場合があります。たとえば、同じ注文IDに対して別eventが複数届く、似た意味のeventが順不同で届く、provider側で別IDとして再生成される場合です。

その場合は、注文ID、invoice ID、user ID、subscription IDのようなbusiness keyでも二重反映を防ぎます。

評価基準

同じeventを2回、同時に、順番を変えて処理しても、業務状態が壊れないなら良い設計です。Codexへは、このテストをfixtureで作らせます。

queueへ渡してすぐ返す

Visualingest flow受信と処理を分けます。
  1. 1Verify

    検証。

  2. 2Persist

    保存。

  3. 3Enqueue

    投入。

  4. 4Ack

    応答。

  5. 5Work

    処理。

重い処理を受信requestの中に詰め込まない構成にします。

Webhook endpointの中で重い処理をすべて終わらせようとすると、timeoutや再送が増えます。受信requestでは、署名検証、event保存、queue投入までにして、重い処理はworkerへ渡します。

基本の流れはこうです。

1. raw bodyを受ける
2. signature verificationを行う
3. event idとpayloadを保存する
4. queueへjobを入れる
5. providerへ2xxを返す
6. workerで業務処理する
7. 成功、失敗、retry、DLQを記録する

2xxを返すタイミング

2xxを返すのは、eventを安全に保存し、後続処理へ渡せる状態になった時です。業務処理が完了してから2xxにすると、処理が遅い時にprovider側が失敗と見なし、再送が増える可能性があります。

ただし、保存にもqueue投入にも失敗した場合に2xxを返すと、eventを失います。ここは明確に分けます。

dead-letterを残す

workerで処理に失敗したeventは、一定回数のretry後にdead-letterへ送ります。dead-letterには、event id、provider、event type、失敗理由、attempt、最後のerror、次の対応を残します。

実装で見ること

Webhook handler内で外部API呼び出し、メール送信、重いDB更新、長いtransactionをしていないかを見ます。受信と業務処理は分けます。

replayと運用ログを設計する

Visual復旧の流れ再送時に追えるようにします。
  1. Receive

    受信。

  2. Fail

    失敗。

  3. DLQ

    退避。

  4. Inspect

    確認。

  5. Replay

    再実行。

replayは新規実行ではなく、同じeventを安全にやり直す操作です。

Webhookは失敗します。失敗した時に、再送やreplayができる設計にします。

providerによっては、管理画面やAPIからredeliveryできます。一方で、自分たちのDBに保存したeventをworkerへ再投入するreplayもあります。この2つを混同しないようにします。

再送は新規処理ではない

redeliveryやreplayは、新規eventとして扱わないほうが安全です。同じevent idとして扱い、processing statusを見て、再実行してよい状態かを確認します。

runbookへ残す

replayは運用操作です。誰が、どのeventを、なぜ、いつ再実行したかを残します。大量replayする場合は、rate limit、外部APIへの負荷、ユーザーへの影響も見ます。

Codexへ渡す依頼packet

Visual依頼packetそのまま渡せる型です。
項目内容見方
Allowed許可。
Forbidden禁止。
Verify署名。
Tests確認。
Runbook運用。

packet化すると、署名検証や重複処理を実装漏れにしにくくなります。

Codexへは、次のようなpacketで渡します。

目的:
  payment providerから決済完了Webhookを受け、注文をpaidへ進める。

provider:
  Stripe。署名検証は公式SDKを優先する。

route:
  POST /api/webhooks/stripe

secret:
  STRIPE_WEBHOOK_SECRET を環境変数から読む。値はpromptへ貼らない。

受けるevent:
  checkout.session.completed のみ処理する。
  その他eventは保存してignoredにする。

検証:
  raw bodyを署名検証前にparseしない。
  検証失敗時は400を返し、payload本文はlogしない。

idempotency:
  event.idを保存し、処理済みeventは二重処理しない。
  order_idでもpaid反映を一度だけにする。

queue:
  署名検証、保存、enqueue後に2xxを返す。
  業務処理はworkerで行う。

test:
  valid signature、invalid signature、duplicate event、unknown event、worker failure、replayをfixtureで確認する。

review:
  secret露出、署名検証前のparse、同期重処理、重複処理漏れ、DLQなしを重点的に見る。

このpacketがあると、Codexは実装すべき境界を理解しやすくなります。Webhookは小さなrouteに見えますが、実際にはevent ingestionの入口です。

よくある失敗

Visualbad patternsWebhookで崩れやすい点です。
No verify

未検証。

Parsed body

加工済み。

No dedup

重複。

Sync heavy

重い処理。

Webhookの失敗は、テスト時に届いた1回のeventだけでは見えにくいです。

signature verificationを後回しにする

「まず動くようにしてから署名検証を足す」は危険です。署名検証は後付けしにくく、middleware構成やraw bodyの扱いに影響します。

JSON parse済みbodyで検証する

frameworkが先にbodyをparseすると、providerが署名したraw bodyと違う形になることがあります。Webhook routeだけbody parserを分ける必要があります。

event idを保存しない

event idを保存しないと、重複配送やreplayを安全に扱えません。処理済みかどうかを判断できないため、二重反映が起きます。

受信request内で重い処理をする

Webhook request中に外部API呼び出しや重いDB処理を詰め込むと、timeoutや再送の原因になります。受信と処理を分けます。

2xxを早く返しすぎる

保存もqueue投入もできていないのに2xxを返すと、providerは成功と見なし、eventが消えます。2xxは安全に後続処理へ渡せる状態になってから返します。

FAQ

Visual判断の入口迷った時の見方です。
項目内容見方
200?保存後。
Retry?前提。
Secret?環境。
Replay?同一。

迷ったら、同じeventがもう一度来ても安全かを確認します。

署名検証は必須ですか

外部から直接届くWebhookでは、基本的に必須と考えます。providerが提供する署名検証やsecret設定を使い、署名検証前のpayloadを信用しない構成にします。

すぐ2xxを返すべきですか

署名検証、event保存、queue投入が終わったら2xxを返す構成が扱いやすいです。保存できていない、またはqueueへ渡せない状態で2xxを返すのは避けます。

同じeventが2回来たらどうしますか

event idで処理済みを見て、二重処理を避けます。業務状態の反映はbusiness keyでも守ります。同じeventを何度受けても壊れないようにします。

Codexにsecretを渡さずに実装できますか

できます。環境変数名、header名、検証方式、fixture、期待する失敗処理を渡せば、secret値なしで実装できます。

replayは誰が実行しますか

本番では運用者の明示操作にします。自動retryと手動replayを分け、操作ログ、対象event、理由、結果を残します。


次に読むなら

参照した主な情報源

更新履歴

Visual更新メモ公開時点の整理です。
  1. 2026.06.01

    初版。

providerのWebhook仕様は変わるため、導入時に公式Docsを確認します。

  • 2026.06.01: 初版公開。CodexへWebhook受信を任せる前のsignature verification、idempotency、queue、replayを整理しました。