Skip to content

This term

Webhook Event Ordering

Why WhatsApp webhooks arrive out of order — a read before its delivered, a reply before its status — and how to sequence events by timestamp and status rank.

Also called: Out-of-order webhooks · Webhook sequencing · Status precedence · Webhook ordering

Often confused with

Statuses Webhook

Status webhooks report what happened to each message you sent — sent, delivered, read, played or failed — keyed by its wamid, with pricing and error details.

Read the Statuses Webhook entry

Arrival order versus what really happened

6 / 6

11:22:30Event 6 of 6

Old message after an outage

A customer message timestamped 10:58 arrives behind newer events after a short outage. Place it by timestamp, and skip an auto-reply if an agent has already resolved the chat.

Six webhooks in the order they reached the server, each with its own event timestamp. Step through to see how status rank and timestamps rebuild the true sequence.

Event 6 of 6: 11:22:30 — Old message after an outage. A customer message timestamped 10:58 arrives behind newer events after a short outage. Place it by timestamp, and skip an auto-reply if an agent has already resolved the chat.

What is webhook event ordering?

Webhook event ordering is the work of putting WhatsApp events back into the order they happened, because Meta does not guarantee the order in which webhooks reach you. Each event is delivered on its own, a delivery that fails is retried later under the webhook retry policy while newer events carry on, and events about the same message come from different parts of the platform. Arrival order is therefore not event order: a read status can arrive before the delivered for the same WhatsApp message ID (wamid), a customer's reply can land before the read status of the message they are answering, and a retried event from an hour ago can turn up behind dozens of newer ones.

Two signals let you rebuild the true sequence. Every message and status carries a timestamp — Unix seconds, sent as a string — recording when the event was triggered on Meta's side rather than when it reached you; with one-second resolution, ties are common. And statuses have a natural precedence: sent, then delivered, then read (and played for voice messages), with failed replacing only a message that never got further than sent. Meta's reference also notes that no delivered webhook is sent when a message is read immediately, because the read implies delivery — so a missing delivered is normal.

The working rule is to merge, never overwrite: store each event, derive the current message status, and only ever move a message forward. That is different from webhook deduplication, which removes repeats of the same event; ordering puts distinct events into the right sequence. It also differs from outbound message ordering, which is about the messages you send reaching the customer in the order you intended.

Key takeaways

  • Webhook event ordering is rebuilding the true sequence of WhatsApp events when they reach your server out of order.
  • Meta does not guarantee delivery order, and a retry can deliver an old event hours or days after newer ones.
  • Rank statuses sent, delivered, read, played, and only ever move a message forward; failed replaces only sent.
  • No delivered webhook is sent when a message is read immediately, because the read implies delivery.
  • Sequence by the event's own timestamp (Unix seconds, sent as a string), not by when it reached your server.

Common mix-ups

Common mistakes with webhook event ordering

  • Last write wins

    Writing the most recently arrived status turns read back into delivered whenever a retry lands late. Compare ranks before changing the status.

  • Sorting by arrival time

    Received-at reflects your network and Meta's retries, not the customer. Sequence by the event's own timestamp, with rank as the tie-breaker.

  • Expecting delivered before every read

    Meta skips the delivered webhook when a message is read immediately. Reports that require both undercount deliveries; infer delivery from the read.

  • Processing one customer in parallel

    Two workers handling the same customer's messages at once can answer them out of order. Partition by customer so their events are processed one at a time.

How does webhook event ordering work?

  1. Step 1

    Store events, derive state

    Keep an append-only record of each event from the statuses webhook and every inbound message, then compute the current state from it. You can always recompute; you cannot undo an overwrite.

  2. Step 2

    Rank statuses and only move forward

    Give each status a rank — sent 10, failed 15, delivered 20, read 30, played 40 — and change the stored status only when the incoming rank is higher. A late delivered after a read updates nothing but its timestamp.

  3. Step 3

    Fill gaps from stronger evidence

    A read implies delivery. Set delivered_at provisionally from the read and let a later, earlier-timestamped delivered correct it by keeping the earliest time seen.

  4. Step 4

    Sequence inbound messages per customer

    Process one customer's events in timestamp order — partition queues by customer ID — and use context.id on a reply to link it to the message it answers.

  5. Step 5

    Treat very late events as history

    Retries can arrive hours or days later. Record them in the right place on the timeline, but do not fire time-sensitive side effects, such as an auto-reply, for a conversation that has moved on.

Webhook event ordering in code

const RANK = { sent: 10, failed: 15, delivered: 20, read: 30, played: 40 };
export function mergeStatus(current, event) {
const at = Number(event.timestamp) * 1000; // Unix seconds, sent as a string
const next = { ...current };
if (["delivered", "read", "played"].includes(event.status))
next.deliveredAt = Math.min(current.deliveredAt ?? Infinity, at); // read implies delivered
if (["read", "played"].includes(event.status))
next.readAt = Math.min(current.readAt ?? Infinity, at);
if ((RANK[event.status] ?? 0) > (RANK[current.status] ?? 0)) {
next.status = event.status; // only ever move forward
next.statusAt = at;
}
return next;
}

Higher rank wins the status; the earliest timestamp wins each milestone.

Example: Flickering ticks at a Bengaluru grocery app

A Bengaluru grocery-delivery app's agents complained that order-update messages showed blue ticks, then grey ones a moment later. The status handler wrote whatever arrived last, and delivered webhooks retried after brief endpoint hiccups were landing after the read. The team added a status rank and stored the earliest timestamp per status, so a late delivered now only corrects delivered_at. The flicker stopped, and the weekly read-rate report rose by a few points because reads were no longer being overwritten (figures illustrative).

Webhook event ordering: key facts and limits

Delivery order
Not guaranteed by Meta
Event timestamp
Unix seconds, as a string
Status precedence
sent → delivered → read → played
failed
Replaces sent only
Delivered when read instantly
Not sent; the read implies it
Latest a retry can arrive
Up to 7 days after the event

Why the difference matters

Why does webhook event ordering matter?

Order mistakes are visible to everyone. Agents watch a read receipt turn back into a delivery receipt — blue ticks going grey — read-rate reports undercount because a late delivered overwrote a read, SLA timers start from the wrong moment, and a chatbot answers an older question after a newer one has been handled. None of it throws an error, so it surfaces as distrust in the numbers. A small amount of sequencing logic — a rank per status and a timestamp per event — makes every dashboard and conversation view consistent however the webhooks arrive.

Webhook Event Ordering FAQs

Does Meta guarantee webhook order?+
No. Events can arrive in any order, and retries can deliver an old event long after newer ones, so your code must sequence them itself.
Why did I get read but never delivered?+
When a message is read immediately, Meta does not send a separate delivered webhook — the read implies delivery. It can also mean the delivered event is still being retried.
Is webhook ordering the same as deduplication?+
No, they solve different problems. Deduplication drops a second copy of the same event; ordering places different events, such as a delivered and a read, in the sequence they happened. Run deduplication first, then the merge.
Can I rely on timestamps alone?+
Not entirely. They have one-second resolution, so several events can share a timestamp. Use the status rank to break ties for statuses and arrival order as a last resort.

Rules of thumb

Best practices for webhook event ordering

  • Keep both the event timestamp and the received-at time; the gap between them is your best measure of webhook lag.
  • Run ordering after deduplication, so repeats never reach the merge logic.
  • Test with a shuffled replay of real payloads — if the final state differs from the in-order replay, the merge logic has a bug.

See InfiQ pricing

Try it on the official WhatsApp Business API

InfiQ is an official Meta Business Partner. Start a 7-day free trial — no card needed — and see this running on your own number.