00 / guide
Stripe webhook 400, 500 or timed out: what each one means
Your webhook endpoint shows red errors in Stripe. A 400, a 500 and a timeout look alike, but each has a different cause. Find yours below.
Free tool: paste your webhook error and get the fix
01 / what CheckoutAlarm checks
a
What it would catch here
All three are failed deliveries. With a read-only key, CheckoutAlarm emails you when events are still undelivered about 15 minutes after they were created.
b
What it won't catch
It won't say which code you got or which line crashed. Read that in Stripe's Event deliveries tab and your logs. If your code answers 200 and then fails, Stripe sees a success and so do we.
c
Plans
Free: 1 site, checked once a day. Pro: $19 a month, up to 3 sites checked hourly. You prove you own the site first. For Stripe we only take a restricted key with read access to Events, Webhook Endpoints and Charges. Full secret keys are refused. Compare plans
02 / find the code
1
Open the failed delivery
In Workbench, go to Webhooks, pick the endpoint, then Event deliveries. Click a failed event to see its status code and your server's reply. Stripe: view event deliveries
03 / 400 bad request
1
Most often: signature check
Stripe lists 400 as "the destination URL returned an error." In Stripe's sample code, a failed signature check returns 400. Stripe: fix HTTP status codes
2
Fix the signature
Check with the raw body, not parsed JSON. Use the whsec_ secret for this endpoint and this mode. Our signature guide walks through it.
04 / 500 server error
1
Read your logs
For a 5xx, Stripe says the destination had a problem and to check your logs for that time. On Vercel, that is the project's Logs. On Supabase, the function's logs. Stripe: fix HTTP status codes
2
Common crashes
A missing setting such as an empty secret, a database call that fails, or code that expects a field the event doesn't have. Paste the log line into your AI builder and ask it to handle that case.
05 / timed out
1
Answer first, work later
Stripe says to return a 2xx "before any complex logic that might cause a timeout." For timeouts, Stripe says to "defer complex logic and return a successful response immediately." Stripe: quickly return a 2xx Stripe: timed out
2
Next.js: use after()
Next.js after() runs code once the response is sent, inside Route Handlers. On Vercel it uses waitUntil and still has to finish within the route's max duration. Next.js: after
3
Supabase: use EdgeRuntime.waitUntil
Edge Functions can run work after the reply with EdgeRuntime.waitUntil(promise). It is still limited by the function's time, CPU and memory limits. Supabase: background tasks
4
Heavy work: use a queue
Stripe suggests an asynchronous queue to handle bursts of events. Stripe: process events asynchronously
06 / the catch with answering early
a
A 200 doesn't mean it worked
Once you answer 200, Stripe marks the event delivered and stops retrying, even if your later work fails. Save the event id and check that each one finished. Stripe also says to log processed event ids so duplicates are skipped. Stripe: handle duplicate events
07 / questions
- What does a 400 on a Stripe webhook usually mean?
- Stripe lists 400 as 'the destination URL returned an error.' The most common cause is a signature check that fails, often because the body was changed before checking, or the wrong whsec_ secret is set.
- What does a 500 mean?
- Your code crashed or threw an error. Stripe tells you to check your server's logs for that time.
- Why does my webhook time out?
- Your code took too long to answer. Stripe's advice is to answer with a 2xx right away and do the slow work after.
- Will Stripe retry?
- Yes. In live mode Stripe retries for up to three days. Make your handler safe to run twice, since retries and duplicates happen.
08 / where CheckoutAlarm fits
CheckoutAlarm emails you when Stripe events stay undelivered after a 400, a 500 or a timeout. It can't see work that fails after you already answered 200.
CheckoutAlarm is new. It only checks sites you prove you own. How to verify
Watch my app free09 / sources
- Stripe: fix HTTP status codes
- Stripe: quickly return a 2xx response
- Stripe: process events asynchronously
- Stripe: handle duplicate events
- Stripe: view event deliveries
- Next.js: after
- Supabase: background tasks (EdgeRuntime.waitUntil)
Docs checked on Oct 20, 2026.