Skip to content

Webhooks

The Booking Kit’s webhook system delivers signed HTTP payloads to subscriber endpoints when booking events occur.

Every webhook payload is signed with the subscription’s secret:

import { signWebhookPayload, verifyWebhookSignature, SIGNATURE_HEADER, TIMESTAMP_HEADER } from "@thebookingkit/core";
// Signing (sender side)
const signature = signWebhookPayload(payload, secret, timestamp);
// Verification (receiver side)
const result = verifyWebhookSignature(
payload,
signature, // From X-The Booking Kit-Signature header
timestamp, // From X-The Booking Kit-Timestamp header
secret,
);
// Returns: WebhookVerificationResult { valid, reason? }

The timestamp is included in the signature computation. verifyWebhookSignature() rejects payloads older than the tolerance window (default: 300 seconds).

TriggerPayload
booking.createdFull booking data
booking.confirmedBooking with status change
booking.cancelledBooking with cancellation reason
booking.rescheduledOld and new booking data
booking.completedCompleted booking data
booking.no_showNo-show booking data
import { createWebhookEnvelope } from "@thebookingkit/core";
const envelope = createWebhookEnvelope(
"booking.created",
bookingData,
subscription,
);
// Returns: WebhookEnvelope
// { id, trigger, payload, signature, timestamp, subscriptionId }

Failed deliveries are retried with exponential backoff:

import { getRetryDelay, isSuccessResponse, DEFAULT_RETRY_CONFIG } from "@thebookingkit/core";
// Default config: 3 retries, 60s base delay, 3600s max delay
const delay = getRetryDelay(attemptNumber, DEFAULT_RETRY_CONFIG);
// Attempt 0: ~60s, Attempt 1: ~120s, Attempt 2: ~240s
isSuccessResponse(200); // true (2xx)
isSuccessResponse(500); // false
import { validateWebhookSubscription, matchWebhookSubscriptions } from "@thebookingkit/core";
// Validate a subscription
validateWebhookSubscription({
url: "https://example.com/webhooks",
triggers: ["booking.created", "booking.cancelled"],
secret: "whsec_...",
});
// Find subscriptions matching a trigger
const matching = matchWebhookSubscriptions(allSubscriptions, "booking.created");
import { resolvePayloadTemplate } from "@thebookingkit/core";
const customPayload = resolvePayloadTemplate(
{ event: "{{trigger}}", customer: "{{booking.customerName}}" },
context
);
import { WebhookManager } from "./components/webhook-manager";
<WebhookManager
webhooks={subscriptions}
deliveryLogs={logs}
onCreateWebhook={handleCreate}
onDeleteWebhook={handleDelete}
onTestWebhook={handleTest}
/>