Gareth Wilson Gareth Wilson

Guide to YouCanBookMe Webhooks: Features and Best Practices

Published


YouCanBookMe webhooks let your booking pages update the rest of your stack. When someone books, reschedules or cancels a meeting, YouCanBookMe can send the booking details straight to your endpoint, so you can create a CRM record, open a ticket, prepare a video room or start an onboarding sequence without waiting for someone to copy the details across.

This guide covers how YouCanBookMe webhooks work, how to build the request and its payload, how to authenticate it with a secret header, and the practices that keep a YouCanBookMe receiver reliable.

What are YouCanBookMe webhooks?

In YouCanBookMe, a webhook is one of the actions a booking page can take in its notifications workflow, alongside emails and other notifications. You attach a webhook action to a trigger, and YouCanBookMe sends an HTTP request to your URL when that trigger fires for a booking.

You design the request. You choose the method, add any request headers and write the body as a JSON template, using shorthand codes that YouCanBookMe replaces with the booking's details when it sends. YouCanBookMe adds no event type, envelope or signature of its own. If your receiver needs to know which trigger fired, put that in the template. To authenticate the request, add a secret request header.

Webhooks are separate from YouCanBookMe's API, which you call, and from its Zapier integration.

YouCanBookMe webhook features

FeatureDetails
ConfigurationA webhook action in a booking page's notifications workflow
TriggersBooking made, rescheduled or cancelled, reminders before the booking, follow-ups after it, and no-shows
DelaySet per action. 0 sends immediately
MethodGET, POST, PUT, PATCH or DELETE
BodyA JSON template you write with shorthand codes. It must be valid JSON
Special characters{ENCODE-FOR-URL} and {ENCODE-FOR-JSON} tags
Custom headersRequest headers as key and value pairs
Signature and timestampNone
Event typeNone. Defined by your template
Timeout and retriesNot documented
Content-TypeNot documented
Source IPsNot published
PlansThe help articles disagree. Check your plan before you build on it

What YouCanBookMe sends

YouCanBookMe's own example payload looks like this:

{
  "startDateTime": "{START-ISO}",
  "endDateTime": "{END-ISO}",
  "firstName": "{FNAME}",
  "email": "{EMAIL}"
}

When the trigger fires, each shorthand code is replaced with the booking's value, so your endpoint receives the start and end times, the booker's first name and their email address. Any field the booking form collects can be passed through if it has a shorthand code, including custom ones you create.

Nothing in that body says whether the booking was made, moved or cancelled. Add a field for it, with a different value in each trigger's webhook action:

{
  "event": "booking_cancelled",
  "startDateTime": "{START-ISO}",
  "email": "{EMAIL}"
}

The event field and its values are your own convention. YouCanBookMe sends whatever text you put there.

Inspect YouCanBookMe webhooks as they arrive. Point a webhook action at a Hookdeck Inspect URL to see the exact method, headers and body your template produces, with no account or setup required.

Setting up YouCanBookMe webhooks

Generate a long random secret first, for example with openssl rand -hex 32.

  1. Select the booking page and click Edit Settings.
  2. Open Additional options, then Notifications.
  3. Open the notification you want the webhook to follow, such as a new booking, a cancellation or a reminder.
  4. Click +, then Webhook.
  5. Leave the delay at 0 to send immediately, and enter your HTTPS URL.
  6. Choose the method. POST is the simplest.
  7. In the header space, add a key and value pair: a header name such as X-YCBM-Secret and your secret.
  8. Write the JSON payload with your shorthand codes and an event field, then save.

Repeat for each trigger you need. Each webhook action is configured separately, so remember to give each one the header and its own event value.

The help articles disagree about which plans include webhooks. "Passing data to other systems" says the feature is available on all plans, while "More information on Webhooks" says it is available on the Professional and Teams plans. Check that your plan has the webhook action before you rely on it.

To route through Hookdeck, create a Hookdeck source with the YouCanBookMe type and use its URL as the webhook URL. The source asks for an API Key Header and an API Key: enter the header you added and its exact value, including any Bearer prefix. The source pre-selects POST but leaves the method open, because the webhook action lets you choose. If your action uses GET, PUT, PATCH or DELETE, add that method to the source's allowed HTTP methods as well.

Securing YouCanBookMe webhooks

Read the header you chose, compare its whole value with your stored secret in constant time, and reject the request if either is missing. YouCanBookMe doesn't document the Content-Type it sends, so read the body raw and parse it after the check.

const crypto = require('crypto');
const express = require('express');

const HEADER_NAME = (process.env.YOUCANBOOKME_WEBHOOK_HEADER || 'x-ycbm-secret').toLowerCase();
const SECRET = process.env.YOUCANBOOKME_WEBHOOK_SECRET;

function safeEqual(received, expected) {
  const a = Buffer.from(received, 'utf8');
  const b = Buffer.from(expected, 'utf8');
  // timingSafeEqual throws on unequal lengths, so check first.
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

const app = express();

app.post('/webhooks/youcanbookme', express.raw({ type: '*/*' }), (req, res) => {
  const received = req.get(HEADER_NAME);
  if (!SECRET || typeof received !== 'string' || !safeEqual(received, SECRET)) {
    return res.sendStatus(401);
  }

  let booking;
  try {
    booking = JSON.parse(req.body.toString('utf8'));
  } catch {
    return res.sendStatus(400);
  }

  // Fields are whatever your template defines, e.g. booking.event and booking.email.
  res.sendStatus(200);
});

The same check in Python:

import hmac
import os

HEADER_NAME = os.environ.get("YOUCANBOOKME_WEBHOOK_HEADER", "X-YCBM-Secret")
SECRET = os.environ.get("YOUCANBOOKME_WEBHOOK_SECRET", "")


def verify_youcanbookme_request(headers) -> bool:
    if not SECRET:
        return False  # never accept when unconfigured
    received = headers.get(HEADER_NAME)  # Starlette and Flask headers are case-insensitive
    if not received:
        return False
    # Compare bytes: compare_digest raises TypeError on a non-ASCII str.
    return hmac.compare_digest(received.encode("utf-8"), SECRET.encode("utf-8"))

A static header proves the sender knows the secret. It does not cover the body, and there is no timestamp, so a captured request can be replayed and will still pass. Use HTTPS, and if the secret might have leaked, change it in every webhook action and in your receiver together.

Make YouCanBookMe webhooks production-ready. Hookdeck Event Gateway checks the secret header you configure, stores every booking notification durably, and retries delivery to your service, which YouCanBookMe does not document doing for you.

YouCanBookMe webhook limitations and pain points

No documented retries

The Problem: If your endpoint is down when a booking comes in, you may never receive that booking's webhook.

Why It Happens: YouCanBookMe's help articles say nothing about timeouts, retries or what happens after a failed request.

Workarounds:

  • Keep the endpoint fast and highly available, and return 2xx as soon as the request is stored.
  • Reconcile regularly against YouCanBookMe's API or booking list, so a missed booking is caught.
  • Keep the confirmation emails as a second record while you build trust in the integration.

How Hookdeck Can Help: Hookdeck accepts each request as soon as it arrives and stores it, then delivers to your service with retries you control. You can replay any booking notification after a fix.

The payload doesn't say what happened

The Problem: A webhook from the cancellation trigger can look exactly like one from the new booking trigger.

Why It Happens: The body is your template, and YouCanBookMe adds no field or header naming the trigger.

Workarounds:

  • Add an event field to every webhook action with a value unique to its trigger.
  • Or give each trigger its own URL path.

How Hookdeck Can Help: Hookdeck filters can route on the event field or the path, sending cancellations and new bookings to different destinations.

Special characters can break the template

The Problem: A booker's name or answer containing a quote mark, accent or other special character can arrive mangled or make the body invalid JSON.

Why It Happens: Shorthand codes are filled into your template with the booker's own text, and YouCanBookMe provides encoding tags because special characters may not otherwise come through correctly.

Workarounds:

  • Use the {ENCODE-FOR-JSON} tag in the payload and {ENCODE-FOR-URL} in the URL, as YouCanBookMe recommends for special characters.
  • Validate your template as JSON before saving, and test with a booking whose name contains a quote mark and an accented letter.

How Hookdeck Can Help: Every request is stored with its raw body, so you can see what arrived, fix the template, and transform or replay affected requests.

The secret is only as good as the header

The Problem: Nothing proves a request body came from YouCanBookMe unchanged.

Why It Happens: There is no signature, only the static header you add.

Workarounds:

  • Use a long random secret, sent only over HTTPS.
  • Treat the webhook as a signal, and confirm anything consequential through YouCanBookMe's API before acting.

How Hookdeck Can Help: Hookdeck's YouCanBookMe source compares the header you name with the exact value you enter. Hookdeck answers with a 200 either way, but requests that fail the check are recorded as failed verification and never reach your service.

Best practices

Use POST with a JSON payload

The webhook action offers five methods, and the help articles describe them inconsistently. POST with a JSON body is the easiest to authenticate, parse and route.

Include a stable booking reference

Put a shorthand code that identifies the booking in every payload if one is available to you, or combine the email address with {START-ISO}, so reschedules and cancellations can be matched to the original booking and duplicates can be dropped. See our guide to webhook idempotency.

Use ISO timestamps

Prefer {START-ISO} and {END-ISO} over local date formats, so your receiver doesn't have to guess the time zone.

Configure every trigger the same way

Each notification's webhook action has its own URL, header and template. Keep a checklist, and check all of them when you rotate the secret.

Acknowledge fast and process asynchronously

Store the request, return 2xx, and do the work afterwards. See why to process webhooks asynchronously.

Conclusion

YouCanBookMe webhooks are notification actions that send a request you design: a JSON template filled with shorthand codes, with no signature and no event type. Add a long random secret as a request header, compare it whole in constant time over HTTPS, name the trigger in each template, encode special characters, and plan for the fact that retries are not documented.

Hookdeck Event Gateway checks the header, keeps every booking notification, and retries and replays delivery to your service, so an outage on your side doesn't lose a booking.

Get started with Hookdeck for free and handle YouCanBookMe webhooks reliably in minutes.


Gareth Wilson

Gareth Wilson

Product Marketing

Multi-time founding marketer, Gareth is PMM at Hookdeck and author of the newsletter, Community Inc.