module-41/webhook-notary.mdDELIVERY STANDARD

The Webhook Notary

Webhooks that are verified, deduplicated, and impossible to spoof with a curl command.

Anyone who found the webhook URL could POST fake payment events to it — and when the real provider retried, the same event processed twice.
Signed, verified, idempotent webhooks: signature validation at the door, event-ID dedupe, ordered retries with a dead-letter queue, and a replayable event log.

The incident

The payment webhook endpoint did what the quick-start guide showed: parse the JSON, mark the order paid. Two problems arrived in the same quarter. First, the provider retried a delivery and the same payment processed twice. Then a security researcher demonstrated the bigger one: the endpoint accepted his hand-crafted 'payment succeeded' event too, because nothing checked who was sending it.

Why the obvious approach fails

A webhook endpoint is a door on the public internet that changes your system's state — and quick-start code treats it like a trusted internal call. It isn't. Anyone who finds the URL can POST to it, so unverified payloads are an open invitation to forge the exact events you care most about. And providers retry by design — networks drop acknowledgments — so an endpoint without deduplication will process real events twice. Inbound events need the same rigor as payments themselves: prove the sender, process each event once, and keep the ones you couldn't handle.

The standard

  • Every inbound webhook verifies the provider's signature before parsing; unsigned or invalid payloads are rejected and logged as security events.
  • Event IDs are deduplicated: a retried delivery is acknowledged and ignored, never reprocessed.
  • Handlers acknowledge fast and process async (through the Job Marshall) — the provider's timeout never dictates your processing time.
  • Failed processing lands in a dead-letter queue with the full payload; events are replayable after the bug is fixed.
  • Out-of-order arrival is handled by design — event timestamps and state checks, not the assumption that the network preserves sequence.

How Cortex validates it

At plan time

every inbound integration declares its verification method, dedupe key, and replay strategy.

At validation

assert: unsigned_payload → rejected && security_loggedassert: duplicate_event_id → processed_onceassert: handler_ack_latency < provider_timeout && processing == async

Assertion syntax is illustrative.

At review

the approver sees the hostile run: forged events rejected, duplicate deliveries deduplicated, a poison event dead-lettered and replayed after repair.

Composes with

See where your codebase stands against this standard.