Webhooks
Webhooks let your integration react the moment something happens in your SMBcrm account, instead of polling the API for changes. You set them up inside a workflow, and SMBcrm sends an HTTP POST with a JSON body to your endpoint as matching events occur.
Set up a webhook
Section titled “Set up a webhook”There’s no separate API to register a webhook. You wire it up once inside a workflow:
- Create or open a workflow in your SMBcrm account.
- Add the trigger for the event you want, such as Contact Created or Appointment Booked.
- Add a Custom Webhook action as a step in that workflow.
- Enter your HTTPS endpoint URL. To authenticate requests, add a shared secret to the URL as a query parameter or send it in a custom header (see Securing your endpoint).
- Publish the workflow.
Every contact or event that meets the trigger’s conditions now sends a request to your URL.
Receiving a webhook needs no token. You need a Location token or Private Integration Token only when your handler calls the SMBcrm API back, for example to fetch the full record.
Events you can trigger on
Section titled “Events you can trigger on”Any trigger in the workflow builder can drive a Custom Webhook action. Common ones:
- Contact created or updated
- Inbound or outbound message (SMS, email, or other conversation activity)
- Appointment booked, rescheduled, or canceled
- Opportunity stage or status changed
- Form submitted
- Order or payment received
The trigger picker in the workflow builder shows the full list available to your account.
Payload
Section titled “Payload”Each call is an HTTP POST with a JSON body describing what happened. The exact fields depend on the trigger and on how you configured the webhook step. A contact event looks roughly like this:
{ "type": "ContactCreate", "locationId": "<location_id>", "id": "<contact_id>", "firstName": "Jordan", "lastName": "Lee", "email": "jordan@example.com", "phone": "+15125550142", "tags": ["website-lead"], "dateAdded": "2026-07-08T15:04:00.000Z"}Parse it defensively. Check that a field is present before you use it, tolerate keys you don’t recognize, and expect the shape to grow over time. When you need more than the payload carries, use the ids in it to fetch the full record. On a contact event, id is the contact id, so you can call the API with your Location token or PIT. See Contacts.
Securing your endpoint
Section titled “Securing your endpoint”Treat every inbound request as untrusted until you verify it.
A minimal handler that checks the secret, responds first, and queues the work:
import express from 'express';
const app = express();app.use(express.json());
app.post('/webhooks/smbcrm', (req, res) => { // Verify the shared secret before trusting anything in the body // (check req.query.token instead if you used a URL token) if (req.header('x-webhook-secret') !== process.env.SMBCRM_WEBHOOK_SECRET) { return res.status(401).end(); }
res.status(200).end(); // acknowledge first, before doing any real work
enqueueWebhookEvent(req.body); // hand off to a queue; don't await it here});
app.listen(3000);Test your endpoint
Section titled “Test your endpoint”Look at a real delivery before you build on it.
-
Point the Custom Webhook action at a request inspector such as webhook.site. It shows the headers and body your workflow sends.
-
To develop locally, expose your server with a tunnel such as ngrok and use its HTTPS URL as the endpoint.
-
Save a captured body as
sample.jsonand replay it against your handler, with the same secret your webhook step sends:Terminal window curl -X POST https://your-app.example.com/webhooks/smbcrm \-H "Content-Type: application/json" \-H "x-webhook-secret: <your_secret>" \-d @sample.json
Log every inbound request, how you processed it, and any error. When a delivery misbehaves, those logs show what arrived and what your handler did with it.
Reliability and retries
Section titled “Reliability and retries”Delivery is at-least-once. If your endpoint doesn’t return a 2xx quickly, expect the same event again.
- Acknowledge fast. Return
2xxonce you’ve verified the secret and queued the work, not after processing finishes. - Deduplicate using an event id if the payload carries one, or a hash of the body if it doesn’t.
- Don’t rely on ordering. Two events for the same record can arrive out of order, so key your logic off data in the payload, like an updated-at timestamp, rather than the order requests land in.
Managing webhooks in code
Section titled “Managing webhooks in code”Webhooks live in workflows, so you create, change, and remove them in your account rather than through the API. There’s no REST endpoint in this reference for managing webhook subscriptions programmatically. You set them up with the Custom Webhook action in a workflow.
Related
Section titled “Related”- Workflows. The trigger-and-action model webhooks build on.
- Contacts. Fetch the full record behind a lean payload.
- Conversations & Messages. The API for the message events above.
