Web Development / 4 min read

How to test webhook retries before launch

A staging test for Shopify and Stripe integrations that checks duplicate deliveries, interrupted processing and out-of-order events against real business outcomes.

Insight featured cover image

Pick one action you can count

Start with a business action that should happen once, such as creating a fulfilment task for a paid order. In a test store or payment sandbox, use one synthetic order and route every notification to test recipients. Before sending an event, write down the expected result: one task tied to that order, with enough information to trace it back to the incoming event.

Capture the provider’s event or delivery ID alongside the order ID and a processing status. The first identifier helps you trace what arrived. The second helps you decide whether the customer action has already happened.

Send the same delivery twice

Use the provider’s resend feature or a staging replay harness that generates a valid signature. Deliver the event twice, then repeat with two deliveries arriving at nearly the same time. Check the task table, the queue and the test inbox. One task should exist even if the endpoint received two requests.

For Shopify HTTPS webhooks, use X-Shopify-Webhook-Id to identify an individual delivery and X-Shopify-Event-Id to relate deliveries from the same merchant action. For Stripe, start with the Event ID. Where distinct events can drive the same business action, protect that action with its own key. For example, a unique constraint on store, order and task type can prevent two workers from creating the same fulfilment task.

Interrupt processing at two points

First simulate an outage before the event has been saved. The endpoint should return a failure so the provider can retry. Then interrupt the worker after it creates the task but before it records completion. Restart the worker and check that the original task survives and the retry creates no second task. If the side effect crosses into another service, verify that service’s idempotency support or reconcile the result before retrying.

For a queued design, verify the signature before accepting the event and return success only after the event is stored durably. The worker can then retry its own failures without asking the provider to deliver an event you already accepted.

Change the order and record the result

Run the test again with events arriving out of sequence. Stripe does not guarantee event ordering. If a payment arrives before an earlier lifecycle event, retrieve the current state from the provider when needed and check that a late event cannot undo the correct state.

Record which test event was used, the order it arrived in and the final outcome. A useful handoff shows the expected count and the observed count for every side effect. Run the test again whenever the handler, queue or downstream destination changes.

References: Stripe webhook delivery and retry guidance (https://docs.stripe.com/webhooks) and Shopify’s webhook delivery guide (https://shopify.dev/docs/apps/build/webhooks/verify-deliveries).