What Is a Webhook? A Developer's Guide

Webhooks in Plain English

A webhook is an HTTP request that a server sends to your application when something happens. Instead of your application repeatedly asking "did anything change?" (polling), the external service tells you when something changes by sending an HTTP POST to a URL you specify. Think of it like a notification callback — "call me when the pizza is ready" instead of walking up to the counter every 30 seconds.

For example, when a customer completes a payment on Stripe, Stripe sends a POST request to your server with the payment details. When someone pushes code to a GitHub repository, GitHub sends a POST request with the commit information. When an email bounces in SendGrid, SendGrid notifies you via a POST request.

The term "webhook" was coined by Jeff Lindsay in 2007 as a play on "callback" — it is a web callback initiated by the external service rather than by your application. Today, webhooks are the standard mechanism for real-time communication between web services.

How Webhooks Work

The webhook flow involves three steps: configuration, event, and delivery. First, you tell the external service (the "provider") what URL to send notifications to and which events you care about. This is typically done through the provider's dashboard or API. The URL you provide is called the "webhook endpoint" or "listener."

When a relevant event occurs, the provider constructs an HTTP request — almost always a POST request with a JSON body — containing details about the event. The provider sends this request to your endpoint URL. Your server receives the request, processes the event data, and returns a response (typically a 200 status code to acknowledge receipt).

The provider usually includes metadata like an event type identifier, a timestamp, and a signature for verification. If your server does not respond successfully, most providers will retry the delivery with increasing delays (exponential backoff). After a certain number of failed attempts, the provider may disable the webhook.

Common Webhook Use Cases

Payment processing is the most common webhook use case. Services like Stripe, PayPal, and Square send webhooks when payments succeed, fail, or are refunded. Your application uses these events to fulfill orders, update subscription status, and maintain financial records.

CI/CD and DevOps tools use webhooks for deployment notifications. GitHub sends webhooks on push events, Vercel notifies you about deployment status, and monitoring tools alert you when services go down. These webhooks trigger automated workflows — running tests, deploying code, or sending notifications.

Communication platforms like Slack, Discord, and Twilio use webhooks for bot interactions and messaging events. When a user sends a message, clicks a button, or submits a form in these platforms, your application receives a webhook with the interaction details.

E-commerce platforms like Shopify send webhooks for order lifecycle events: order creation, payment, fulfillment, and returns. These drive inventory management, shipping integrations, and customer notifications.

Anatomy of a Webhook Request

A typical webhook request consists of several parts. The HTTP method is almost always POST, though some providers use PUT for update events. The URL is your endpoint — the address you registered with the provider.

The headers include the standard HTTP headers plus provider-specific ones. Most providers include a signature header for verification (like Stripe's Stripe-Signature or GitHub's X-Hub-Signature-256), an event type header, and a unique delivery ID. Content-Type is usually application/json, though some providers (like Twilio and Slack) use application/x-www-form-urlencoded.

The body contains the event data as JSON (or form data). A typical payload includes the event type, a timestamp, a unique event ID, and a data object containing the relevant resource. Here is what a simplified webhook payload might look like:

json
{
  "id": "evt_1234567890",
  "type": "payment.completed",
  "created": 1709854800,
  "data": {
    "amount": 2500,
    "currency": "usd",
    "customer_id": "cus_abc123"
  }
}

The Localhost Problem

The biggest challenge with webhook development is that your local development server is not accessible from the internet. When you run your application on localhost:3000, Stripe or GitHub cannot reach it to deliver webhooks. This is the fundamental problem that tools like ReqPour solve.

There are several approaches to this problem. Localhost tunneling tools (like ngrok or localtunnel) create a secure tunnel from a public URL to your local machine. Webhook proxy services (like ReqPour or smee.io) provide a public endpoint that captures requests and forwards them to localhost.

ReqPour's approach has advantages for webhook development specifically: it captures and stores every request in a dashboard (so you never miss an event), lets you replay requests for iterative testing, and maintains persistent endpoint URLs across sessions. This makes the development workflow smoother compared to general-purpose tunneling tools.

Getting Started with Webhooks

To start working with webhooks, you need three things: a webhook endpoint in your application, a public URL for the provider to reach it, and a way to verify incoming requests.

Set up a route in your application that handles POST requests. Parse the request body (JSON or form data), process the event, and return a 200 status code. Keep your handler fast — acknowledge receipt and do heavy processing asynchronously.

For local development, use ReqPour to get a public URL. Create an endpoint in the dashboard, point your webhook provider at it, and start the CLI relay to forward requests to your local server:

bash
npx reqpour login
npx reqpour relay --to http://localhost:3000/api/webhooks

Register the ReqPour URL with your webhook provider, trigger an event, and watch it flow through: the ReqPour dashboard shows the request details, and your local server processes it. This is the foundation for building any webhook integration.

Get started with ReqPour

Catch, inspect, and relay webhooks to localhost. Free to start, $3/mo for Pro.