Docs menu ▾

Developers

Webhooks

Get a POST request on your server the moment something happens: a booking is made, moved, cancelled or paid, a form is submitted, someone registers for an event.

Set one up#

Go to Settings → Developer → Webhooks, add your server's public URL (use https://), choose the triggers and set a secret (one is generated for you if you leave it empty). Use Ping to send a test, and Deliveries to see every request and your server's reply. Your plan needs Webhooks.

Triggers#

TriggerSent when
BOOKING_CREATEDA booking is made (or a pending one is confirmed).
BOOKING_REQUESTEDA booking needs your confirmation.
BOOKING_RESCHEDULEDA booking moves to a new time.
BOOKING_CANCELLEDA booking is cancelled, or you ask the person to reschedule.
BOOKING_REJECTEDYou decline a booking.
BOOKING_PAIDPayment for a booking succeeds.
BOOKING_NO_SHOW_UPDATEDYou mark (or unmark) a no-show.
FORM_SUBMITTEDSomeone submits a routing form.
EVENT_REGISTRATION_CREATEDSomeone registers for one of your events.
EVENT_REGISTRATION_CANCELLEDA registration is cancelled.
EVENT_CANCELLEDYou cancel an event.

What you receive#

A JSON POST with the trigger in the X-Scheduler-Trigger header. Reply with any 2xx status within a few seconds; do slow work after replying.

BOOKING_CREATED
{
  "triggerEvent": "BOOKING_CREATED",
  "createdAt": "2026-10-12T14:03:11.000Z",
  "payload": {
    "uid": "bk_7h2k9…",
    "title": "Consultation between Ada Obi and Tunde Bello",
    "type": "consultation",
    "eventTypeId": "evt_abc123",
    "startTime": "2026-10-15T08:30:00.000Z",
    "endTime": "2026-10-15T09:30:00.000Z",
    "status": "accepted",
    "organizer": { "name": "Ada Obi", "email": "[email protected]", "timeZone": "Africa/Lagos" },
    "attendees": [{ "name": "Tunde Bello", "email": "[email protected]", "timeZone": "Africa/Lagos" }],
    "responses": { "topic": "Pricing" },
    "additionalNotes": "Booked from our app",
    "location": { "type": "google-meet", "url": "https://meet.google.com/abc-defg-hij" },
    "payment": { "amount": 2500000, "currency": "NGN", "status": "paid", "provider": "paystack" }
  }
}
You can change the body's shape per webhook with a custom payload: write your own JSON and use variables like {{title}}, {{startTime}}, {{attendeeName}}, {{attendeeEmail}}, {{organizerName}} or any payload field with dots, e.g. {{location.url}}.

Check the signature#

Every request has an X-Scheduler-Signature-256 header: the HMAC-SHA256 of the raw request body, keyed with your webhook's secret, as lowercase hex. Compute it yourself and compare before trusting the request.

import crypto from "node:crypto";
import express from "express";

const app = express();
// Use the raw body: re-serialising the JSON changes it and breaks the signature.
app.post("/webhooks/zylux-meet", express.raw({ type: "application/json" }), (req, res) => {
  const expected = crypto.createHmac("sha256", process.env.WEBHOOK_SECRET).update(req.body).digest("hex");
  const given = req.get("X-Scheduler-Signature-256") ?? "";
  const ok = given.length === expected.length && crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
  if (!ok) return res.status(401).end();

  const event = JSON.parse(req.body.toString("utf8"));
  if (event.triggerEvent === "BOOKING_CREATED") {
    // save event.payload ...
  }
  res.sendStatus(200);
});

Manage webhooks with the API#

GET/api/webhooksAPI key
Your webhooks.
POST/api/webhooksAPI key
Create one. Body: { "subscriberUrl": "https://…", "triggers": ["BOOKING_CREATED"], "secret": "…" }. Optional: eventTypeId (only that link), payloadTemplate, active.
PATCH/api/webhooks/{id}API key
Change it.
DELETE/api/webhooks/{id}API key
Delete it.
POST/api/webhooks/{id}/pingAPI key
Send a test request.
GET/api/webhooks/{id}/deliveriesAPI key
Recent requests and your server's replies.
cURL
curl -X POST https://meet.zyluxmedia.app/api/webhooks \
  -H "Authorization: Bearer $ZYLUX_MEET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "subscriberUrl": "https://your-app.com/webhooks/zylux-meet", "triggers": ["BOOKING_CREATED", "BOOKING_CANCELLED"], "secret": "a-long-random-string" }'