Skip to main content

Webhooks

Webhooks let Reservly push real-time notifications to your app when events happen — new bookings, payments, cancellations, etc. Instead of polling our API, your server receives an HTTP POST automatically.

Setting Up Webhooks

Configure webhooks from your dashboard in Settings → Integrations → Webhooks.

  1. Enter your endpoint URL. It must use HTTPS.
  2. Select the events you want to receive.
  3. Click Add.

After adding a webhook, use the Test button to send a sample payload and verify your endpoint is reachable.

Event Types

Subscribe to any combination of the following events:

EventDescription
booking.createdA new booking is made
booking.confirmedA booking is confirmed by the business owner
booking.cancelledA booking is cancelled
booking.rescheduledA booking's date or time is changed
payment.receivedA payment is successfully completed
payment.refundedA refund is processed
customer.createdA new customer profile is created

Payload Format

Every webhook delivery is a POST request with a JSON body. The top-level structure includes the event type, a timestamp, your business identity, and the event-specific data.

Booking event example

booking.created
{
  "event": "booking.created",
  "timestamp": "2026-04-15T10:30:00.000Z",
  "business": {
    "id": "uuid",
    "slug": "luxe-salon"
  },
  "data": {
    "booking_id": "uuid",
    "date": "2026-04-15",
    "start_time": "10:00",
    "end_time": "11:00",
    "status": "pending",
    "customer_name": "Jane Smith",
    "customer_email": "jane@example.com",
    "services": [
      {
        "name": "Haircut",
        "duration_minutes": 60,
        "price": 45
      }
    ]
  }
}
json

Payment event example

payment.received
{
  "event": "payment.received",
  "timestamp": "2026-04-15T10:31:00.000Z",
  "business": {
    "id": "uuid",
    "slug": "luxe-salon"
  },
  "data": {
    "booking_id": "uuid",
    "amount_cents": 4500,
    "currency": "USD",
    "provider": "stripe",
    "status": "paid",
    "customer_name": "Jane Smith",
    "customer_email": "jane@example.com"
  }
}
json

Headers

Every webhook request includes the following headers:

HeaderDescription
X-Reservly-SignatureHMAC-SHA256 signature of the payload
X-Reservly-EventThe event type (e.g., booking.created)
X-Reservly-TimestampISO 8601 timestamp of the delivery attempt
Content-Typeapplication/json
User-AgentReservly-Webhooks/1.0

Signature Verification

To verify that a webhook was genuinely sent by Reservly, compute an HMAC-SHA256 hash of the raw request body using your signing secret, then compare it to the X-Reservly-Signature header.

Your signing secret is the SHA-256 hash of your first API key. Generate an API key in Settings → Integrations before setting up webhooks.

Node.js verification example
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your Express handler:
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-reservly-signature'];
  const isValid = verifyWebhook(
    JSON.stringify(req.body),
    signature,
    YOUR_SECRET
  );

  if (!isValid) return res.status(401).send('Invalid signature');

  // Process the event...
  res.status(200).send('OK');
});
javascript

Retry Behavior

If your endpoint does not respond with a 2xx status code, Reservly retries delivery up to 3 times with exponential backoff:

  • 1st retry— 1 second after the initial attempt
  • 2nd retry— 5 seconds after the 1st retry
  • 3rd retry— 25 seconds after the 2nd retry

Each attempt has a 15-second timeout.

Only 5xx errors and network failures trigger retries. 4xx errors are treated as permanent failures and are not retried. You can view the full delivery history in Settings → Integrations.

Best Practices

  • Respond with 200 quickly. Acknowledge the webhook immediately and process the event asynchronously (e.g., via a queue). Long-running handlers risk hitting the 15-second timeout.
  • Verify signatures on every request. Always check the X-Reservly-Signature header to confirm the payload was not tampered with.
  • Handle duplicate deliveries. Network issues can cause the same event to be delivered more than once. Use the timestamp and data fields to implement idempotency in your handler.
  • Monitor delivery history. Check Settings → Integrations for failed deliveries and address any endpoint issues promptly.