Overview
This guide sets up a production-safe webhook integration with signature validation and idempotent processing.
Prerequisites
- HTTPS endpoint under your control
- Access to tenant webhook settings
- Secret storage for webhook signing key
1) Register endpoint
Create a webhook endpoint from tenant settings and capture:
- endpoint ID
- signing secret
- subscribed event types
2) Receive requests
Your endpoint should:
- accept
POST - respond
2xxquickly - enqueue work for async processing
3) Verify signature
import crypto from "node:crypto";
export function verifySignature(rawBody: string, signature: string, secret: string) {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected, "utf8"),
Buffer.from(signature, "utf8")
);
}
4) Enforce replay protection
- Store delivery ID for a bounded window.
- Reject duplicate delivery IDs.
- Return
2xxfor already-processed deliveries.
5) Implement idempotent handlers
Use event ID or aggregate version checks so retries do not duplicate side effects.
6) Retry and failure behavior
- Non-
2xxresponses are retried with backoff. - Timeout and network errors are retried.
- Keep handlers short; offload heavy jobs to queues.
Troubleshooting
- Invalid signature: confirm raw-body handling and shared secret.
- Repeated retries: return
2xxonly after durable persistence. - Missing events: check endpoint subscription filters and delivery logs.
Next steps
- Signature details:
/docs/reference/webhook-signatures - Event catalog:
/docs/reference/webhook-events - Incident model:
/docs/reference/incident-comms