GuideUltimate plan

Set up webhooks

Send real-time updates about appointments, clients, invoices and more to your own system, and verify that each request comes from Softalon.

5 min readRole: Super Administrator or higherIntegrations & developersUpdated October 25, 2026
Open in the app

A webhook sends an HTTP request to a URL you choose whenever something happens in your salon, for example when an appointment is created or a client is updated. Use it to keep another system in sync with Softalon.

Before you start

  • Your salon is on the Ultimate plan.
  • You have the Super Administrator or Owner role.
  • You have a URL that accepts POST requests with a JSON body, starting with https:// or http://.

Create a webhook

  1. 1

    Step 1 of 4

    Open Webhooks

    Go to Settings › Developers › Webhooks and click Create Webhook.

  2. 2

    Step 2 of 4

    Enter the destination

    Fill in Destination URL, for example https://example.com/webhook, and optionally a Description so you can recognize it later.

  3. 3

    Step 3 of 4

    Choose topics

    Under Topics, select the events you want. The All Topics tab lists every available topic, and Selected Topics shows what you picked. Your URL only receives the topics you select.

  4. 4

    Step 4 of 4

    Save

    Click Create Webhook.

    You will see:

    Webhook Created, and the webhook appears in the table with its status switch on.

Topics

Topics are named resource.action. These are available:

AreaTopics
Team memberssalons/member.created, .updated, .deleted
Locationslocations/location.created, .updated, .deleted
Servicesservices/service.created, .updated, .deleted
Clientsclients/client.created, .updated, .deleted, .birthday, .lapsed
Client sign-in codesclients/session_request.code_generated
Appointmentsbooking/appointment.created, .updated, .deleted, .upcoming, .started
Conversationsconversations/conversation.created, .updated, .deleted
Invoicesfinances/invoice.created, .updated, .deleted

For what each trigger means, see Automation triggers explained.

What Softalon sends

Each event is a POST request with a JSON body:

{
  "topic": "booking/appointment.created",
  "event": {
    "id": "...",
    "type": "booking/appointment.created",
    "resource": "booking/appointment",
    "resourceId": "...",
    "salonId": "...",
    "data": {
      "object": { "...": "the full object" },
      "previousAttributes": { "...": "changed fields, for updates" }
    }
  }
}

The request has these headers:

HeaderValue
X-Webhook-Signaturesha256= followed by the signature
X-Webhook-TopicThe topic, for example booking/appointment.created
X-Webhook-Endpoint-IdThe ID of your webhook
X-Webhook-Delivery-IdThe ID of this delivery. It stays the same when a delivery is retried.
User-AgentSoftalon API

Verify the signature

Every webhook has a secret. Softalon signs the request body with it using HMAC-SHA256 and sends the hex result in X-Webhook-Signature. Compute the same value from the raw request body and compare. If they don't match, ignore the request.

const crypto = require("crypto");

function isValid(rawBody, header, secret) {
  const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}

To manage the secret, use the buttons in the Secret column:

  • The eye button shows the full secret, and the copy button copies it.
  • The regenerate button creates a new secret right away. The old secret stops working immediately, so update your system at the same time.

Deliveries and retries

  • Your URL must answer with a 2xx status code within 10 seconds. Anything else counts as a failure.
  • A failed delivery is retried, up to 5 attempts in total. The waits between attempts grow: about 30 seconds, 1 minute, 2 minutes and 4 minutes.
  • Use X-Webhook-Delivery-Id to ignore a delivery you've already processed.

Each delivery has one of these statuses:

StatusWhat it means
pendingWaiting to be sent.
deliveredYour URL answered with a 2xx status.
failedThe last attempt failed. If attempts are left, it's retried.
exhaustedAll 5 attempts failed. It won't be retried.

The app doesn't show a delivery log yet. You can read deliveries through the API at GET /v1/salons/:salonId/webhook-endpoints/:webhookEndpointId/deliveries. See Create an API app.

If the last 5 deliveries to a webhook are all exhausted, Softalon turns the webhook off. Fix your endpoint, then turn the status switch back on. Events that happen while a webhook is off aren't sent later.

Edit, pause or delete a webhook

  • Pause: turn off the switch in the Status column.
  • Edit: open the row's menu and choose Update.
  • Delete: open the row's menu and choose Delete.

Webhooks only send while your salon has an active, trialing or past-due subscription on a plan that includes webhooks.

Common questions

Each delivery is sent separately and retried on its own schedule, so don't rely on the order requests arrive in. Use the object's own timestamps instead.