A webhook is an event-driven HTTP callback. When something happens in a provider or source application, that application sends an HTTP request—usually a POST containing JSON—to a URL owned by your application. Instead of repeatedly asking an API whether anything changed, your system receives the notification when the event occurs.
A production-quality webhook integration must do more than accept JSON. It should authenticate the sender, validate the exact request body, record a delivery ID, acknowledge quickly with a 2XX response, and process the event asynchronously and idempotently. The provider’s documentation remains authoritative for event names, headers, signatures, payload limits, retries and timeouts.
How a webhook works
There are two applications:
- Provider (sender): detects an event such as a payment succeeding, a repository changing, or a capture job finishing.
- Consumer (receiver): exposes an HTTPS endpoint and performs work based on the notification.
- You deploy a publicly reachable HTTPS endpoint, for example
https://example.com/webhooks/provider. - You register that URL and the event types you want in the provider’s dashboard or API.
- The provider detects a subscribed event and sends an HTTP
POST. - The request includes a body (commonly JSON) and metadata headers such as an event type, a delivery ID and a signature.
- Your endpoint authenticates and validates the request, stores the delivery ID, places the event on a queue, and returns a fast 2XX response.
- A worker performs the slow or irreversible operation and records its result.
CloudEvents’ HTTP binding requires POST and a Content-Type header carrying the notification payload. The Standard Webhooks specification recommends JSON in the body but does not define one universal event schema. Consequently, two webhook providers can use completely different envelopes even when they report similar events.
A representative request
POST /webhooks/orders HTTP/1.1
Host: example.com
Content-Type: application/json
X-Event-Type: order.created
X-Delivery-Id: 8f2e...
X-Signature: sha256=...
{"id":"ord_123","customer_id":"cus_456","total":4200}
The header names above are illustrative. Use the exact names and signing algorithm documented by your provider.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
Webhook versus API and polling
Webhook and API are complementary
An API is an interface for making requests and receiving responses. A webhook is a delivery mechanism that lets an API provider initiate a request to your application after an event. You might use an API to create an order, then receive a webhook when payment for that order is completed.
Webhook versus polling
| Concern | Webhook | Polling |
|---|---|---|
| Notification timing | Usually near the event, subject to provider delivery and network delay | Only when the next poll runs |
| Request volume | Requests generally occur for events | Repeated requests occur even when nothing changed |
| Receiver requirements | Publicly reachable endpoint, authentication, retry and duplicate handling | Client needs API credentials and a schedule; no inbound endpoint is required |
| Failure model | Provider retries may create duplicate deliveries; you must acknowledge and deduplicate | Client retries failed polls and must track cursors or last-seen state |
| Implementation | More operational work at the receiver, but efficient for event-driven updates | Often simpler initially, but can add latency and unnecessary API traffic |
Polling can be preferable when inbound traffic is impossible, the provider has no webhook facility, or periodic reconciliation is more important than immediate notification. Many robust systems use both: webhooks for prompt updates and scheduled API polling to repair missed events.
Build a secure webhook endpoint
1. Use HTTPS and a dedicated route
Serve the endpoint over HTTPS and keep it separate from browser-facing form routes. Do not put secrets in the URL, query string or path. Restrict accepted methods to POST, enforce a sensible body-size limit, and reject unsupported content types.
2. Verify the signature over the raw body
Treat every request as untrusted until authenticated. Configure a high-entropy secret, store it in a secret manager or environment variable, and calculate the provider’s specified signature over the exact bytes received. Verify the signature before parsing JSON or performing any action. Use constant-time comparison to avoid timing leaks.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →GitHub, for example, documents an HMAC SHA-256 value in X-Hub-Signature-256. That algorithm and header are GitHub-specific; another provider may use a different scheme, timestamp format or header.
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
const crypto = require('node:crypto');
function validSignature(rawBody, received, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
const a = Buffer.from(expected, 'utf8');
const b = Buffer.from(received || '', 'utf8');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Capture the raw bytes before a JSON parser transforms whitespace, character encoding or key ordering. Follow the provider’s replay-window or timestamp rules when they are specified.
3. Deduplicate before side effects
Retries and network behavior can deliver the same event more than once. Persist the provider’s delivery or event ID in durable storage with a uniqueness constraint before sending email, charging a card, provisioning access or making another irreversible change. If the ID already exists, return success without repeating the work.
The Standard Webhooks specification describes the unique event identifier as remaining the same across retries. Do not assume every provider uses the same field name; map its documented identifier to your internal idempotency key.
Recommended Free Tools
4. Acknowledge quickly, then queue
Validate, persist and enqueue the event, then return a 2XX response as soon as possible. Long-running work inside the request handler increases timeout and retry risk. GitHub recommends responding within 10 seconds; other providers can impose different limits. A queue or background worker lets you retry application work independently of provider delivery.
Runnable receiver examples
Node.js with Express
This example keeps the raw body for HMAC validation and uses an in-memory set only for demonstration. Replace it with a transactional database table and a real queue in production.
Rank #3
const express = require('express');
const crypto = require('node:crypto');
const app = express();
const secret = process.env.WEBHOOK_SECRET;
const seen = new Set();
app.post('/webhooks/orders', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.get('X-Signature');
const expected = 'sha256=' + crypto.createHmac('sha256', secret)
.update(req.body).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signature || '');
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.sendStatus(401);
}
let event;
try { event = JSON.parse(req.body.toString('utf8')); }
catch { return res.sendStatus(400); }
const deliveryId = req.get('X-Delivery-Id');
if (!deliveryId) return res.sendStatus(400);
if (seen.has(deliveryId)) return res.sendStatus(204);
seen.add(deliveryId);
// Enqueue event here; do not perform slow work in this handler.
console.log(event);
return res.sendStatus(204);
});
app.listen(3000, () => console.log('Listening on :3000'));
Python with Flask
import hashlib
import hmac
import json
import os
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = os.environ["WEBHOOK_SECRET"].encode()
seen = set() # Use a durable unique table in production.
@app.post("/webhooks/orders")
def orders():
raw = request.get_data(cache=False)
received = request.headers.get("X-Signature", "")
expected = "sha256=" + hmac.new(SECRET, raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, received):
abort(401)
delivery_id = request.headers.get("X-Delivery-Id")
if not delivery_id:
abort(400)
if delivery_id in seen:
return ("", 204)
try:
event = json.loads(raw)
except ValueError:
abort(400)
seen.add(delivery_id)
# Enqueue event here; return before slow business work.
print(event)
return ("", 204)
Send a test delivery with cURL
For a real signature, calculate the provider-specific value over the exact body. This command demonstrates the HTTP shape only:
curl -i -X POST https://example.com/webhooks/orders
-H 'Content-Type: application/json'
-H 'X-Event-Type: order.created'
-H 'X-Delivery-Id: test-001'
-H 'X-Signature: sha256=REPLACE_WITH_VALID_SIGNATURE'
--data '{"id":"ord_123","total":4200}'
Retries, replay and failure handling
A provider can retry when your endpoint times out, returns an error, or cannot be reached. A retry schedule, maximum attempts, timeout and manual redelivery controls are provider-specific. Record each delivery attempt and correlate it with the stable event or delivery ID.
- Return a 2XX only after authentication, schema validation and durable enqueue or persistence succeed.
- Return a 4XX for an invalid signature, malformed body or unsupported event that should not be retried.
- Return a 5XX or allow a timeout when a temporary dependency failure means the provider should retry.
- Keep a dead-letter or failed-event queue, with controlled replay after fixing the cause.
- Make workers idempotent as well as the HTTP endpoint; a queued message can also be delivered twice.
Keep payloads and logs free of unnecessary personal or secret data. Redact authorization headers and signature secrets, and apply retention limits to stored event bodies.
Provider differences you must check
There is no universal webhook contract. Before implementing, document:
- Event names, versioning and whether events are snapshots or partial updates.
- Envelope fields, content type, character encoding and maximum body size.
- Signature algorithm, signed components, timestamp tolerance and key rotation process.
- Delivery and event identifiers, retry schedule, timeout and redelivery controls.
- Whether ordering is guaranteed, and how to fetch the authoritative object through the API.
- Test-event behavior, IP ranges, mutual TLS or private networking options, if offered.
For example, GitHub documents a 25 MB payload cap and its own event and signature headers. That limit and those names must not be generalized to other services.
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Testing and operations checklist
- Test valid events, invalid signatures, altered bodies, missing headers and malformed JSON.
- Send the same delivery twice and verify that business effects happen once.
- Force a queue or database outage and confirm the provider receives a retryable response.
- Exercise slow downstream work and verify the endpoint still acknowledges within the provider’s timeout.
- Test old timestamps and replayed signatures where the provider supports replay protection.
- Monitor acceptance rate, authentication failures, processing latency, queue age, retries and dead-letter volume.
- Provide an authenticated operator path to inspect and replay a failed delivery without disabling signature checks.
Or skip the browser setup
Webhooks are also useful when an asynchronous service tells your system that a job has finished. ScreenshotNeo can submit capture jobs with signed webhooks, alongside its synchronous screenshot API. It is a website screenshot API and MCP server for developers; its cleanup steps accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups and chat widgets before capture, with each step configurable.
Only clean shots are billed. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and each response reports the result through X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.
One synchronous call looks like this (see the ScreenshotNeo documentation for parameters and webhook job details):
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
The same request in Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
And Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
There is a free allowance of 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is on every plan, and yearly billing gives two months free. Create a free ScreenshotNeo account to try it.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Common errors and fixes
401 or 403 responses
Usually the signature was calculated from a parsed body, the wrong secret or header was used, or a timestamp has expired. Capture raw bytes, check the provider’s exact signing recipe and rotate secrets through a controlled overlap period.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchRepeated deliveries
Do not treat repetition as proof of provider failure. Persist the documented event or delivery ID with a uniqueness constraint and make the worker idempotent.
Best Value
Timeouts and request storms
Move network calls and heavy computation to a queue, return only after durable enqueue, and use bounded worker concurrency. A fast 2XX without persistence can lose events, so acknowledgement must follow a durable handoff.
Valid events rejected as malformed
Check content-type handling, compression, character encoding and body-size limits. Validate against the provider’s current schema and tolerate documented additive fields.
Events arrive out of order
Do not assume ordering unless the provider guarantees it. Use event timestamps or sequence numbers where available, fetch current state from the API, and make updates conditional on version or revision.
Frequently Asked Questions
Can a webhook response contain useful data?
Yes, but most providers primarily need a status code confirming receipt. Put business results in your own API or follow-up event rather than making the sender wait for slow work.
Should webhook endpoints require user login?
Usually not interactive login. Authenticate the machine-to-machine request with the provider’s signature, secret, certificate or network control, and protect operational dashboards separately.
Can I run a webhook receiver on localhost?
Not directly from a public provider. Use a secure tunneling or staging service for development, then deploy the endpoint on reachable HTTPS infrastructure and restrict test credentials.
What happens if the provider has no retry mechanism?
Persist events, alert on gaps, and schedule reconciliation against the provider’s API. A webhook should not be your only source of truth when the service offers no redelivery.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

