Bewtee

Webhooks

Know the moment a booking changes

Add an HTTPS URL in your dashboard and Bewtee will POST signed JSON to it whenever a booking event happens. Update your CRM, billing or messaging tools without polling the API.

  • Eight booking events
  • Signed requests
  • Automatic retries

Setup

Set one up in a minute

  1. Add your URL

    In the Developers section of your dashboard, add a public HTTPS address and pick the events you want.

  2. Save the signing secret

    It is shown once. Your server uses it to check that requests really come from Bewtee.

  3. Send a test

    Press Send test to deliver a sample event and see whether your server accepted it.

Open the Developers section of your business dashboard

Reference

Events

  • booking.created

    A new booking was placed.

  • booking.accepted

    The booking was confirmed, by the business or by auto-accept.

  • booking.rejected

    The business declined the booking.

  • booking.cancelled

    The booking was cancelled.

  • booking.rescheduled

    The booking moved to a new date or time.

  • booking.completed

    The appointment was marked as completed.

  • booking.no_show

    The customer did not turn up.

  • booking.expired

    A pending booking was not accepted in time.

Payload

What Bewtee sends

Every event has the same outer shape. The type field tells you what happened and data.booking holds the booking at that moment.

JSON
{
    "id": "evt_...",
    "type": "booking.accepted",
    "api_version": "v1",
    "business_id": 123,
    "created_at": "2026-11-12T10:30:00+05:30",
    "data": {
        "booking": {
            "id": 9812,
            "status": "accepted",
            "date": "2026-11-15",
            "time": "11:00",
            "amount": {
                "total": 1200,
                "currency": "INR"
            },
            "customer": {
                "name": "Asha",
                "phone": "98XXXXXXXX"
            },
            "services": [
                {
                    "name": "Haircut",
                    "price": 1200,
                    "duration_minutes": 45,
                    "quantity": 1
                }
            ]
        },
        "previous_status": "pending"
    }
}

Reply quickly. Answer with any 2xx status within 5 seconds, then do slower work afterwards. Anything else counts as a failed delivery.

Security

Verify the signature

Each request carries a Bewtee-Signature header so you can confirm it really came from Bewtee:

Header
Bewtee-Signature: t=1794373200,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
  • t is the Unix time the request was signed.
  • v1 is the hex HMAC-SHA256 of the text <t>.<raw body>, using the signing secret of your endpoint as the key.
  • Compute the same value on your server from the raw request body (before parsing the JSON) and compare. Reject the request if they differ.
JavaScript
const crypto = require('crypto');

// rawBody must be the exact request body string, before JSON parsing.
function verifyBewteeSignature(rawBody, header, secret) {
  const parts = Object.fromEntries(
    header.split(',').map((pair) => pair.split('='))
  );
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`)
    .digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1 || '');

  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
PHP
<?php

function verifyBewteeSignature(string $rawBody, string $header, string $secret): bool
{
    $parts = [];
    foreach (explode(',', $header) as $pair) {
        [$key, $value] = array_pad(explode('=', $pair, 2), 2, '');
        $parts[$key] = $value;
    }

    $expected = hash_hmac('sha256', ($parts['t'] ?? '').'.'.$rawBody, $secret);

    return hash_equals($expected, $parts['v1'] ?? '');
}

$rawBody = file_get_contents('php://input');
$header = $_SERVER['HTTP_BEWTEE_SIGNATURE'] ?? '';

if (! verifyBewteeSignature($rawBody, $header, $signingSecret)) {
    http_response_code(400);
    exit;
}

Reliability

Retries

If a delivery fails, Bewtee tries again, up to 6 attempts in total over about 8.5 hours.

  1. First try
  2. +1 min
  3. +5 min
  4. +30 min
  5. +2 hours
  6. +6 hours

Because a delivery can be retried, use the event id to skip events you have already handled. A webhook that keeps failing is paused, and you can switch it back on from your dashboard once your server is fixed. Delivery details and the full payload for each event are in the webhooks documentation.

Ready to connect Bewtee?

Everything is set up from the Developers section of your business dashboard. It is free for Bewtee businesses.

New to Bewtee? See what the salon software does

Found something wrong? Report an error

Login

Use your mobile number to view and manage your bookings.

+91

Enter the code we sent to +91 on WhatsApp.