Webhook delivery handling
Put a durable inbox behind the webhook endpoint
Store verified event identity and processing state before returning success. Let workers handle slow business logic without losing the ability to retry.
In this article
Bound and verify the incoming request
Apply appropriate method and size limits before expensive processing. Preserve the raw body required by the provider's signature scheme and use its supported verification library where available.
Resolve the endpoint secret and expected account context through trusted configuration. Do not allow untrusted payload fields to select arbitrary verification authority.
Reject invalid signatures without logging secret material or unnecessary payload content.
Insert one receipt record
Store the verified event under a unique identity scoped to its provider and relevant account. Use a database constraint or equivalent atomic mechanism so concurrent duplicates cannot both create independent receipt records.
INSERT INTO webhook_inbox (
provider, account_id, event_id, received_at, state
)
VALUES (
:provider, :account_id, :event_id, :received_at, 'pending'
)
ON CONFLICT (provider, account_id, event_id) DO NOTHING;This illustrative receipt schema omits payload storage and worker ownership details. The actual design needs the verified data or a reliable reference required for later processing, protected according to its contents.
Return the provider-appropriate success response only after durable acceptance is established. An already accepted duplicate can follow the same acknowledgement policy.
Make worker discovery reliable
A database inbox can be polled directly or connected to a durable notification mechanism. Avoid creating a new gap where the row commits but an unrecorded queue notification is lost.
Claim work with a concurrency policy and a recoverable lease or state transition. A crashed worker must not leave the event permanently invisible.
Keep attempt count and next eligible time separate from final business outcome.
Protect the processing effect
Where the effect is local, commit it and the relevant processed marker together when the storage model allows. For an external effect, use the appropriate operation identity and reconciliation path.
Test a worker crash after the effect but before completion recording. The inbox should not cause a duplicate action on retry.
The receiver and worker form one recovery design. A durable inbox fixes receipt loss, but it does not automatically make every downstream operation exactly once.
Primary sources
GitHub: webhook best practicesPostgreSQL: INSERTReferences checked 11 September 2026.