What is a webhook listener? Definition and example

A webhook listener is the server or process that waits for incoming webhook requests and handles them. It binds to a port, accepts POST requests on a route such as /webhooks, verifies each request, passes the event to your code and replies with a 2xx status. The listener is the running program; the webhook endpoint is the route it serves; the webhook URL is the public address providers send to.

A minimal webhook listener

Node.js with Express:

import express from 'express'
const app = express()

app.post('/webhooks', express.raw({ type: '*/*' }), (req, res) => {
  if (!verifySignature(req.body, req.headers)) return res.sendStatus(401)
  const event = JSON.parse(req.body)
  queue.add(event)       // process later
  res.sendStatus(204)    // acknowledge fast
})

app.listen(3000, () => console.log('listening on :3000'))

Python with Flask:

from flask import Flask, request

app = Flask(__name__)

@app.post("/webhooks")
def webhooks():
    raw = request.get_data()          # raw bytes for signature checks
    if not verify_signature(raw, request.headers):
        return "", 401
    enqueue(raw)
    return "", 204

app.run(port=3000)

How a webhook listener works

  1. It listens. The process binds to a port, such as 3000, and waits for HTTP connections.
  2. A provider sends a request. When an event happens, the provider sends an HTTPS POST to the public URL, and a reverse proxy, load balancer or tunnel passes it to the listener.
  3. It verifies the request. It checks the webhook signature against the raw body using the webhook secret.
  4. It acknowledges. It stores or queues the payload and returns 200 or 204 within a few seconds.
  5. A worker processes the event. Slow work like sending email or updating several systems happens outside the request.

Listener vs endpoint vs URL

TermWhat it isExample
Webhook URLThe public address given to the providerhttps://api.example.com/webhooks
Webhook endpointThe route that handles itPOST /webhooks
Webhook listenerThe running server processA Node process on port 3000

Some CLIs use "listen" for a forwarder: stripe listen receives Stripe events and forwards them to your local listener. That's a forwarding tool, not the listener itself.

Running a listener on localhost

A listener on localhost:3000 works for local requests, but providers can't reach it from the internet. You have three options:

  • Deploy it to a server with a public HTTPS address.
  • Open a tunnel to it, which exposes the whole port publicly. See tunnel.
  • Forward webhooks to it. With webhook forwarding, only the webhooks reach your machine:
relay forward --bucket my-app http://localhost:3000/webhooks

The bucket's URL is permanent, so you configure the provider once. Details are in receiving webhooks on localhost.

Common mistakes

  • Parsing the body before verifying it. Body-parsing middleware changes the bytes and breaks signature checks. Read the raw body on webhook routes.
  • Doing slow work in the request. If the listener takes too long, the provider times out, often seen as a 504 Gateway Timeout, and retries, so the same event is processed twice.
  • Assuming each event arrives once. Retries mean duplicates. Deduplicate on the event ID. See idempotency.
  • Binding to 127.0.0.1 inside a container. A listener in Docker that binds to 127.0.0.1 can't be reached from outside the container. Bind to 0.0.0.0 and publish the port.
  • No plan for downtime. Deploys and crashes happen. If the provider's retry window is short, events sent while the listener was down are lost. A gateway with durable retries stores them and delivers once the listener is back.

Frequently asked questions

What is a webhook listener?

A webhook listener is the server or process that waits for incoming webhook HTTP requests and handles them. It listens on a port, accepts POST requests on a route such as /webhooks, verifies the signature, hands the event to your code and replies with a 2xx status.

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

The endpoint is the URL and route that receives webhooks. The listener is the running program behind it, the HTTP server bound to a port. One listener can serve many endpoints, for example one route per provider.

How do I run a webhook listener locally?

Start your listener on a local port, for example a small Express or Flask app on port 3000, then use a forwarding tool to give it a public URL. With Webhook Relay, relay forward --bucket my-app http://localhost:3000/webhooks prints a permanent public URL that delivers every webhook to the local listener.

Does a webhook listener need to be always on?

Ideally, yes, because providers send webhooks whenever events happen. If the listener is down, deliveries fail and depend on the provider's retries. A webhook gateway with durable retries can store the events and deliver them once the listener is back.