Webhooks Fundamentals: How Webhooks Work, How to Secure Them and How to Test Them
A webhook is an HTTP callback that delivers event data from one system to another as it happens. When an event occurs (a payment succeeds, a user signs up, a commit is pushed), the source system sends an HTTP POST to a URL you registered, so you never have to poll for changes.
This guide covers how delivery and retries work, how to build and secure an endpoint, how to survive duplicates and out-of-order events, and how to test all of it on localhost, with provider details current as of September 2026.
Key takeaways
- A webhook is an HTTP POST a provider sends to your URL when an event happens; it replaces polling with push.
- Delivery is at-least-once: providers retry on timeouts and non-2xx responses (Stripe for up to 3 days, Shopify up to 8 times in 4 hours), so every handler must be idempotent. GitHub is the exception that doesn't retry automatically.
- Verify the signature over the raw body before parsing JSON, check the timestamp, and compare in constant time; re-serialized JSON is the most common cause of "invalid signature".
- Acknowledge with a 2xx within a few seconds (Shopify allows 5, GitHub 10) and do the real work from a queue.
- Newer providers converge on two signing styles: Standard Webhooks headers (
webhook-id,webhook-timestamp,webhook-signature, used by OpenAI) and asymmetric signatures verified with public keys from a JWKS URL (used by fal.ai). - To see what a provider really sends, point it at a Hooklistener endpoint: it captures the headers and body, forwards them to localhost with
hooklistener tunnel --port 3000, replays them on demand, and lets Claude Code or Codex wait for a delivery through the Hooklistener MCP server.
What is a webhook?
A webhook is an HTTP request triggered by an event in a source system and sent to a destination system, often with a payload of data.
Webhooks enable automated communication between independent systems, allowing applications to notify each other about events in real-time without constant polling. They're the foundation of event-driven architectures and modern integration patterns.
How do webhooks work?
You register a URL with the provider once; after that, every matching event triggers a signed HTTP POST to it, retried until you answer with a 2xx.
Event Occurs
Something significant happens in the source system - a user signs up, payment completes, or file is uploaded.
HTTP Request Created
The source system automatically generates an HTTP POST request containing event details and relevant data.
Webhook Delivered
The HTTP request is sent to the configured webhook URL endpoint in the destination system.
Event Processed
The destination system verifies the signature, returns a 2xx quickly, and processes the event. If it times out or returns an error, most providers retry the same event later.
Webhook vs API: what's the difference?
An API is pull (you ask when you want data); a webhook is push (the provider tells you when something changes). They work together: the webhook signals the event, and an API call fetches the current state when you need to be sure.
APITraditional APIs (Pull Model)
- Client requests data when needed
- Requires constant polling for updates
- Higher resource usage and latency
- Client controls timing of requests
WHWebhooks (Push Model)
- Server pushes data when events occur
- Real-time event notifications
- Efficient resource usage
- Server controls timing of notifications
How do I build a webhook endpoint?
Creating a Webhook Endpoint
A webhook endpoint is a public HTTPS route that accepts a POST, verifies it, stores it and answers 2xx within a few seconds. In practice it:
- Accepts POST requests (typically)
- Processes JSON or form-encoded payloads
- Returns HTTP status codes to indicate processing result
- Handles requests asynchronously for better performance
Before you deploy to production, it pays to test your webhooks against a disposable inspection URL so you can confirm the exact headers, body, and timing of incoming requests without deploying half-finished handler code to a real environment.
Webhook Payload Structure
Typical webhook payloads include:
How do I secure a webhook endpoint?
Signature Verification
Verify the provider's signature over the raw request body before you parse or trust it. Most providers use HMAC-SHA256 with a shared secret. Two details break most hand-written checks: verifying a re-serialized body instead of the raw bytes, and comparing buffers of different lengths (Node's timingSafeEqual throws instead of returning false):
Additional Security Measures
HTTPS Requirements
- • Always use HTTPS endpoints
- • Validate SSL certificates
- • Encrypt data in transit
- • Use TLS 1.2 or higher
Access Control
- • IP whitelist restrictions
- • Authentication headers
- • Rate limiting protection
- • Request origin validation
What are the most common webhook problems?
At-Least-Once Delivery
Webhooks are typically delivered "at-least-once," meaning you might receive duplicates.
Timeout Handling
Senders give you a few seconds before they count a delivery as failed (Shopify 5 s, GitHub 10 s) and retry it. Acknowledge first, then process asynchronously, ideally from a durable queue rather than in-process:
Out-of-Order Delivery
Webhooks may arrive out of chronological order. Design your system to handle events regardless of order, or implement ordering mechanisms using timestamps.
The best way to internalize these edge cases is to see them in action against a live endpoint. Try our free webhook tester to practice these concepts — send duplicates, replay payloads, and watch how retries actually behave before you ship a handler.
What changed in webhooks in 2025–2026?
Webhook tooling has matured quickly over the last two years. Event-driven architectures are no longer a niche pattern — they are the default for SaaS integrations, internal microservices, and AI-powered workflows. Several concrete shifts are worth calling out.
Standard envelopes and headers. Two specs are reducing per-provider guesswork. The Standard Webhooks spec fixes the signing headers (webhook-id, webhook-timestamp, webhook-signature); OpenAI uses it, so one verifier library covers every provider that does. The CNCF CloudEvents spec standardizes the payload envelope, giving consumers predictable fields (id, source, type, time) regardless of producer; Knative and Azure Event Grid speak it natively.
Retry policies differ a lot. Stripe retries live-mode events with exponential backoff for up to 3 days, Shopify retries up to 8 times over 4 hours, OpenAI keeps trying for up to 72 hours, and GitHub does not automatically redeliver failed deliveries at all. Know your provider's window, and implement idempotency either way.
Public-key signatures & key rotation. Shared HMAC secrets are still the default, but more providers sign with asymmetric keys and publish the public half at a JWKS URL. fal.ai, for example, signs with ED25519 and serves its keys at rest.fal.ai/.well-known/jwks.json, so there is no secret to leak and keys rotate without coordination. HMAC providers handle rotation by sending several signatures during a grace window. See webhook security fundamentals for verifying rotating keys safely.
AI-triggered event workflows. Agents now emit and consume webhooks directly — a model finishes a task, fires an event, and another system reacts. This raises the bar for schema discipline, auth, and audit trails, since autonomous producers amplify any weakness in your pipeline. Read more on what's next in webhook trends for 2025–2026.
Webhook Best Practices
Implementation Patterns
- • Return HTTP 200 quickly (< 5 seconds)
- • Process events asynchronously
- • Implement idempotent operations
- • Validate signatures and payloads
- • Log all webhook events
- • Use message queues for reliability
Monitoring & Observability
- • Track success/failure rates
- • Monitor processing latency
- • Alert on signature failures
- • Dashboard for webhook health
- • Retry failed processing
- • Dead letter queue setup
Common Webhook Use Cases
Payment Processing
Notify about successful payments, refunds, chargebacks, and subscription changes
User Management
Sync user registrations, profile updates, and account status changes
Content Publishing
Trigger builds, deployments, and content synchronization across platforms
Communication
Send notifications, messages, and alerts across multiple channels
Data Synchronization
Keep databases, analytics, and external systems synchronized
DevOps Automation
Trigger CI/CD pipelines, deployments, and infrastructure changes
How do I test webhooks locally? (with Hooklistener)
Give the provider a public HTTPS URL that records each delivery and forwards it to your machine, then replay captured requests while you fix the handler. Providers can't reach localhost, and most webhook bugs (wrong body bytes, missing headers, unexpected payload shape) are only visible in the real request.
- Capture: create an endpoint in the Hooklistener dashboard (the Free plan includes one), paste its URL into the provider's webhook settings, and trigger an event. You see every header and the exact body.
- Forward to localhost: install the CLI (
npm i -g hooklistenerorbrew tap hooklistener/tap && brew install hooklistener), runhooklistener login, thenhooklistener tunnel --port 3000. - Replay: resend any captured request to your handler after each change, including edited bodies, instead of re-triggering the event in the provider.
- From your coding agent: connect the Hooklistener MCP server (
claude mcp add --transport http hooklistener https://app.hooklistener.com/api/mcp) and Claude Code, Codex or Cursor can callcreate_endpoint, callwait_for_request, which waits for the matching webhook (as a task the agent follows, or blocking up to 60 s withblocking: true), andreplay_requestit against the code it just wrote.
FAQ
What is a webhook?
A webhook is an HTTP POST that a source system sends to a URL you register when an event happens, such as a payment succeeding or a job finishing. The body describes the event, usually as JSON, so your application reacts immediately instead of polling an API for changes.
What is the difference between a webhook and an API?
With an API your code asks for data (pull); with a webhook the provider sends data to you when something changes (push). Most integrations use both: the webhook says an event happened, and an API call fetches the current, authoritative state.
What are the best practices for signing and verifying webhook payloads?
Verify a signature over the raw request body before parsing it (HMAC-SHA256 with a shared secret, or an asymmetric signature such as ED25519 checked against the provider's published keys), include a timestamp in the signed content and reject anything older than about 5 minutes, compare signatures in constant time, and support two active secrets during rotation. IP allowlists are defense in depth, not a replacement.
How do I handle duplicate webhook deliveries?
Assume at-least-once delivery. Store each event ID (or a header such as webhook-id) with a unique constraint, skip events you have already processed, and make side effects idempotent. Providers retry on timeouts and non-2xx responses, so duplicates are normal, not an error.
How do I test webhooks on localhost?
Providers can't reach localhost, so give them a public HTTPS URL. Capture deliveries on a Hooklistener endpoint to inspect the exact headers and body, forward them to your machine with hooklistener tunnel --port 3000, and replay captured requests while you fix the handler. AI coding agents can do the same through Hooklistener's MCP tools create_endpoint, wait_for_request and replay_request.