An export webhook tells another system that something changed: a file is ready, a job failed, or an artifact expired. The HTTP request is only the delivery mechanism. A reliable integration must also decide whether the message is authentic, whether it has already been handled, and whether the requested downstream action actually completed. Those decisions become especially important when the sender sees a timeout after the receiver has accepted an event.
Define the event contract first
Give every event an immutable event identifier, an event type, a schema version, an occurrence time, and the export job identifier. Include an artifact version when a job can produce corrected outputs. Prefer a compact message describing the change and pointing to an authenticated resource where the receiver can obtain current details. Avoid putting the exported dataset into the event itself. That reduces payload size and limits the places where sensitive data can accumulate.
Distinguish event identity from delivery attempt identity. One logical file-ready event may be sent several times, with a new attempt record for each transmission. Keep the event identifier unchanged. Separately identify the business operation, such as importing artifact version three into a particular destination. Two different events can occasionally describe the same business action, so deduplicating messages alone may not protect the final effect.
Assume delivery can repeat or arrive out of order
The Stripe webhook documentation provides a useful real-world example: it describes duplicate event delivery, does not guarantee event ordering, and recommends asynchronous handling. These are characteristics to check in any provider's contract rather than assumptions to hide inside a handler. Your export workflow should state its own retry horizon, ordering behavior, and acknowledgment meaning explicitly.
Imagine the receiver records a completed export and then loses its connection before returning a response. The sender sees an unsuccessful attempt and retries. The second request is legitimate even though the first one changed local state. Conversely, an earlier processing event might arrive after the ready event. A handler that blindly assigns the most recently received status could move a finished job backward and confuse the user.
Authenticate before accepting work
Require HTTPS and implement the sender's documented verification procedure with its maintained verification library where available. Preserve the raw request bytes when the signature scheme depends on them; parsing and reconstructing JSON can change the signed representation. Validate the endpoint identity and secret associated with the expected sender. Apply body size limits and reject malformed envelopes before allowing them to consume an unbounded amount of processing capacity.
If the signature includes a timestamp, use the scheme's replay tolerance and maintain accurate receiver time. Distinguish the signed delivery timestamp from the event's original occurrence time. A delayed but freshly signed retry can legitimately describe an older event. During secret rotation, define a limited overlap period and remove the retired secret afterward. Log verification outcomes without copying signatures, secrets, or sensitive payloads into general application logs.
Acknowledge durable acceptance
After verification, insert the event into a persistent inbox using a uniqueness constraint scoped to the sender and event identifier. Store the minimum information needed for processing and investigation. Return a successful acknowledgment only once the event is durably accepted under your chosen contract. If the storage transaction fails, return an appropriate failure so the sender can follow its retry policy. A message held only in process memory can disappear immediately after an apparently successful response.
A background worker should claim inbox records and execute downstream work. If you also publish to a queue, avoid the gap where the inbox commit succeeds but queue publication fails. One option is a transactional outbox record written alongside the inbox record, with a dispatcher that retries publication. Another is a worker that directly polls eligible inbox rows. Choose the design your team can operate and verify rather than adding a queue without a durable handoff.
Make the business effect idempotent
For a local database update, apply the change and mark the business operation completed in the same transaction. An example operation key might combine destination account, artifact identifier, and import version. A repeated event then finds the completed operation and returns the same outcome. Keep attempted, completed, and permanently rejected states distinct. Marking an event processed before its effect commits can suppress the retry needed to finish the work.
External side effects require another boundary. If processing calls a separate import service or sends a customer notification, pass a stable idempotency key when that service supports one. Otherwise, retain the uncertainty after timeouts and provide a way to reconcile the remote outcome. An event ledger does not create exactly-once behavior across unrelated systems. The export API pattern reference helps separate job state, artifact state, and delivery state in that design.
Choose bounded retries with room for recovery
Classify failures according to the receiving contract. A temporary capacity problem may recover without intervention; an invalid signature or removed destination usually needs a configuration change. Document which responses trigger retries, and honor retry guidance where the contract defines it. Use increasing delays with random variation so many failed deliveries do not return simultaneously. Set limits on attempts, elapsed time, and concurrent work for each destination.
As an illustrative policy, an internal reporting integration could retry after roughly one, five, and twenty minutes, then continue at wider intervals until a twelve-hour horizon. Those numbers are a design example, not a universal recommendation. Select the horizon from the reporting deadline and artifact retention period. After exhaustion, retain a recoverable failed record and alert the responsible owner. A manual replay should keep the original event identity and create a new attempt record.
Isolate events that cannot be processed
A verified event can still be unusable because its schema version is unsupported or a required business reference is missing. Move such work into an inspectable quarantine state instead of retrying it forever at the front of the queue. Record the reason, the handler version, and enough safe metadata for an operator to decide whether deployment, configuration, or producer correction is needed.
After fixing the cause, replay selected records through the normal processing path. Preserve the original event and business operation identities so the repair does not bypass deduplication. Limit replay concurrency and observe the results before releasing a large backlog. A recovery tool should explain which records it will retry and should avoid automatically regenerating files merely because a completion event previously failed to process.
Prevent stale events from changing newer results
Use explicit transition rules or a monotonic version supplied by the event producer. If artifact version four is current, a delayed event for version three should not overwrite it. When ordering cannot be resolved from the envelope, fetch the authoritative job resource using the receiver's credentials. Avoid treating occurrence timestamps alone as a total ordering mechanism, especially when multiple changes can share a timestamp or clocks differ across components.
A file-ready event also does not guarantee that its download link remains valid when a worker finally handles it. Prefer retrieving a fresh authorized download capability when processing begins. If the artifact has been deleted or access has been revoked, record that outcome and stop retrying the same expired link. Read the guide to secure export delivery for the distinction between artifact retention and link lifetime.
Test acknowledgment gaps and operator actions
Test the failures that cross state boundaries. Terminate the receiver after committing the inbox but before responding. Terminate the worker after the business transaction but before acknowledging the queue. Replay an older event after a newer version, and send two matching events concurrently. Verify that each test creates the expected inbox attempts while preserving one intended business outcome. Test an exhausted delivery and its manual replay as carefully as the happy path.
Retention is part of correctness. If you delete deduplication records before the sender's replay window closes, an old event can become new work again. Decide how long to retain operation identities separately from full payloads. The former may need to last longer and can often contain less sensitive information. Record enough provenance to show why an event was ignored, retried, rejected, or applied.
Make reliability visible to the people using it
Track acceptance latency, processing latency, retry counts, exhausted destinations, and the age of pending work. Show operators the event identifier, artifact version, and last actionable error. Give customers precise status language: accepted by receiver, import completed, or delivery needs attention. The scheduled export guide places these events within recurring reporting obligations. A webhook becomes dependable when repeated requests are ordinary, state changes are controlled, and uncertain outcomes have a clear recovery path.



