Delivery, Retries & Idempotency

WHCC webhook delivery is at-least-once, not exactly-once. Your endpoint has to handle two things correctly: responding fast enough to avoid self-inflicted retries, and treating duplicate deliveries as normal rather than exceptional.

Deduplicate on ConfirmationId + SequenceNumber + event type

Every notification carries a ConfirmationId and a SequenceNumber — top-level JSON fields on V2, top-level form fields (also inside the json payload) on V1. WHCC may send the same notification more than once, so your handler has to be idempotent. But the key matters, and so does what you do when it repeats.

Use all three parts of the key. A ConfirmationId is not unique to one order. When WHCC splits an order across shipments or production paths, the resulting orders share a ConfirmationId and are told apart by SequenceNumber (for example "1" and "1.2") — each with its own OrderNumber and its own tracking. Keying on ConfirmationId + event type alone will silently discard the second half of every split order.

A repeat is not always a no-op. Even with the full key, a later delivery can carry more data than the earlier one — most commonly a Shipped notification re-sent moments later with additional tracking numbers as more packages are scanned. Treat a repeat as a reconcile, not a discard: re-apply the payload so the newer content wins, and make the side effects (emails, downstream syncs) fire only on genuinely new information.

Duplicates are structural, not exceptional:

  • WHCC may POST your endpoint successfully, then fail to record that the delivery succeeded, and send it again.
  • A delivery interrupted part-way through — by a restart or a crash — is re-sent, because from WHCC's side it never completed.
  • Multi-item shipments and repeated voids can produce repeated notifications for the same order upstream, before delivery even begins.

None of these are bugs. Key on (ConfirmationId, SequenceNumber, event type), reconcile rather than drop, and repeats become harmless.

Response timeout

Your endpoint has 100 seconds to return a response once WHCC opens the connection. If your endpoint is still processing when the timeout elapses, WHCC treats the request as failed and retries it — even if your endpoint eventually would have returned 200. A slow endpoint therefore generates its own retries and its own duplicates.

Return a 2xx as soon as you have durably recorded the notification. Do any slow downstream processing (image lookups, order sync, notifications to other systems) asynchronously, after you respond.

Retry logic

What happens next depends on the response WHCC receives:

Response Outcome
Any 2xx Success. Delivery complete; never retried.
301, 302, 303 The redirect is followed, but replayed as a GET with no body, so your endpoint never receives the notification. If that GET returns a 2xx, WHCC records the delivery as successful and never retries it — the notification is lost silently. Never register a callback URI that redirects — including a plain http:// URL that your server upgrades to https://. Register the final destination directly.
Any 4xx Terminal. WHCC stops sending this notification permanently.
Any 5xx Retried.
Connection failure (refused, reset, DNS failure) Retried.
No response within 100 seconds Retried.

Upcoming changes. Two parts of the table above will change in a future release. No date is set yet, so write your integration to be correct under both the current and the future behaviour.

  • 408 Request Timeout and 429 Too Many Requests will become retryable, rather than terminal like the rest of the 4xx range. Until then, treat them as terminal — do not rely on WHCC retrying them.
  • Redirects will no longer be followed. A 3xx will be treated as a failed delivery. If your endpoint currently returns a redirect, point your registered callback URI directly at the final destination now.

Retry schedule

Retries use exponential backoff: the delay before attempt n is 6^(n-1) minutes. These are minimums — a retry becomes eligible after the delay elapses and is sent on the next delivery pass, so the real gap can be slightly longer, particularly at busy times. WHCC currently makes up to 7 attempts total (the initial attempt plus 6 retries) before giving up.

Attempt Minimum delay since previous attempt Minimum elapsed since first attempt
1 — (initial delivery) 0
2 6 minutes 6 minutes
3 36 minutes 42 minutes
4 216 minutes (3.6 hours) ~4.3 hours
5 1,296 minutes (21.6 hours) ~1.1 days
6 7,776 minutes (5.4 days) ~6.5 days
7 46,656 minutes (32.4 days) ~38.9 days

A single notification can therefore keep retrying for up to ~39 days after the triggering event, if your endpoint keeps returning a retryable failure. Size your idempotency storage with that window in mind — a repeat can arrive more than a month after the original. If you expire dedup keys after a week, a delivery on attempt 7 will look brand new.

Upcoming change. That last row is longer than intended. In a future release the cap becomes 6 attempts, ending the window at ~6.5 days. Retaining dedup keys for ~39 days is correct under both the current and the future schedule, so size for 39 days now and you will not need to revisit it.

After the final attempt fails, WHCC stops retrying that notification. There is currently no partner-facing endpoint to query undelivered notifications, so a monitored, reliably-responding endpoint is the only way to guarantee delivery.

What's Next

Security and Signatures describes how to validate that a webhook request actually came from WHCC.

Back to Top 👆
Get in Touch

Interested in integrating with WHCC? Tell us more about what you’re looking for and we’ll be in touch.