Cookies

We use essential cookies to make our site work. With your consent, we also use cookies for analytics (Google Analytics) and targeted marketing (Meta Pixel). Read Privacy Policy

Developers & IntegrationsWebhooks
Developers & Integrations

Webhooks

Get an HTTP request the moment an appointment is created, confirmed, rescheduled, cancelled or completed, and connect BookifyLabs to your own systems.

Add an endpoint

  1. As an owner, open Settings in business scope and find the Webhooks card.
  2. Click Add endpoint and enter a public https:// URL. Private network addresses and localhost are refused.
  3. Copy the signing secret shown after creation. It starts with whsec_ and is displayed only once.
  4. Send a test event by creating an appointment, then check the Deliveries list.

You can have up to 5 endpoints per business. Each can be paused and resumed, have its URL changed, its secret regenerated, or be deleted along with its delivery history.

Events

EventSent when
appointment.createdA booking is made, online, by Booky or by your team.
appointment.confirmedA pending appointment is confirmed.
appointment.rescheduledThe time or professional changes.
appointment.cancelledThe appointment is cancelled by you or the customer.
appointment.completedThe appointment is marked done through the completion screen.

Request format

Every delivery is a POST with a JSON body. The data object is a snapshot of the appointment at the moment the event happened; retries resend the same body.

POST https://example.com/hooks/bookify
Content-Type: application/json
User-Agent: BookifyLabs-Webhooks/1.0 (+https://bookifylabs.com)
X-Bookify-Event-ID: evt_3f6c…
X-Bookify-Timestamp: 1757145600
X-Bookify-Signature: 4b1d…

{
  "id": "evt_3f6c…",
  "type": "appointment.created",
  "created_at": 1757145600,
  "data": {
    "appointment": { "id": 1234, "status": "booked", "start_at": "…", "…": "…" }
  }
}

Verify the signature

The signature is a hex HMAC-SHA256 over the string <timestamp>.<raw body>, keyed with your endpoint secret. Compute it from the raw request body, before any JSON parsing, and compare with a constant-time function.

import crypto from "node:crypto";

function verify(rawBody, headers, secret) {
  const ts = headers["x-bookify-timestamp"];
  const sig = headers["x-bookify-signature"];
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // older than 5 minutes
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${ts}.${rawBody}`)
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}
  • Reject timestamps older than 5 minutes to defeat replay.
  • De-duplicate on X-Bookify-Event-ID: a retry carries the same id.
  • Respond with any 2xx within 10 seconds. Do slow work after responding.

Retries and delivery history

A delivery that times out, or gets a 408, 425, 429 or any 5xx response, is retried every 12 hours for up to 30 attempts. Redirects are not followed and other 4xx responses are treated as final. The Deliveries table shows each event's status (pending, sending, retrying, delivered, failed), attempts, the response we stored (up to 4 KB) and the next attempt time. Failed or retrying deliveries can be pushed with Retry now. History is kept for 30 days.

Good to knowRegenerating a secret invalidates the old one immediately. Update your receiver first if you cannot tolerate a gap, or pause the endpoint while you switch.