Webhooks QuickstartSigned • Retried • Production-safe

Receive real-time events from Zautic in minutes

Webhooks let your system react instantly to events like message delivery, incoming messages, and device status changes. This guide shows exactly how to create your webhook URL, verify signatures, and process events safely.

4-step webhook setup (Stripe-style)

You choose your webhook URL by creating a simple endpoint on your server (or serverless function). Then you paste that URL into Zautic.

1) Choose your URL

Create an endpoint like https://your-domain.com/webhooks/zautic

2) Verify signatures

Validate t=1700000000,v1=abcdef using your webhook secret

3) Subscribe to events

Select which events you want in Members → API Integration → Webhooks

4) Process asynchronously

ACK fast (2xx), enqueue work to your job queue / worker

What Zautic sends to your server

Zautic sends an HTTP POST request with a JSON body and these headers. Your server must return a 2xx quickly.

X-Zautic-Eventmessage.delivered
X-Zautic-Delivery-Idunique per delivery (idempotency key)
X-Zautic-Timestampunix seconds
X-Zautic-Signaturet=...,v1=... (HMAC SHA256 of t.rawBody)
Important
  • • Verify signatures using the raw request body (before JSON parsing).
  • • Use idempotency (store X-Zautic-Delivery-Id) to avoid duplicate processing.
  • • Respond fast; do heavy work asynchronously.
Sample webhook payload
{
  "id": "evt_5f3c2a1b9d4e8c0a1f2b3c4d5e6f7a8b",
  "type": "message.delivered",
  "created": 1767432000,
  "created_at": "2026-01-03T00:00:00.000Z",
  "livemode": true,
  "data": {
    "object": {
      "message_id": "3EB0DC15F6ACF859FB492F",
      "phone": "919876543210",
      "device_id": 114,
      "status": "delivered",
      "direction": "outgoing"
    }
  }
}

Copy‑paste receiver examples

Pick your stack, deploy a public HTTPS URL, paste it into Zautic Webhooks, and click “Test”.

Signature verification included (HMAC SHA256)
Receiver example
// Node.js (Express) - production-safe signature verification
// Install: npm i express
import crypto from "crypto";
import express from "express";

const app = express();

// IMPORTANT: we need raw body to verify the signature.
app.use("/webhooks/zautic", express.raw({ type: "application/json" }));

app.post("/webhooks/zautic", async (req, res) => {
  const secret = process.env.ZAUTIC_WEBHOOK_SECRET; // from Zautic dashboard
  const signatureHeader = String(req.header("X-Zautic-Signature") || "");
  const deliveryId = String(req.header("X-Zautic-Delivery-Id") || "");

  if (!secret) return res.status(500).send("Missing secret");

  // Idempotency: store deliveryId (or event.id) and ignore duplicates.
  // if (await alreadyProcessed(deliveryId)) return res.sendStatus(200);

  const rawBody = req.body.toString("utf8");
  const { t, v1 } = (() => {
    const parts = signatureHeader.split(",").map(p => p.trim());
    const map = Object.fromEntries(parts.map(p => p.split("=")));
    return { t: map.t, v1: map.v1 };
  })();

  if (!t || !v1) return res.status(400).send("Invalid signature header");

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");

  const ok = crypto.timingSafeEqual(Buffer.from(v1, "hex"), Buffer.from(expected, "hex"));
  if (!ok) return res.status(400).send("Signature mismatch");

  const event = JSON.parse(rawBody);

  // Process quickly (enqueue work) and ACK with 2xx.
  switch (event.type) {
    case "message.delivered":
      // enqueueJob("message.delivered", event);
      break;
    case "message.received":
      // enqueueJob("message.received", event);
      break;
    default:
      break;
  }

  // Mark deliveryId as processed (idempotency)
  // await markProcessed(deliveryId);

  return res.sendStatus(200);
});

app.listen(3000, () => console.log("Listening on http://localhost:3000"));

Supported events

Subscribe only to what you need. You can update subscriptions anytime from the Members dashboard.

message.sentmessage.deliveredmessage.readmessage.failedmessage.receiveddevice.connecteddevice.disconnectedcontact.createdcontact.updatedcontact.deletedgroup.createdgroup.updatedgroup.deletedtemplate.createdtemplate.updatedtemplate.deletedcampaign.startedcampaign.pausedcampaign.resumedcampaign.stoppedcampaign.cancelledcampaign.completedwebhook.test

Reliability best practices

Webhooks are delivered asynchronously and may be retried. Your receiver should be designed for retries and duplicates.

Respond fast
Return 2xx quickly. Offload heavy processing to background jobs.
Handle retries
Temporary failures (timeouts/5xx/429) may be retried automatically.
Verify signatures
Always validate X-Zautic-Signature using raw request body.
Idempotency
Store X-Zautic-Delivery-Id (or event.id) to avoid double-processing.

How to test your receiver

  1. 1. Deploy your endpoint publicly via HTTPS (or use ngrok/cloudflared for local dev).
  2. 2. In Zautic Members → API Integration → Webhooks, create a webhook with your URL.
  3. 3. Click Test to receive a webhook.test event.
  4. 4. Trigger real events by sending a message and watching delivery/read updates.
  5. 5. (Optional) Use our Postman Collection → Webhooks (Simulator) folder to send signed sample events to your server.
Tip
If your server returns non‑2xx or times out, the delivery may be retried. Check delivery history inside the Members Webhooks page.

Use webhooks with Zapier, Make, or n8n

These platforms can act as your webhook receiver. They generate an HTTPS URL; paste it into Zautic and build workflows without writing backend code.

Zapier
  1. 1. Create a Zap with trigger: Webhooks by ZapierCatch Hook.
  2. 2. Copy the webhook URL Zapier gives you.
  3. 3. In Zautic → Members → API Integration → Webhooks, create a webhook using that URL and select events.
  4. 4. Click Test in Zautic (or send a message) to capture the first sample in Zapier.
  5. 5. Add actions (Sheets/CRM/Slack) and branch on type.

Signature verification: use Catch Raw Hook + a code step (or forward via your own endpoint) if you want strict verification.

Make.com
  1. 1. Create a Scenario and add WebhooksCustom webhook.
  2. 2. Copy the webhook URL that Make generates.
  3. 3. Add it in Zautic Webhooks and select events.
  4. 4. Run the Scenario once to let Make “listen”, then trigger Zautic Test or send a message.
  5. 5. Map fields into other modules (CRM, Sheets, email) and branch on type.

If you need signature verification inside Make, use a code step to HMAC t.rawBody and compare with v1.

n8n
  1. 1. Create a workflow with a Webhook node (method: POST).
  2. 2. Copy the Production URL from n8n.
  3. 3. Paste it into Zautic Webhooks and select events.
  4. 4. Use Zautic Test to confirm the workflow triggers.
  5. 5. Add nodes to route by type and process data.object.

n8n is great if you want full control (including signature verification) while staying mostly no-code.