Webhooks that cannot lose deliveries.
Outbound webhooks ride the canonical event substrate — outbox-backed, exactly-once-materialized, claimed and dispatched through a durable five-state machine. Inbound webhooks have idempotency receipts and globally-unique public receiver keys. Signing operates on ReadOnlySpan<byte> — secret material never becomes a string. Retry includes random jitter to avoid synchronized storms.
Pending → Claimed → Succeeded / RetryScheduled / DeadLettered.
Durable per-delivery row
Every outbound dispatch is a WebhookDelivery row. ClaimedBy/ClaimedAt cleared on every transition out of Claimed — so retry-scheduled rows remain eligible for future scans (anti-pattern #50).
WebhookDeliveryAttempt
Per-try record. Status code, response body, latency, error class. Auditable history — operators see exactly what happened on every attempt.
Retry with jitter
ComputeBackoffSeconds adds 0-50% random jitter to base exponential backoff. Synchronized retry storms across instances are prevented by construction.
HMAC-SHA256 on bytes
WebhookPayloadSigner operates on ReadOnlySpan<byte>. Key material never becomes a string. Format: t={unix},v1={hex}. Verifiable by every standard webhook receiver.
IKeyRing-managed secrets
Signing keys live in the key ring. SecretKeyRingId never appears in API projections, logs, traces, exception messages. Anti-pattern #49 codified.
Typed SubscriptionFilterAst
Replaces the legacy glob string EventTypeFilter. 15 typed operators, depth-bounded validator, deterministic serializer, fail-closed evaluator. Filter expressions are first-class.
Public receiver keys. Receipts. Never double-process.
PublicReceiverKey
Globally-unique ULID identifying the inbound route. Path uniqueness is platform-wide, not scoped by tenant — receivers can be discovered, validated, rotated independently.
InboundWebhookReceipt
Pending / Succeeded / Failed lifecycle. PlannedOutboxEventKey links to the canonical event for crash recovery reconciliation. Same payload twice yields the same canonical event once.
Verification on bytes
Same WebhookPayloadSigner verifies inbound signatures. Timing-safe comparison. Reject before parsing. Anti-pattern #76 codified — never trust a payload before its signature checks.
Crash-resumable
Never key-as-string
Globally unique
15 operators
Webhooks that don't get lost.
Outbound rides the canonical outbox. Inbound idempotency through receipts. Signing operates on bytes. Retries jitter. The substrate is designed for production realities, not demos.