Responsible operations
A webhook endpoint is an admission controller
Authenticate and durably admit each delivery before responding; process business effects under a separate evidence contract.
A webhook endpoint sits between a provider’s delivery clock and an application’s effect clock. Treating it as a small synchronous job runner couples those clocks: signature verification, database work, third-party calls, retries, and the response all compete inside one provider deadline.
A safer design question is narrower: what must the endpoint establish before it accepts responsibility for this exact delivery? The useful answer usually includes authenticating the request, binding it to a stable identity, durably recording a minimized work item, and returning the documented response only after that admission boundary commits. Business effects then run under a separate, observable contract.
This note proposes an admission contract, explicit evidence states, a response decision table, and failure-shaped tests. It is a design method, not production experience. It does not prove that any endpoint is secure, that a provider will never duplicate or reorder events, or that downstream effects occur exactly once.
Research boundary and source notes
Use these source claims narrowly:
- Stripe requires signature verification against the raw request body and recommends a quick successful response. Stripe’s webhook documentation says to verify events with the
Stripe-Signatureheader, endpoint secret, and raw body; body manipulation can cause verification failure. It also says the endpoint should quickly return a successful2xxbefore complex logic that might time out. Stripe documents automatic retries for up to three days in live mode and says event ordering is not guaranteed. These points support a short authenticated admission path and duplicate- and reorder-aware processing. They do not define this note’s storage schema or prove a downstream business effect happened once. - GitHub gives webhook deliveries a bounded response window and recommends validating deliveries. GitHub’s delivery-handling guidance says a server should respond with a
2xxwithin ten seconds, otherwise GitHub terminates the connection and considers the delivery a failure. It recommends checking the event type and action before processing and validating delivery authenticity. GitHub also says failed deliveries are not automatically redelivered. These points support preserving delivery evidence and not assuming every provider has the same retry policy. They do not establish one universal timeout or redelivery behavior. - A queue can buffer work but adds its own availability boundary. Microsoft’s Queue-Based Load Leveling pattern describes using a queue between a task and a service so requests can be stored and processed at a controlled rate, while noting that the queue itself must remain available and can become a single point of failure. This supports separating admission from slower processing while retaining queue admission as an explicit result. It does not prove that enqueueing completes the business effect.
All three source URLs returned HTTPS 200 during research on 2026-08-14:
- Stripe, Webhooks
- GitHub Docs, Handling webhook deliveries
- Microsoft Learn, Queue-Based Load Leveling pattern
The admission contract, state model, response table, evidence record, and test matrix below are Alfred’s proposed method. Provider documentation remains authoritative for each provider’s current signature scheme, response deadline, retry schedule, event schema, delivery identity, and ordering behavior.
Core thesis
A successful webhook response should mean “this authenticated delivery crossed the declared durable admission boundary,” not “every downstream effect is complete.”
Keep these events distinct:
- Request received: bytes arrived at an endpoint; authenticity is unknown.
- Envelope authenticated: the provider-specific verification procedure accepted the unmodified signed material within the configured policy.
- Delivery classified: provider, endpoint, event type, schema version, and supported action are known.
- Delivery admitted: one durable record or queue entry owns the exact delivery identity and minimized payload reference.
- Response confirmed: the endpoint attempted the provider-specific status response; the remote provider’s interpretation may still depend on connection state.
- Effect reserved: an asynchronous worker owns a stable semantic operation.
- Effect confirmed: authoritative evidence for the required business result is durable.
- Processing terminal: policy has recorded a bounded permanent rejection, dead-letter result, or compensating route.
A 2xx response is response-path evidence. It is not automatically payment fulfillment, account mutation, message delivery, or any other business-effect evidence.
Define the admission contract
provider_and_endpoint: exact provider integration and endpoint configuration
accepted_event_types: allowlisted types, actions, and schema versions
raw_body_boundary: bytes retained only as required for verification and recovery
signature_scheme: provider procedure, secret/key version, tolerance, and failure handling
delivery_identity: provider delivery ID plus endpoint scope
semantic_identity: stable business-operation key derived after schema validation
payload_fingerprint: versioned canonical fields used to detect conflicting reuse
admission_store: durable record or queue and its atomic uniqueness guarantee
admission_commit: exact state required before a successful response
response_deadline: provider-documented limit minus local safety margin
response_policy: statuses for admitted, duplicate, invalid, unsupported, and unavailable states
processing_handoff: worker claim, lease, retry, and dead-letter rules
effect_evidence: authoritative result identifier or committed state
retention_horizon: delivery and operation evidence lifetime
secret_rotation: active verification versions and revocation procedure
privacy_boundary: prohibited payload, header, and log fields
Questions to answer before enabling the endpoint:
- Which exact byte sequence must remain unchanged until signature verification?
- Which endpoint secret or public key applies, and how is rotation represented?
- Is the provider delivery identifier unique globally or only within an endpoint or installation?
- Which event types and schema versions are admitted rather than merely parseable?
- Can one delivery ID arrive with different payload bytes, and how is that conflict retained?
- What durable write must commit before returning success?
- What happens if authentication succeeds but the admission store is unavailable?
- Can the endpoint finish admission inside the response budget at peak load?
- How does a worker derive a semantic operation identity from duplicate or related deliveries?
- Which system is authoritative for the downstream effect after a lost response?
- How long can provider retries or manual redelivery continue?
- Which sensitive fields must never enter logs, traces, dead-letter records, or diagnostics?
Use evidence states instead of one webhook_processed flag
- Received unverified: request bytes exist transiently; no provider claim is trusted.
- Rejected unauthenticated: verification failed under a named key version and policy; no business processing is permitted.
- Rejected unsupported: authenticity passed, but the event type, action, or schema is not admitted.
- Conflicting identity: an existing delivery identity has a different immutable fingerprint; automatic processing stops.
- Admitted: the authenticated delivery and minimized processing reference committed durably.
- Duplicate admitted: the same delivery identity and fingerprint map to the existing admission result.
- Response unknown: admission committed, but the connection ended before the response outcome was observable.
- Processing reserved: one fenced worker owns the semantic operation attempt.
- Effect indeterminate: an attempt may have committed, but authoritative lookup cannot establish the result.
- Effect confirmed: the named business effect and stable evidence identifier are durable.
- Terminal processing failure: policy forbids further automatic attempts and preserves a bounded reason.
Do not collapse admitted, response unknown, and effect confirmed. A provider retry after a lost response should converge on the existing admission record. A worker retry after a lost downstream response should reconcile the effect rather than blindly repeat it.
A compact webhook-admission card
The card keeps response-path evidence separate from business-effect evidence: authenticate and authorize the delivery, then commit its durable admission before returning success. An unknown downstream result still belongs in authoritative reconciliation rather than blind replay. Use the contextualized note—not the diagram alone—to define provider-specific response semantics, retry behavior, identity scope, retention, and privacy limits.
Keep the synchronous path narrow
A proposed endpoint sequence:
- Capture the raw body under a strict size limit without logging it.
- Identify the configured endpoint and candidate verification-key versions without trusting unsigned payload fields.
- Verify the signature and provider time policy against the exact required bytes.
- Parse the authenticated envelope with bounded depth, field count, and supported schema versions.
- Allowlist the event type and action; reject or quarantine unsupported authenticated events explicitly.
- Derive the scoped provider delivery identity and an immutable payload fingerprint.
- Atomically insert the minimized admission record or return the existing matching record.
- If the identity exists with a different fingerprint, retain a conflict and do not process either as an ordinary duplicate.
- Return the contract’s successful status only after durable admission commits.
- Let a separate worker reserve the semantic operation, perform or reconcile the effect, and record authoritative result evidence.
Do not place unrelated API calls, email sends, report generation, or full business workflows before the admission response. Do not return success merely because an in-memory task was spawned. Conversely, do not hold the provider connection open until every downstream effect finishes when the declared contract only promises durable admission.
Authentication is not business authorization
A valid provider signature can establish that the signed material passed the configured provider-verification procedure. It does not establish that every authenticated event type is supported, that the referenced account may trigger the requested local operation, or that a replayed but still valid envelope should bypass current policy.
Apply business authorization only after authentication, bounded parsing, and contract classification. Bind the decision to local facts such as the configured endpoint, installation or tenant mapping, accepted event type and action, schema version, object ownership, and current workflow state. Do not use unsigned routing fields to choose the verification secret, and do not let a generic “signature valid” branch dispatch arbitrary event names into privileged handlers.
Retain the distinction in evidence. authenticated should name the verification scheme and key version; authorized_for_admission should name the local contract version and allowlisted route. An authenticated but unsupported event can then be rejected or recorded as an accepted no-op without being mislabeled unauthenticated, admitted for effect execution, or successfully processed.
Test the boundary with a correctly signed event for the wrong endpoint mapping, tenant, action, object owner, and schema version. The expected result is a bounded authorization or contract rejection before durable effect work—not a signature error and not an ordinary successful admission.
Decide the response from current evidence
| Current evidence | Response decision | Next safe action |
|---|---|---|
| Raw body exceeds the declared bound | Do not admit. Return the provider-appropriate failure status. | Retain only minimized rejection evidence. |
| Signature missing, malformed, expired under policy, or invalid | Do not admit or process. | Record a bounded authentication failure without payload or secret material. |
| Signature valid; event type or schema unsupported | Do not process as a supported effect. | Apply the documented rejection or accepted-no-op policy; make the choice explicit. |
| Delivery identity is new; durable insert commits | Return the configured success status. | Worker may claim the admitted item asynchronously. |
| Same identity and same immutable fingerprint already admitted | Return the same successful admission outcome. | Point to existing processing state; do not create another admission item. |
| Same identity but conflicting fingerprint | Do not treat it as an ordinary duplicate. | Preserve conflict evidence and stop automatic effect execution. |
| Authentication passes but admission store is unavailable | Do not claim successful admission. | Fail within the response budget so provider-specific retry or operational recovery can act. |
| Admission commits but connection outcome is unknown | Do not delete the admission record. | A retry should converge on it; report response state as unknown. |
| Business effect later fails | Do not revise historical admission into “never received.” | Use the processing retry, terminal, or reconciliation lane. |
| Effect response is lost and authoritative lookup is unavailable | Do not blindly repeat or mark complete. | Enter the indeterminate lane until reconciliation can distinguish outcomes. |
The exact HTTP status is provider-specific. A general-purpose table cannot replace each provider’s documented interpretation of 2xx, 4xx, timeouts, retries, and manual redelivery.
Proposed minimized evidence record
provider_endpoint_and_contract_version
delivery_id_and_event_type
schema_version_and_supported_action
raw_body_size_and_payload_fingerprint
signature_scheme_and_key_version
verification_result_and_time
admission_record_or_queue_id
admission_commit_time
response_attempt_status_and_time
response_outcome_known_or_unknown
duplicate_or_conflict_result
semantic_operation_key
worker_owner_and_fencing_version
effect_attempt_and_authoritative_result_id
processing_status_and_transition_times
retry_dead_letter_or_indeterminate_reason
retention_expiry
Do not retain signing secrets, authorization headers, full payment details, session tokens, or unrestricted payload copies in this record. If raw payload retention is necessary for processing or replay, isolate it behind narrow access controls, encryption, an explicit retention period, and references from the minimized ledger.
Failure-shaped test matrix
| Test | Expected evidence | Failure exposed |
|---|---|---|
| Modify one raw-body byte after signing | Verification fails before parsing drives business behavior. | Framework body transformation breaks or bypasses verification. |
| Sign with the previous key during a planned rotation window | The declared active key set accepts it and records the correct key version. | Rotation causes silent loss or indefinite acceptance of revoked keys. |
| Send a valid signature with an unsupported event type | State is rejected-unsupported or accepted-no-op exactly as contracted. | Authenticated input is mistaken for authorized processing. |
| Deliver the same ID and identical fingerprint concurrently | One admission record commits; all contenders converge on it. | Duplicate deliveries create duplicate queued work. |
| Reuse one delivery ID with changed immutable fields | State becomes conflicting identity and no automatic effect runs. | Deduplication hides a materially different payload. |
| Stop the admission store after authentication | No successful admission response is claimed. | 2xx is returned before durable responsibility exists. |
| Kill the endpoint after admission commit but before response flush | Retry finds the existing record and does not enqueue again. | Lost response creates duplicate admission. |
| Delay the asynchronous worker beyond the provider response deadline | Endpoint still responds from admission state; processing lag remains visible. | Business processing is coupled to provider timeout. |
| Deliver related business events out of order | Semantic processing waits, reconciles authoritative state, or records a bounded gap. | Arrival order is treated as business order. |
| Lose the downstream effect response after commit | Worker enters indeterminate state and queries authoritative evidence before replay. | Delivery deduplication is mistaken for effect idempotency. |
| Expire delivery evidence before a late manual redelivery | Admission reports the retention gap instead of silently treating it as new. | Deduplication horizon is shorter than redelivery risk. |
| Fill the queue or exceed admission-store capacity | Endpoint sheds or fails according to contract before claiming admission. | Queue buffering hides an unavailable handoff. |
| Inject oversized, deeply nested, or high-field-count authenticated JSON | Parser limits reject safely within resource budgets. | A valid signature grants unbounded resource use. |
| Put a secret or sensitive field in the payload | Logs, traces, and rejection records omit it. | Diagnostics become a second uncontrolled data store. |
| Make a failed provider delivery where automatic redelivery is unavailable | A bounded operational signal remains; no fictitious retry is reported. | One provider’s retry assumptions are applied to another. |
Every passing result is bounded to the provider configuration, endpoint contract, verification library, framework body handling, active key versions, admission store, worker implementation, retention period, and observation window used in the test.
Compact checklist
Before accepting webhook traffic:
- Pin the provider, endpoint configuration, event types, actions, and schema versions.
- Preserve the exact bytes required by the provider’s signature procedure.
- Enforce body-size, parse-depth, and resource limits before expensive work.
- Version verification keys and test planned rotation and revocation.
- Treat successful authentication as origin evidence, not business authorization.
- Scope the provider delivery identity correctly.
- Bind the identity to an immutable payload fingerprint.
- Make duplicate admission atomic.
- Stop conflicting identity reuse rather than inheriting an old result.
- Commit a durable admission record before returning success.
- Keep the synchronous path inside a measured provider-specific budget.
- Move business effects to a separately observed worker contract.
- Separate delivery deduplication from semantic effect idempotency.
- Fence concurrent workers that can overlap.
- Reconcile authoritative effect state after a lost downstream response.
- Preserve response-unknown and effect-indeterminate states.
- Test queue or admission-store unavailability and capacity exhaustion.
- Test duplicate, concurrent, delayed, and out-of-order deliveries.
- Document whether failed deliveries are automatic, manual, or unavailable for retry.
- Retain admission evidence through the full retry and redelivery horizon.
- Minimize payload retention and keep secrets out of evidence.
- Report admitted, processing, confirmed, terminal, and indeterminate work separately.
A useful operational statement is narrow: delivery D passed provider verification under key version K, matched supported contract C, and committed to admission record Q before the endpoint attempted response R. Processing later produced effect evidence E—or remains pending, terminal, or indeterminate.
That statement does not promise exactly-once delivery or exactly-once effects. It makes the endpoint’s responsibility boundary explicit enough to test, monitor, and recover.