What is a webhook endpoint?

A webhook endpoint is the URL on your server that receives webhook requests from another service. You register it with a provider such as Stripe, GitHub or Shopify. When an event happens there, the provider sends an HTTP POST with the event details to your endpoint, and your code processes it and replies with a 2xx status.

https://api.example.com/webhooks/stripe
└────────── host ──────┘└──── path ────┘

How a webhook endpoint works

  1. You create a route in your app, for example POST /webhooks/stripe.
  2. You give its full public URL to the provider. That's the webhook URL.
  3. An event fires. The provider sends a request whose body is the webhook payload, usually JSON, along with headers that include a signature.
  4. Your endpoint verifies the signature, stores or queues the event, and returns 200 OK.
  5. If the endpoint returns an error or times out, the provider retries later.

Example endpoint

// Express
const raw = express.raw({ type: 'application/json' })

app.post('/webhooks/stripe', raw, (req, res) => {
  // reject the request if the signature is invalid
  const sig = req.headers['stripe-signature']
  const event = verifySignature(req.body, sig)
  queue.add(event)     // do slow work later
  res.sendStatus(200)  // acknowledge fast
})

What makes a good webhook endpoint

  • Publicly reachable over HTTPS. Providers can't reach localhost or a private network. Many refuse plain HTTP or self-signed certificates (ERR_CERT_AUTHORITY_INVALID).
  • Fast. Respond in a few seconds and do the heavy lifting asynchronously. Slow handlers cause 504 timeouts and duplicate retries.
  • Verified. Check the webhook signature with your webhook secret before trusting the body. You can test one with the signature verifier.
  • Idempotent. The same event can arrive more than once, so deduplicate on the event ID. See idempotency.
  • Observable. Log every request so you can see what the provider actually sent and replay it.

Testing a webhook endpoint

To see what a provider sends before writing any code, point it at a free Webhook Bin URL and inspect the captured requests. To test your real handler on localhost, run relay forward --bucket my-app http://localhost:3000/webhooks. You get a permanent public URL, and each webhook is delivered to your machine.

Frequently asked questions

What is a webhook endpoint?

A webhook endpoint is an HTTP URL on your server that another service sends webhook requests to. When an event happens, such as a payment succeeding or code being pushed, the provider sends an HTTP POST with the event data to that URL, and your code at the endpoint processes it.

What is the difference between a webhook endpoint and a webhook URL?

They are usually the same thing. The webhook URL is the address you paste into the provider's settings, and the webhook endpoint is the route on your server that handles requests sent to that address. People use the two terms interchangeably.

What should a webhook endpoint return?

A 2xx status code, usually 200 or 204, as quickly as possible, ideally within a few seconds. Do slow work asynchronously after responding. A non-2xx response or a timeout tells the provider the delivery failed, and most providers will retry.

Can a webhook endpoint be on localhost?

Not directly. The provider sends requests over the internet and can't reach localhost or a private network. Use a forwarding tool such as the relay CLI, which gives you a public URL and delivers each webhook to your local endpoint over an outbound connection.