Skip to content

Webhook Response Codes Explained

Last checked November 14, 2026

A status code is a three-digit number your system sends back after it receives a webhook. It tells the sending app whether the message arrived and was accepted. Senders such as Stripe and GitHub look for a code in the 200s, written 2xx, as the sign of success12.

The first digit gives the family3. Each family points to a different place to look.

How to read a status code2xx: your system accepted it4xx: the request or the URL is the issue5xx: your system hit an error
The first digit tells you who to look at.

200: it worked

The request succeeded3. Stripe's documentation says that when an event shows a status code of 200, it indicates successful delivery to the webhook endpoint1.

GitHub asks for any 2XX code, and says your server should respond with a 2XX response within 10 seconds of receiving a webhook delivery2. Read your sender's own rule.

Speed matters. Stripe tells developers to defer complex logic and return a successful response immediately in webhook handling code1. In plain terms: reply first, do the slow work afterward.

400: the request was rejected

A 400 is MDN's label for a request the server refuses to handle because it looks like the sender's mistake, such as broken syntax3. For a webhook, the "client" is the sending app.

Stripe's example handler code returns 400 when the payload can't be parsed or the signature check fails1. If a sender's log shows 400, look at your own receiving code first.

Stripe groups all 4xx codes together. It says they can mean the server detected an error (400), that the URL has access restrictions (401, 403, 405), or that the URL doesn't exist (404)1.

404: the address doesn't exist

A 404 says the server has nothing at the address it was sent to3. For a webhook, that points at the URL, which Stripe lists as a case where the destination doesn't exist1.

Check these in order:

  1. Compare the URL in the sending app to the one your system listens on, character by character.
  2. Look for a missing or extra slash, a typo in the route, or an old address after a site move.
  3. Confirm the receiving route accepts POST requests. Stripe's advice for 4xx codes is to make sure the endpoint is publicly accessible and accepts a POST HTTP method1.

500: the receiver failed

A 500 is a catch-all error for a server that hit a problem it couldn't handle3. Stripe says the receiving server ran into an error while processing, and it points you to your application's logs1.

The fault sits on the receiving side. The sender did its job, but your system broke while handling the message.

Other codes you may meet

Code Meaning Source
429 Too many requests sent in a set period, also called rate limiting MDN3
503 The server can't take requests right now, for example during maintenance MDN3
3xx, such as 302 A redirect, which Stripe counts as a failure for webhooks Stripe1

A timeout isn't a code at all. Stripe lists it as its own case, for a receiver that answers too slowly1.

What to send from your side

Return a 2xx code as soon as the message is received, then do the slow work. Stripe and GitHub both ask for a quick reply12.

What happens after a failure depends on the sender. The sender's retry rules are in Webhook Retries and Failed Deliveries.

Sources used

  1. Receive Stripe events in your webhook endpoint, Stripe Documentation
  2. Handling webhook deliveries, GitHub Docs
  3. HTTP response status codes, MDN Web Docs