Skip to content
Moosewave
Demo
Transactional email & event reliability

A webhook tells you what happened, not what is true now.

The same event may knock twice, and yesterday’s fact may arrive after today’s. Reliable systems preserve the evidence before deciding what it means now.

By Moosewave

Published · 10 min read

Several webhook delivery attempts converge on one verified event record before updating separate delivery, safety, and engagement states.
Several deliveries can carry one event. Record the evidence once, then update each kind of state deliberately.

Share this article

The short version

Store the fact before you act on it.

An email webhook is an HTTP notification about an event such as delivery, delay, complaint, unsubscribe, open, or click. It is not a live copy of current message or recipient state.

  • 01Verify the sender against the original request bytes before parsing the payload or changing anything.
  • 02Record a stable source and event ID durably, then return success without waiting for every downstream workflow.
  • 03Expect valid retries and surprising arrival order; make both the handler and each business effect idempotent.
  • 04Build transport, safety, and engagement views from the event log, then reconcile important records with the source.

The outward half of this contract is explained in A retry is not permission to send twice.

One conversation contains four different things

Your application requests an order receipt. The email API accepts it. Later, an email service observes delivery and calls your webhook endpoint. If the response disappears, it calls again. The two HTTP requests look like two things happening. They may be two attempts to report one thing.

This is the mirror image of uncertainty on the send path. A stable idempotency key stops repeated API attempts from becoming repeated email. A stable event identity stops repeated webhook attempts from becoming repeated workflow changes. Both are needed because a network can lose an acknowledgement without losing the work it acknowledges.

Occurrences, events, delivery attempts, and projections
ObjectMeaningExample
OccurrenceA fact observed in a systemA receiving server accepted the message
EventA record describing that factdelivery.completed / evt_71
Delivery attemptOne transport attempt carrying itPOST number 1, 2, or 3
ProjectionThe current view derived from factsRecipient transport: delivered

CloudEvents makes the distinction explicit: an event is a record of an occurrence, and one occurrence can yield more than one event. It defines source plus id as the event identity. Neither an HTTP request ID nor a hash of the whole payload is a universal substitute for the provider’s documented identity.

The webhook is a delivery mechanism for evidence. It is not the database where truth lives.

Make the receiver boring and fast

A webhook endpoint should do a small amount of important work. It should prove who sent the request, preserve what was sent, and make later processing possible. Rendering a report, updating six systems, or sending another message can happen after the provider connection has closed.

  1. 01

    Preserve the original bytes

    Signature schemes commonly cover the request body exactly as sent. Parsing and re-serialising it first can change the bytes required for verification.

  2. 02

    Verify source and recency

    Use the provider's signature header, endpoint secret or public key, and replay-window rules. Reject invalid requests before any side effect.

  3. 03

    Insert one immutable event

    Store workspace, source, event ID, type, schema version, occurrence time, message and recipient identity under a unique constraint.

  4. 04

    Enqueue, then acknowledge

    Commit a processing intent with the event, or make the durable queue the capture boundary, then return 2xx. A valid duplicate can receive the same success.

webhook receiver / pseudocodeverify · persist + schedule · acknowledge
raw = request.body_bytes
verify(raw, signature, timestamp)
event = decode(raw)

transaction:
  created = events.insert_once(
    key = [workspace, event.source, event.id],
    envelope = event
  )
  if created: outbox.insert_once(event.id)

return 204

A relay publishes committed outbox rows to the worker queue. This closes the crash gap between storing the event and scheduling its processing; a durable queue can serve as the same boundary when its write is the first committed record.

Stripe documents automatic retries, duplicate events, unordered delivery, signature verification, asynchronous queues, and prompt successful responses. GitHub similarly recommends a quick 2xx and a processing queue. Exact timeout and signature formats differ, but the boundary remains: authenticate and capture before acknowledging; do expensive work later.

Keep endpoint secrets scoped and rotatable, map each event to the correct workspace, and retain an audit trail. Those controls belong beside the isolation boundaries on the Moosewave security page.

Deduplicate twice

The first deduplication answers a transport question: have we recorded this event before? A unique constraint on source and event ID makes that decision atomic. Two workers can race and still leave one record.

The second answers a product question: has this effect already happened? Recording evt_71 once does not help if a worker suppresses a recipient, publishes a notification, and crashes before marking the job complete. A retry can run the business action again.

Event key
workspace + provider source + provider event ID
Projection key
message + recipient + projection version
Effect key
business action + stable source fact
Replay result
the existing outcome, not a second effect

Where possible, commit the state change and effect record in one transaction. When the effect lives elsewhere, use a durable inbox or outbox and give the next operation its own idempotency key. AWS advises idempotent event consumers because duplicate processing can occur in managed systems.

Do not discard every similar payload as a duplicate. Stripe notes that separate event objects can sometimes describe the same object change. Preserve both records, then make the domain effect safe using documented object, event-type, recipient, and revision fields.

Arrival order is not event order

Webhooks travel on different schedules. An endpoint outage can leave one event in retry while a newer event succeeds on its first attempt. The HTTP arrival time describes your connection, not the chronology of the customer’s experience.

10:02

Occurred

Message accepted

10:05

Occurred

Recipient complained

10:08

Arrived first

Acceptance retry

10:09

Arrived second

Complaint event

10:11

Arrived late

Older delivery event

Now

Current decision

Remain suppressed

Shopify states that it does not guarantee ordering within or across webhook topics and recommends event timestamps. Timestamps help, but they are not the whole policy. Prefer a documented provider sequence when one exists. Otherwise use occurrence time, stable subject identity, and explicit domain rules.

A later arrival should add evidence, not overwrite a row blindly. If facts conflict, retain both, flag the projection, and reconcile with the source. This is how connected integrations exchange events without turning delivery order into customer state.

Email has several states, not one status

The label “sent” compresses too much. A request can be accepted while transport is delayed. A receiving server can accept a message without placing it in the inbox. A person can complain after delivery. An open or click is an observation, not permission to erase a safety decision.

Separate state lanes for email webhook events
LaneTypical evidenceSafe rule
Requestaccepted, attempting, rejected, unknownDo not infer mailbox delivery
Recipient transportdelayed, delivered, permanently failedProject per recipient
Recipient safetycomplaint, unsubscribe, durable suppressionLate transport cannot restore eligibility
Engagement evidenceopen and click observationsAppend evidence; do not upgrade permission

Amazon SES documents these as different event families and identifies which recipients each event applies to. It defines delivery as handoff to the recipient’s mail server. That remains different from inbox placement and human action, as our guide to email delivery evidence explains.

Safety state deserves its own durable lane. A late open or delivery must not reverse an unsubscribe or complaint. The same principle underlies reliable unsubscribe handling. An event can trigger an action, but current eligibility decides whether an automation should continue.

Use webhooks for speed and reconciliation for repair

A webhook can still be missed. Your endpoint may be down until a retry window ends. A schema change may move an event into quarantine. A worker may exhaust its attempts. Treat replay and reconciliation as ordinary design, not emergency procedures added after the first gap.

Shopify recommends reconciliation jobs because webhook delivery should not be the only path to consistency. For important transactional email, compare unresolved records with the provider or source API. Rebuild projections from the durable event log. Replay a failed event without inventing a new identity.

Queue lag
How long valid events wait before processing.
Oldest unresolved
Whether one stuck event hides behind a healthy average.
Duplicate rate
How often retry traffic reaches the receiver.
Signature failures
Invalid, stale, or misconfigured deliveries.
Projection conflicts
Facts the state rules cannot resolve automatically.
Reconciliation drift
Facts at the source but absent from the local log.

Good email analytics begin with this separation between raw observation and derived view. Reports can change when better evidence arrives without rewriting the event that arrived first.

The product consequence

Moosewave connects the original application event, the transactional message identity, each authenticated webhook event, and the current recipient projection. Duplicate deliveries resolve to the existing event record. Processing happens behind a durable boundary, so a quick response does not require hurried business logic.

Message history keeps request, transport, safety, and engagement evidence distinct. A stronger safety fact cannot be erased by an older delivery event arriving late. Ambiguous records remain visible for replay or reconciliation instead of becoming a reassuring but false status.

Explore the contract on the Moosewave transactional email API page. See how commerce, CRM, support, and custom webhooks enter through the integration layer, then follow audience, automation, message, and evidence through the connected ecosystem.

Open the interactive product walkthrough to see that history move across the workspace. A reliable webhook system is not one that never sees repetition or disorder. It is one that sees both without changing what is true.

Frequently asked questions

Direct answers about email webhooks, duplicate delivery, event order, signatures, acknowledgements, and recovery.

What is an email webhook?

An email webhook is an HTTP notification sent when an email service observes an event such as delivery, delay, bounce, complaint, unsubscribe, open, or click. It describes an occurrence; it is not automatically a complete or current view of the message or recipient.

Can the same email webhook arrive more than once?

Yes. A provider may retry because it did not receive a successful response, even when your endpoint already stored the event. Give each source event a stable identity, store it under a unique constraint, and acknowledge a valid duplicate without repeating its effects.

Are email webhook events delivered in order?

Do not assume so unless the provider explicitly guarantees ordering for that event stream. Network retries, separate processing paths, and endpoint downtime can change arrival order. Use provider sequence data or occurrence times when available, plus domain rules and reconciliation.

When should a webhook endpoint return a 2xx response?

Return success after the request has been authenticated and the event has been captured durably or placed on a durable queue. Do not hold the connection open for every downstream workflow. Invalid signatures should be rejected, while already-recorded valid events can be acknowledged successfully.

How should an email webhook signature be verified?

Follow the provider's exact verification contract. It commonly requires the original request bytes, a signature header, an endpoint secret or public key, and a timestamp or replay window. Verify before parsing or performing a side effect, use HTTPS, and rotate secrets deliberately.

What is the difference between API idempotency and webhook idempotency?

API idempotency keeps repeated send requests from creating repeated emails. Webhook idempotency keeps repeated event deliveries from creating repeated state changes, notifications, or workflow actions. They protect opposite directions of the same distributed conversation.

How do you recover a missed webhook event?

Keep a replayable event log, expose failed deliveries, and periodically reconcile important records against the provider or source API. Webhooks provide timely notification; reconciliation repairs gaps caused by downtime, exhausted retries, schema errors, or application failures.

Sources & method

Event and webhook references

Official specifications and provider documentation support the event-delivery and email-event claims. The state model and product recommendations are Moosewave’s synthesis.

Last reviewed 9 August 2026. Webhook contracts, retry windows, and signature procedures vary; verify the documentation for every provider you connect.

Continue reading

Make the command safe before reading its events

The previous field note explains the other half of the conversation: why every retry of one transactional send must preserve one message identity.

From field note to next move

Turn the question into a reviewable plan.

Give Moosewave the outcome you want. The goal carries into a guided workspace with its scope, approval points, and evidence still attached.

Journal handoffGuided workspace · no live actions
Enter to preview · Shift + Enter for a new line

Opens a guided workspace. Nothing is sent or changed.

  1. 01UnderstandQuestion and evidence
  2. 02PlanScope and exclusions
  3. 03ApproveExact proposed action
  4. 04VerifyResult and receipt
Keep the evidence intact

Make every email event explainable.

Explore the connected product, then request Moosewave access and updates.