Webhooks

Receive real-time notifications when events occur in your BookingScheduler account

Overview

Webhooks allow you to build integrations that subscribe to certain events in your BookingScheduler account. When one of those events is triggered, we'll send an HTTP POST payload to the webhook's configured URL.

Webhooks can be used to:

  • Update your internal systems when bookings are created or modified
  • Send custom notifications to customers
  • Sync data with external platforms
  • Trigger automated workflows

Setting Up Webhooks

  1. 1
    Go to Webhook Settings

    Navigate to Organization Settings → Integrations → Webhooks

  2. 2
    Add Endpoint URL

    Enter the URL where you want to receive webhook events

  3. 3
    Select Events

    Choose which events you want to subscribe to

  4. 4
    Save and Test

    Save your webhook and send a test event to verify it works

Available Events

Booking Events

booking.created

Booking Created

Triggered when a new booking is created

Payload Example

{
  "event": "booking.created",
  "timestamp": "2024-01-15T10:00:00Z",
  "data": {
    "id": "book_123",
    "experienceId": "exp_456",
    "experienceName": "City Walking Tour",
    "customerName": "John Doe",
    "customerEmail": "[email protected]",
    "startTime": "2024-02-15T14:00:00Z",
    "participants": 2,
    "status": "CONFIRMED",
    "totalAmount": 9000,
    "currency": "USD"
  }
}
booking.confirmed

Booking Confirmed

Triggered when a pending booking is confirmed

Payload Example

{
  "event": "booking.confirmed",
  "timestamp": "2024-01-15T10:05:00Z",
  "data": {
    "id": "book_123",
    "status": "CONFIRMED",
    "confirmedAt": "2024-01-15T10:05:00Z"
  }
}
booking.cancelled

Booking Cancelled

Triggered when a booking is cancelled

Payload Example

{
  "event": "booking.cancelled",
  "timestamp": "2024-01-15T10:10:00Z",
  "data": {
    "id": "book_123",
    "status": "CANCELLED",
    "cancelledAt": "2024-01-15T10:10:00Z",
    "reason": "Customer request",
    "refundAmount": 9000,
    "refundStatus": "PENDING"
  }
}
booking.updated

Booking Updated

Triggered when booking details are modified

Payload Example

{
  "event": "booking.updated",
  "timestamp": "2024-01-15T10:15:00Z",
  "data": {
    "id": "book_123",
    "changes": {
      "participants": {
        "old": 2,
        "new": 3
      },
      "totalAmount": {
        "old": 9000,
        "new": 13500
      }
    }
  }
}

Payment Events

payment.succeeded

Payment Succeeded

Triggered when a payment is successfully processed

Payload Example

{
  "event": "payment.succeeded",
  "timestamp": "2024-01-15T10:20:00Z",
  "data": {
    "id": "pay_789",
    "bookingId": "book_123",
    "amount": 9000,
    "currency": "USD",
    "method": "card",
    "status": "SUCCEEDED"
  }
}
payment.failed

Payment Failed

Triggered when a payment fails

Payload Example

{
  "event": "payment.failed",
  "timestamp": "2024-01-15T10:25:00Z",
  "data": {
    "id": "pay_789",
    "bookingId": "book_123",
    "amount": 9000,
    "currency": "USD",
    "status": "FAILED",
    "errorCode": "CARD_DECLINED",
    "errorMessage": "The card was declined"
  }
}

Customer Events

customer.created

Customer Created

Triggered when a new customer is created

Payload Example

{
  "event": "customer.created",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "id": "cust_321",
    "name": "Jane Smith",
    "email": "[email protected]",
    "phone": "+1234567890",
    "createdAt": "2024-01-15T10:30:00Z"
  }
}

Handling Webhooks

Example webhook handler implementation

// Express.js example
const express = require('express');
const app = express();

app.post('/webhooks/bookingscheduler', express.json(), (req, res) => {
  const event = req.body;

  // Verify webhook signature (see Signature Verification section)
  const signature = req.headers['x-bookingscheduler-signature'];
  if (!verifySignature(signature, req.body)) {
    return res.status(401).send('Invalid signature');
  }

  // Handle different event types
  switch (event.event) {
    case 'booking.created':
      console.log('New booking:', event.data.id);
      // Your custom logic here
      break;

    case 'booking.cancelled':
      console.log('Booking cancelled:', event.data.id);
      // Your custom logic here
      break;

    case 'payment.succeeded':
      console.log('Payment succeeded:', event.data.id);
      // Your custom logic here
      break;

    default:
      console.log('Unhandled event:', event.event);
  }

  // Acknowledge receipt
  res.status(200).send('OK');
});

app.listen(3000);

Signature Verification

BookingScheduler signs webhook payloads with a signature that you can use to verify the webhook came from us. The signature is included in the X-BookingScheduler-Signature header.

Verification Steps:

  1. Get your webhook signing secret from your dashboard
  2. Compute an HMAC with the SHA256 hash function
  3. Compare the computed signature with the received signature

Example Implementation (Node.js):

const crypto = require('crypto');

function verifySignature(signature, payload) {
  const secret = process.env.WEBHOOK_SIGNING_SECRET;
  const hmac = crypto.createHmac('sha256', secret);
  const digest = hmac.update(JSON.stringify(payload)).digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(digest)
  );
}

Best Practices

Do

  • ✓ Verify webhook signatures
  • ✓ Respond with 200 status code quickly
  • ✓ Process webhooks asynchronously
  • ✓ Implement retry logic for failed processing
  • ✓ Log all webhook events
  • ✓ Use HTTPS endpoints

Don't

  • ✗ Process webhooks synchronously
  • ✗ Assume webhooks arrive in order
  • ✗ Rely on duplicate webhook prevention
  • ✗ Expose your webhook endpoint publicly without verification
  • ✗ Use HTTP (non-secure) endpoints