CarSignalDocs
Book a demoSupportSign in
Account & billing

Webhooks and Slack

Post a signed event to your own URL, or a message to a Slack channel, when a booking lands, a car checks in, a quote or invoice goes out or gets approved or paid, or a car leaves.

Settings, Apps, then Webhooks and Slack in the ••• menu. Admins only.

What you can do

  • Add endpoint. A name, an https URL, how to send (JSON webhook or Slack message), and the events it should hear about: booking created, car checked in, quote sent, quote approved, invoice sent, invoice paid, car picked up.
  • Slack. Create an incoming webhook in Slack for the channel you want, paste its URL, choose Slack message. Each event arrives as one line (what happened, who, which car, the amount) with an Open in CarSignal link.
  • Send test. Posts a test event right away and shows the HTTP status your endpoint returned.
  • Log. The last deliveries per endpoint: event, time, status, attempts, and the error if it failed.
  • Turn off an endpoint without deleting it; Remove when it is gone for good.

Timing and retries

Events post within a minute. If your endpoint is down or answers with an error, CarSignal retries after 1 minute, 5 minutes, 15 minutes, 1 hour and 3 hours, then gives up and says so in the log and on the endpoint.

Verifying a JSON webhook

Every post carries three headers:

  • X-CarSignal-Event: the event name, for example invoice.paid.
  • X-CarSignal-Delivery: a unique id for this delivery (the same id on a retry).
  • X-CarSignal-Signature: t=<unix seconds>,v1=<hex> where v1 is HMAC-SHA256 of "<t>.<raw request body>" using the endpoint's signing secret (shown under the endpoint, Show signing secret).

Recompute the HMAC over the raw body with your copy of the secret, compare it to v1 with a constant-time comparison, and ignore posts whose t is more than five minutes old.

The body is JSON:

{
  "id": "delivery id",
  "event": "invoice.paid",
  "created_at": "2026-10-20T20:11:03Z",
  "shop": { "id": "...", "name": "Mystique Motors" },
  "data": {
    "invoice": { "id": "...", "number": "INV-0042", "status": "paid", "total": 312.5, "paid_at": "...", "customer_name": "Pat Lee" },
    "vehicle": { "id": "...", "label": "2018 BMW 340i", "plate": "8ABC123", "ro_number": "RO-0007", "url": "https://app.trycarsignal.com/vehicles/..." },
    "customer": { "id": "...", "name": "Pat Lee", "phone": "...", "email": "..." }
  }
}

data always describes the record as it is when the post goes out. A booking carries booking (date, time, service, customer); a quote carries quote (status, total); check-in and pickup carry vehicle and customer.