A webhook is a notification that something happened elsewhere. It is not a guarantee that the event is new, that it arrived in order, or that the rest of your application has already processed the same change. A dependable bidding integration treats delivery as an input to a controlled state transition, not as permission to repeat a business action.
Consider an auction result arriving twice while a purchase confirmation is still being reconciled. A naive handler might send duplicate messages, create two records, or attempt the next action twice. A better design identifies the event, verifies its source, records it durably, and applies the intended effect only when the relevant state transition is valid.
This article proposes an event-processing architecture for your own integration. The webhook reference contains an example envelope, and the data model explains how event identity differs from command and asset identity.
Separate delivery from the business event
A delivery is one attempt to send a notification. An event is the underlying occurrence described by that notification. The same event can have multiple delivery attempts. Your application may also receive different events that concern the same order or listing. Those identifiers should not be collapsed into one generic request ID.
The Stripe webhook documentation explicitly addresses duplicate deliveries, signature verification, and the fact that events are not guaranteed to arrive in order. That is a concrete provider example, not a claim that every marketplace uses Stripe’s protocol. For each adapter, record the actual event identifier, signature rules, retry behavior, and available reconciliation endpoint from its own documentation before building a shared consumer.
Verify before trusting the payload
A request reaching your endpoint does not establish that it came from the expected provider. Follow the provider’s documented verification process, including how it signs the request and which exact bytes are covered. Some mechanisms require the unmodified request body, so parsing and reserializing first can invalidate an otherwise genuine signature.
Reject verification failures without attempting the business action. Keep a small amount of safe diagnostic information, but do not log secrets or complete sensitive payloads by default. Plan for signing-secret rotation using the provider’s supported process. Where timestamps are part of verification, apply the documented tolerance and keep server clocks reliable. Do not invent a universal signature header or algorithm and assume every upstream service implements it.
Persist an inbox before acknowledging
A useful application pattern is to store the verified event in a durable inbox, then acknowledge delivery promptly after that write succeeds. A worker can process the event separately. This avoids making the provider wait for every downstream task while still preserving the event if a later step fails.
The acknowledgement must reflect what your system actually achieved. If the inbox write failed, reporting success can lose the event unless another recovery path exists. If the write succeeded and the event is already known, an acknowledgement can avoid unnecessary repeated processing. Decide how the provider’s timeout interacts with your storage operation and test the slow path. An architecture diagram is incomplete until it explains what happens when the database is unavailable at the exact moment a valid event arrives.
Deduplicate at the right scope
Use a uniqueness rule that matches the provider’s identity model. An event identifier may need to be scoped to the provider and account or tenant. Store processing status separately from receipt status so an event can be durably received but still awaiting its business effect.
Make the duplicate check atomic
A duplicate check followed by an unrelated write is not enough when two workers can race. Use a database constraint or transactional claim appropriate to the storage system. The intended outcome is that only one worker owns the relevant processing transition. A duplicate event should not create another purchase, repeat a transfer step, or issue another customer-facing notification merely because the second delivery reached a different server. Test this with concurrent deliveries, not only sequential replay.
Protect the business effect as well as the event
Deduplicating a notification does not automatically make every downstream side effect idempotent. A worker can update local state, call another service, and crash before recording completion. On restart, it may repeat the external call unless that action has its own stable identity and recovery path.
A proposed solution is to record intended outgoing work in a transactional outbox alongside the local state change. A separate worker sends the work using the destination’s documented idempotency mechanism where available. If the destination cannot support safe retries, define a reconciliation or manual-review path for ambiguous results. The important design question is not “did this handler run once?” but “can the system prove that this particular business effect was applied at most as intended?”
Do not use arrival order as event order
An older event can arrive after a newer one. The processor should apply state transitions using the provider’s documented version, sequence, or authoritative resource state rather than simply overwriting the current record with the last payload received. A timestamp alone may not be sufficient to resolve every conflict.
For a fictional example, imagine receiving “order completed” and then a delayed “order acknowledged.” A blind last-write-wins update would move the record backwards. A transition rule can preserve completion and attach the delayed acknowledgement as history. When the available event data is insufficient to establish the current state, retrieve the authoritative resource through an approved endpoint. Reconciliation is often more reliable than trying to reconstruct certainty from incomplete notifications.
Bound retries and isolate failures
Not every processing error deserves the same response. A temporary database outage may justify a retry. A malformed event, unsupported schema version, or missing permission may require review instead. Classify failures and apply bounded retry schedules so one bad event cannot consume the entire worker fleet.
Use a dead-letter or review queue for events that cannot be processed automatically, with enough context to investigate safely. Monitor queue age as well as queue length. A small number of old events can matter more than a large number of fresh ones when they concern unresolved financial commitments. Keep the original verified event and the processing error associated, so a reviewer can understand the problem without reproducing it from an incomplete log message.
Design replay as an ordinary operation
A replay tool is useful after a bug fix, schema update, or temporary outage. It should use the same verification evidence, identity rules, and transition checks as normal processing. A replay must not bypass safeguards merely because an operator initiated it.
Record who requested the replay, which events were selected, and what outcomes changed. Separate a dry-run comparison from an actual state update where the workflow benefits from review. Do not turn replay into a general “run the action again” button. The goal is to apply any missing intended effects and reconcile records, not to repeat commitments that already succeeded. The rate-limit reference explains how to keep recovery requests from overwhelming an upstream provider.
Test the crash boundaries
Build tests for a duplicate event, an invalid signature, an unknown version, a delayed event, a failed inbox write, and a crash immediately before or after an external action. Inject concurrency so two workers attempt the same item. These tests reveal whether the design protects business meaning rather than only the happy-path response code.
A reliable webhook system makes receiving, processing, and acting three explicit stages. Verify the source, preserve the event, guard the state transition, and reconcile uncertainty. Then expose useful operational information: unresolved events, recovery state, and completed effects. That is how an asynchronous bidding integration stays understandable even when the network delivers the same news more than once.


