Search docs...

Cmd+K

Webhooks

Receive real-time notifications about events in your Bookwell account.

Webhooks allow your application to receive real-time notifications when events occur in Bookwell, such as new bookings or cancellations.

Overview

When an event occurs, Bookwell sends an HTTP POST request to your configured endpoint with event data. Your server processes the event and responds.

Bookwell Event → Your Endpoint → Your Application

Setting Up Webhooks

Create a Webhook Endpoint

1
Access Webhook Settings

Go to Settings > Webhooks in your admin dashboard.

2
Add Endpoint

Click Add Endpoint and provide:

  • URL - Your endpoint URL (must be HTTPS)
  • Events - Which events to receive
  • Description - Optional description
3
Get Signing Secret

Copy the signing secret for verifying webhook signatures.

Endpoint Requirements

Your endpoint must:

  • Use HTTPS
  • Accept POST requests
  • Respond within 30 seconds
  • Return 2xx status code

Event Types

Appointment Events

EventDescription
appointment.createdNew appointment booked
appointment.updatedAppointment modified
appointment.cancelledAppointment cancelled
appointment.completedService completed
appointment.no_showCustomer didn't arrive

Customer Events

EventDescription
customer.createdNew customer registered
customer.updatedCustomer info changed

Payment Events

EventDescription
payment.completedPayment successful
payment.failedPayment failed
payment.refundedRefund processed

Gift Card Events

EventDescription
gift_card.purchasedGift card sold
gift_card.redeemedGift card used

Webhook Payload

Event Structure

All webhooks follow this structure:

{
  "id": "evt_abc123",
  "type": "appointment.created",
  "created_at": "2025-01-15T10:30:00Z",
  "data": {
    "object": {
      "id": "apt_xyz789",
      "service_name": "60-Minute Massage",
      "customer_email": "jane@example.com",
      "start_time": "2025-01-20T14:00:00Z"
    }
  }
}

Example: Appointment Created

{
  "id": "evt_abc123",
  "type": "appointment.created",
  "created_at": "2025-01-15T10:30:00Z",
  "data": {
    "object": {
      "id": "apt_xyz789",
      "service_id": "srv_def456",
      "service_name": "60-Minute Massage",
      "customer_id": "cus_ghi012",
      "customer_name": "Jane Smith",
      "customer_email": "jane@example.com",
      "therapist_id": "thr_jkl345",
      "therapist_name": "Sarah Johnson",
      "start_time": "2025-01-20T14:00:00Z",
      "end_time": "2025-01-20T15:00:00Z",
      "status": "confirmed",
      "price": 9500,
      "currency": "usd"
    }
  }
}

Example: Appointment Cancelled

{
  "id": "evt_def456",
  "type": "appointment.cancelled",
  "created_at": "2025-01-18T09:00:00Z",
  "data": {
    "object": {
      "id": "apt_xyz789",
      "status": "cancelled",
      "cancellation_reason": "Customer request",
      "refund_amount": 9500,
      "cancelled_at": "2025-01-18T09:00:00Z"
    },
    "previous_attributes": {
      "status": "confirmed"
    }
  }
}

Verifying Webhooks

Important

Always verify webhook signatures to ensure requests come from Bookwell.

Signature Verification

Each webhook includes a signature in the X-Bookwell-Signature header:

X-Bookwell-Signature: t=1704067200,v1=abc123...

Verification Steps

const crypto = require('crypto');
 
function verifyWebhook(payload, signature, secret) {
  const [timestamp, hash] = signature.split(',');
  const ts = timestamp.split('=')[1];
  const sig = hash.split('=')[1];
 
  const signedPayload = `${ts}.${payload}`;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');
 
  return crypto.timingSafeEqual(
    Buffer.from(sig),
    Buffer.from(expected)
  );
}

Timestamp Validation

Reject events older than 5 minutes to prevent replay attacks:

const eventTime = parseInt(timestamp);
const currentTime = Math.floor(Date.now() / 1000);
const tolerance = 300; // 5 minutes
 
if (currentTime - eventTime > tolerance) {
  throw new Error('Webhook too old');
}

Handling Webhooks

Best Practices

  1. Return quickly - Return 200 immediately, process async
  2. Be idempotent - Handle duplicate events gracefully
  3. Verify signatures - Always validate webhook authenticity
  4. Log events - Keep records for debugging

Example Handler

app.post('/webhooks/bookwell', async (req, res) => {
  const signature = req.headers['x-bookwell-signature'];
  const payload = req.rawBody;
 
  // Verify signature
  if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(400).send('Invalid signature');
  }
 
  // Acknowledge receipt immediately
  res.status(200).send('Received');
 
  // Process event asynchronously
  const event = JSON.parse(payload);
 
  switch (event.type) {
    case 'appointment.created':
      await handleNewAppointment(event.data.object);
      break;
    case 'appointment.cancelled':
      await handleCancellation(event.data.object);
      break;
    // ... handle other events
  }
});

Retry Policy

If your endpoint fails, Bookwell retries:

AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours
68 hours
724 hours

After 7 failures, the webhook is disabled. Re-enable in settings.

Testing Webhooks

Webhook Logs

View recent webhook deliveries in Settings > Webhooks > Logs:

  • Request payload
  • Response status
  • Response body
  • Retry history

Test Events

Send test events to verify your endpoint:

  1. Go to webhook settings
  2. Click Send Test Event
  3. Select event type
  4. View the response

Local Development

For local testing, use a tunnel service:

# Using ngrok
ngrok http 3000

Use the tunnel URL as your webhook endpoint during development.

Managing Webhooks

Listing Webhooks

Via API:

GET
/v1/webhooks

List webhook endpoints

curl https://api.bookwell.app/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY"

Disabling Webhooks

Temporarily disable without deleting:

  1. Go to webhook settings
  2. Toggle the webhook off
  3. No events will be sent

Deleting Webhooks

Remove a webhook endpoint:

  1. Go to webhook settings
  2. Click delete on the endpoint
  3. Confirm deletion

Troubleshooting

Not Receiving Webhooks

Check:

  1. Endpoint URL is correct and accessible
  2. HTTPS certificate is valid
  3. Firewall allows Bookwell IPs
  4. Events are selected
  5. Webhook is enabled

Invalid Signature Errors

Verify:

  1. Using correct signing secret
  2. Raw body (not parsed JSON)
  3. Signature header is complete

Timeouts

If processing takes too long:

  1. Return 200 immediately
  2. Process event asynchronously
  3. Use a job queue for heavy work

Next Steps