Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

A webhook is an event-driven HTTP callback: when something happens in one application, that application sends an HTTP request to a URL owned by another application. The receiving service can authenticate the request, acknowledge it quickly, and process the event without repeatedly asking whether anything has changed.

For example, a payment provider can send a payment.succeeded event to your server, GitHub can notify a deployment system when code is pushed, and an email service can report a bounce as soon as it occurs. Webhooks are usually delivered as HTTP POST requests containing a JSON payload, event metadata, and authentication headers.

How a webhook works

A webhook connects an event producer (the provider) to an event consumer (your application). The provider owns the event detection; your application owns the receiving endpoint and the work performed after delivery.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Expose an HTTPS endpoint. Your application makes a URL such as https://example.com/webhooks/provider reachable from the public internet. Use HTTPS in production.
  2. Register the URL. In the provider’s dashboard or API, select event types and enter the endpoint. The provider normally gives you a signing secret or another authentication mechanism.
  3. Subscribe to an event. The provider detects an event such as an order being paid, a repository push, or a subscription changing state.
  4. Receive an HTTP POST. The request generally contains a payload (often JSON) and headers identifying the event, delivery, and signature. GitHub, for example, documents X-GitHub-Event, X-GitHub-Delivery, and signature headers.
  5. Authenticate and validate. Check the signature over the exact raw request body before parsing or acting on it.
  6. Deduplicate and acknowledge. Record the provider’s delivery or event ID, return a fast 2XX response, and put slow work on a queue or background worker.

CloudEvents’ HTTP binding requires a 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, so the provider’s documentation is authoritative.

What a delivery contains

A typical delivery has four parts:

  • Method and URL: usually POST to your registered endpoint.
  • Headers: content type, event type, delivery ID, timestamp, and one or more signature values. Names and formats vary.
  • Body: event data, commonly JSON. It might contain an object snapshot, changed fields, or a reference that your application must retrieve through the provider API.
  • Transport result: your HTTP status code and response time, which the provider uses to decide whether to retry.

A minimal, secure Node.js receiver

The example below uses Express and HMAC-SHA-256, the algorithm GitHub documents for X-Hub-Signature-256. It preserves the raw body for signature verification, rejects invalid requests, deduplicates deliveries, and queues work conceptually. Replace the header names and signing rules with those specified by your provider.

  1. Install dependencies: npm install express.
  2. Set a high-entropy secret in the environment: export WEBHOOK_SECRET='replace-with-a-long-random-secret'.
  3. Save this as server.js and run node server.js.
const express = require('express');
const crypto = require('crypto');

const app = express();
const secret = process.env.WEBHOOK_SECRET;
if (!secret) throw new Error('WEBHOOK_SECRET is required');

// Keep the exact bytes for HMAC verification.
app.use('/webhooks/provider', express.raw({ type: 'application/json' }));

const seenDeliveries = new Set(); // Use durable storage in production.

function validSignature(rawBody, received) {
  if (typeof received !== 'string' || !received.startsWith('sha256=')) return false;
  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);
}

app.post('/webhooks/provider', (req, res) => {
  const signature = req.get('X-Hub-Signature-256');
  if (!validSignature(req.body, signature)) {
    return res.status(401).send('invalid signature');
  }

  let event;
  try {
    event = JSON.parse(req.body.toString('utf8'));
  } catch {
    return res.status(400).send('invalid JSON');
  }

  const deliveryId = req.get('X-Provider-Delivery');
  if (!deliveryId) return res.status(400).send('missing delivery ID');

  // In production, atomically insert this ID with a unique constraint.
  if (seenDeliveries.has(deliveryId)) return res.sendStatus(200);
  seenDeliveries.add(deliveryId);

  // Queue processEvent(event) instead of doing slow work in this request.
  console.log('accepted event', event.type, deliveryId);
  return res.sendStatus(202);
});

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

Do not parse JSON before verifying a signature unless the provider explicitly defines a canonicalization scheme. Whitespace, key order, and character encoding can change the bytes that are signed. Also replace the in-memory Set with a database table or durable key-value store so deduplication survives restarts and works across multiple instances.

Webhook security checklist

Verify authenticity before business logic

Treat every incoming request as untrusted. Use the provider’s signature algorithm, secret, timestamp rules, and header names exactly. GitHub’s guidance uses an HMAC SHA-256 value in X-Hub-Signature-256 and recommends constant-time comparison. Never accept a signature supplied as a URL parameter.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Protect transport and secrets

  • Require HTTPS and reject plain HTTP in production.
  • Keep secrets in a secret manager or environment configuration, not source control.
  • Rotate secrets using the provider’s documented overlap procedure.
  • Keep credentials out of URLs; URLs leak through logs, browser history, and proxy metadata.
  • Apply request-size limits and reject unsupported content types.
  • Restrict administrative webhook configuration with strong authentication and least privilege.

Defend against replay

If the provider signs a timestamp, reject requests outside a reasonable clock-skew window and include the timestamp in the signed data. Even without timestamps, store delivery IDs and refuse to process an ID that has already succeeded. A valid old request should not be able to trigger an irreversible action repeatedly.

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option

Retries, duplicates, and reliable processing

A network timeout does not tell the provider whether your application completed the work. Providers can retry failed or ambiguous deliveries, and a request can be duplicated by the network or by your own queue. The Standard Webhooks specification describes a unique event identifier that remains the same across retries.

  1. Read the delivery or event ID.
  2. Persist it with a unique constraint before performing irreversible work.
  3. Return a successful response once the event is durably accepted.
  4. Process the event asynchronously.
  5. Mark the job complete and retain enough logs to investigate failures.

Make handlers idempotent. For example, use an upsert keyed by the provider’s object ID rather than blindly inserting a new order on every delivery. If a downstream operation cannot be made naturally idempotent, store an operation key and check it before retrying.

Acknowledge quickly. GitHub recommends responding within 10 seconds; expensive database migrations, third-party API calls, and report generation belong in a queue or worker. Hookdeck, Resque, RQ, and RabbitMQ are examples GitHub names for background-processing or delivery workflows, but the correct choice depends on your stack.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Webhook versus polling

Consideration Webhook Polling
Notification timing Usually close to the event, subject to provider and network delay Bound by the interval between requests
Request volume Requests arrive when subscribed events occur Repeated requests occur even when nothing changed
Receiver requirement Publicly reachable endpoint, or a secure relay/tunnel Client only needs outbound access to the API
Security work Signature validation, secret handling, replay defense API authentication and response validation
Failure handling Retries, duplicates, replay, and provider redelivery controls Checkpointing, rate limits, missed intervals, and pagination
Operational complexity Event receiver and queue must be monitored Scheduler and polling workers must be monitored

Webhooks reduce needless requests and latency when the provider supports the event you need. Polling remains useful when no webhook exists, when you need periodic reconciliation, or when inbound connectivity is impossible. Many robust systems use both: webhooks for prompt updates and a scheduled API poll to repair missed events.

Provider differences you must check

“Webhook” describes a delivery pattern, not a universal protocol. Before implementing, document:

  • Event names and whether they are versioned.
  • Envelope fields, object schemas, and whether the payload is a snapshot or a delta.
  • Signature algorithm, signed bytes, timestamp tolerance, and header names.
  • Delivery and event ID semantics.
  • Timeout limits, retry schedule, maximum attempts, and manual redelivery.
  • Payload-size limits. GitHub documents a 25 MB cap for its webhooks; that number must not be generalized to other providers.
  • Required response status codes and whether a 202 is accepted.
  • Ordering guarantees, if any, and how to fetch the current object state.

Testing and observability

Use the provider’s test-delivery function or a staging endpoint. Log a correlation ID, event type, delivery ID, verification result, queue ID, processing duration, and final status. Do not log secrets or full payloads that contain personal or payment data.

Useful failure signals

  • 401 or 403: signature, secret, timestamp, or access-control mismatch.
  • 400: malformed JSON, unsupported content type, or missing required header.
  • 404: the registered path or deployment route is wrong.
  • 413: a proxy or application body limit is too small.
  • 429: rate limiting; check whether retries will amplify the load.
  • 5XX or timeout: provider retries are likely; inspect queue and worker health.

Troubleshooting common webhook failures

The provider reports a timeout

Return a response immediately after authentication and durable enqueueing. Move network calls and CPU-heavy work to a worker, and check reverse-proxy timeout settings.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Every signature is invalid

Confirm that you are hashing the raw bytes, not a reserialized JSON object; use the correct secret and header; check whether the provider prefixes the digest with text such as sha256=; and compare values in constant time.

Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • 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

Events are processed twice

Persist the provider’s stable delivery or event ID with a unique constraint. If the provider uses different IDs for retries, derive an idempotency key from the documented event/object identifiers and verify that this is safe for the event type.

Events arrive out of order

Do not assume network order unless the provider guarantees it. Store event timestamps or sequence numbers when available, and retrieve the provider’s current resource state before applying a stale update.

Local development cannot receive deliveries

Use a secure HTTPS tunnel or a staging relay, restrict test secrets, and never expose an unrestricted administrative endpoint. Ensure the public URL forwards the exact path and preserves request bodies and headers.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If a webhook ultimately changes a public status page, dashboard, or generated report and you need a clean image of that result, ScreenshotNeo can capture it with one request. It accepts cookie or consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the capture; bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

For the full parameter list, see the ScreenshotNeo documentation. A simple call is:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

You get 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

Frequently Asked Questions

Can a webhook call an internal service instead of a public URL?

Usually the provider must reach a publicly routable HTTPS endpoint. If the application is private, place a narrowly scoped relay or gateway in front of it and forward only authenticated, validated deliveries.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should a webhook endpoint return 200 or 202?

Use the status code accepted by that provider. Return it only after authentication and durable acceptance; do not claim success while the event exists only in volatile memory.

Are webhooks guaranteed to arrive in order?

Not unless the provider explicitly guarantees ordering. Design consumers to tolerate delays and out-of-order events, and retrieve current resource state when necessary.

What should be retained for an audit trail?

Keep the delivery ID, event type, receipt time, verification result, processing status, and relevant error details while minimizing or redacting sensitive payload data.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.