Delivery behaviour
Sorted by how much time you get. The tightest sender you receive from is your real constraint, not the most familiar one.
| Provider | Response budget | Retry | Gives up / disables |
|---|---|---|---|
| Slacksource | 3s | 3 retries: immediately, after 1 min, after 5 min | Event subscriptions disabled if over 95% of attempts fail within 60 min |
| Discordsource | 3s Interaction endpoints must send an initial response within 3 seconds | not verified | not verified |
| Shopifysource | 5s | 8 attempts over 4 hours | Subscription deleted after repeated failures within a 24-hour period |
| Paddlesource | 5s | Live: 60 attempts over 3 days, 20 in the first hour, 47 in the first day. Sandbox: 3 attempts over 15 min | not verified |
| HubSpotsource | 5s Applies to the whole batch, which can carry up to 100 notifications | Up to 10 attempts spread over 24 hours | not verified |
| GitHubsource | 10s | None. GitHub does not automatically redeliver failed deliveries | No disable. Deliveries stay redeliverable by hand for 3 days, then the record is gone |
| Twiliosource | 15s Configurable. rt read timeout default 15000ms (max 15000), ct connect default 5000ms (max 10000), tt total default 15000ms | Configurable: rc 0 to 5, default 1. rp selects which failures qualify | not verified |
| Stripesource | not published Stripe publishes no figure. Its docs say only to return 2xx before any slow logic. 20s is the community working number | Exponential backoff for up to 3 days in live mode. Sandbox: 3 attempts over a few hours | Endpoint disabled after continued failure, with an email first. Events stay in the Events API for 30 days |
| Svix (Clerk, Resend)source | not published | 8 attempts: immediately, 5s, 5 min, 30 min, 2h, 5h, 10h, 10h. Then a message.attempt.exhausted operational webhook | Endpoint disabled after all attempts fail for 5 days |
| WooCommercesource | not published Delivery is queued into Action Scheduler and driven by WP-Cron, so it leaves when a page is next loaded rather than when the event happens | not verified | Webhook disabled after more than five consecutive delivery failures |
Two rows are worth reading twice. GitHub does not retry at all, so a failed delivery is lost unless somebody redelivers it inside three days. Paddle front-loads 20 of its 60 attempts into the first hour, which punishes a merely slow handler far harder than Stripe's exponential curve.
Signature schemes
The signed payload column is the one that costs people hours. Anything other than raw body means you cannot hash the request body alone.
| Provider | Algorithm | Signed payload | Encoding | Header | Tolerance |
|---|---|---|---|---|---|
| Slack | HMAC-SHA256 | v0:{timestamp}:{body} | hex | x-slack-signature = v0=hex | 5 min |
| Discord | Ed25519 | {timestamp}{body} | hex | x-signature-ed25519 + x-signature-timestamp | none |
| Shopify | HMAC-SHA256 | raw body | base64 | x-shopify-hmac-sha256 | none |
| Paddle | HMAC-SHA256 | {timestamp}:{body} | hex | paddle-signature = ts=X;h1=hex | 5s |
| HubSpot | HMAC-SHA256 | POST{decodedUrl}{body}{timestamp} | base64 | x-hubspot-signature-v3 | 5 min |
| GitHub | HMAC-SHA256 | raw body | hex | x-hub-signature-256 = sha256=hex | none |
| Twilio | HMAC-SHA1 | full URL + form params sorted by key | base64 | x-twilio-signature | none |
| Stripe | HMAC-SHA256 | {timestamp}.{body} | hex | stripe-signature = t=X,v1=hex | 5 min |
| Svix (Clerk, Resend) | HMAC-SHA256 | {id}.{timestamp}.{body} | base64 | svix-signature = v1,base64 | none |
| WooCommerce | HMAC-SHA256 | raw body | base64 | x-wc-webhook-signature | none |
| Lemon Squeezy | HMAC-SHA256 | raw body | hex | x-signature + x-event-name | none |
| PayPal | RSA-SHA256 | {txId}|{txTime}|{webhookId}|{crc32(body)} | base64 | paypal-transmission-sig + 4 more | none |
| SendGrid | ECDSA P-256 | {timestamp}{body} | base64 | x-twilio-email-event-webhook-signature | none |
| Linear | HMAC-SHA256 | raw body | hex | linear-signature | none |
| Sentry | HMAC-SHA256 | raw body, no timestamp | hex | sentry-hook-signature | none |
| Intercom | HMAC-SHA1 | raw body | hex | x-hub-signature = sha1=hex | none |
| Vercel | HMAC-SHA1 | raw body | hex | x-vercel-signature | none |
Use this data
The same table is served as JSON at /providers.json, under CC BY 4.0. Copy it, embed it, correct it. If a number here is wrong or a vendor has changed something, open an issue on the repo and it gets fixed here.
Attribution: AnyHook, Webhook Provider Behaviour Reference, https://anyhook.net/providers
Where each number came up
- GitHub does not retry, and the record expires in three days
- Slack's three seconds, and the 95% disable threshold
- Paddle's 60 attempts against Stripe's curve
- Twilio's configurable timeouts, and why the default retry never runs
- HubSpot's eventId is documented as not unique
- Verifying signatures, provider by provider