A webhook handler written for one payment provider can quietly fail with another. Lemon Squeezy and Paddle count only a 200 as delivered, while Stripe, Polar and Dodo Payments accept any 2xx. Paddle waits 5 seconds for your answer, Dodo 30. Lemon Squeezy gives up after four attempts, about two and a half minutes with the delays it gives as an example, while Stripe and Paddle keep trying for three days. Polar disables an endpoint after 10 failed deliveries in a row. And Lemon Squeezy sends no delivery id at all.
This page puts the five side by side, from each provider's documentation as of 9 October 2026.
The table
| What | Stripe | Paddle | Lemon Squeezy | Polar | Dodo Payments |
|---|---|---|---|---|---|
| Counts as delivered | Any 2xx | 200 | 200 | Any 2xx | Any 2xx |
| Time to answer | Not documented | 5 seconds | Not documented | 10 seconds; answer within 2 | 30 seconds |
| Retries | Up to 3 days, exponential backoff; in a sandbox, 3 over a few hours | 60 within 3 days; in a sandbox, 3 within 15 minutes | 3 more, for example after 5, 25 and 125 seconds | Up to 10, exponential backoff | 8 attempts in all, over about 27.6 hours |
| Failing endpoint | Not documented | Not documented | Not documented | Disabled after 10 failed deliveries in a row, with an email to the organization | Not documented; no email alerts |
| Id to deduplicate | The event's id (evt_…) in the body | event_id (evt_…) in the body | None | The webhook-id header | The webhook-id header |
| Signature header | Stripe-Signature | Paddle-Signature | X-Signature | webhook-signature (Standard Webhooks) | webhook-signature (Standard Webhooks) |
| Signature window | 5 minutes in the SDKs | 5 seconds in the Node, Python and PHP SDKs | None: the signature has no timestamp | 5 minutes, both ways | 5 minutes, both ways |
| Manual resend | Dashboard for 15 days, CLI for 30; same event id, new signature | API replay of a delivered or failed notification, for 90 days; same event_id, new notification_id | Resend in the dashboard; the body is serialized again | Redeliver in the dashboard | Replay one message from the logs, or failed messages in bulk, up to two weeks back |
What counts as delivered
Two of the five count only a 200. Lemon Squeezy's documentation says to return a 200 and that anything else is retried, and Paddle's delivery guide says the same of any other status code. So a handler that answers 201, 202 or 204, which Stripe, Polar and Dodo accept, runs again for every Lemon Squeezy or Paddle event, and the delivery still ends up failed. Answer exactly 200 and every provider is satisfied.
Stripe and Polar also treat a redirect as a failure and do not follow it, so the endpoint URL must be the final one: a www redirect on your host is enough to fail every delivery.
How long you have to answer
Paddle waits 5 seconds, Polar 10 (and asks for an answer within 2), Dodo 30; Stripe and Lemon Squeezy do not give a number. Whatever the number, a timeout counts as a failure and brings a retry, even when your work finished. So answer first and do the work after, from a queue or a background job, as Stripe, Paddle, Polar and Dodo all recommend.
Paddle's five seconds come back in its signature check: its Node, Python and PHP SDKs reject a signature more than 5 seconds old, so a slow tunnel fails both. See Paddle's signature error.
How long they keep retrying
The schedules differ by orders of magnitude. Lemon Squeezy makes four attempts; with the delays its documentation gives as an example, that is about two and a half minutes, so an endpoint that is down for three minutes loses the event. Dodo retries for about 27.6 hours, Stripe and Paddle for three days in live mode. Polar retries up to 10 times, and after 10 failed deliveries in a row it disables the endpoint and emails the organization's members; it stays disabled until someone enables it again in the webhook settings.
Test environments retry less: Stripe retries three times over a few hours in a sandbox, Paddle three times within 15 minutes.
Deduplicate, and do not trust the order
Every provider may deliver the same event twice, so keep the id of each event you have handled and skip repeats. Stripe and Paddle put it in the body: Stripe's event id, and Paddle's event_id, not its notification_id, which differs between destinations and replays. Polar and Dodo send it as the webhook-id header, which the Standard Webhooks specification keeps the same on every retry. Lemon Squeezy sends none, and its body's meta.webhook_id changes on a Resend: build a key from the event name, the resource and its updated_at, as our Lemon Squeezy page shows.
No provider promises the order of events. Paddle says to compare occurred_at, Dodo to order by the payload's timestamp, and Dodo adds that a delivery carries the latest state at the time it is sent. Stripe warns not to order by created: it is in seconds, and several events share it.
Signatures and their windows
Each scheme signs the raw body, so a body parsed and serialized again fails everywhere. The windows differ: Stripe's SDKs allow 5 minutes, Paddle's 5 seconds, Polar's and Dodo's Standard Webhooks libraries 5 minutes in either direction, and Lemon Squeezy's signature has no timestamp, so a captured request stays valid forever. The details, error by error: Stripe, Paddle, Lemon Squeezy, Polar and Dodo Payments.
How PayHook reports it
PayHook, the webhook inspector we are building, checks each event with its provider's own signature scheme and time window. When it relays events to your app, it keeps your app's answer next to each event and warns when the provider would count that answer as a failure, such as a 204 sent to Lemon Squeezy. PayHook is in closed beta; the home page has the details.
Sources
- Stripe documentation, Receive Stripe events in your webhook endpoint and Manage webhook endpoints, checked on 9 October 2026.
- Paddle documentation, How webhooks work, Handle webhook delivery and Replay a notification, checked on 9 October 2026.
- Lemon Squeezy documentation, Webhook requests and Signing requests, checked on 9 October 2026; Resend and
meta.webhook_id: PayHook's own test-mode capture, 7 October 2026. - Polar documentation, Handle and monitor webhook deliveries, checked on 9 October 2026.
- Dodo Payments documentation, Webhooks, checked on 9 October 2026.
- The Standard Webhooks specification and its JavaScript library: the
webhook-idon retries and the five-minute window, read on 9 October 2026.