Docs / Developers / Outbound webhooks

Outbound webhooks

Last updated: 7 August 2026

Register an HTTPS endpoint under Settings > Developer, choose which events you want (new messages, sent messages, new leads, lead-stage changes, completed campaigns), and Stravax Engage POSTs each matching event to your endpoint. Every delivery carries an HMAC signature you verify against a secret only you and Stravax Engage know.

How do I register a webhook endpoint?

In Settings > Developer, add a webhook, enter your endpoint URL, and pick the events you want to subscribe to. The endpoint must be a public HTTPS URL: plain HTTP, and private or loopback network addresses, are rejected at registration. Once created, you're given a signing secret. Unlike an API key, this secret isn't a one-time reveal, you can view it again later in the Developer panel if you need to re-check your verification code.

Which events can I subscribe to?

Event Fires when
message.received A WhatsApp message arrives in your inbox.
message.sent A message you sent (from the inbox, the API, an automation, or the AI qualifier) reaches sent status.
lead.created A new lead is created.
lead.stage_changed A lead moves to a different pipeline stage.
campaign.completed A broadcast campaign's dispatched batch finishes sending.

How do I verify a webhook signature?

Each delivery arrives with these headers:

The signature covers {timestamp}.{raw request body}, not the body alone, so a captured delivery can't be replayed with a rewritten timestamp. Recompute it yourself and compare with a constant-time check:

const crypto = require("crypto");

function isValidSignature(secret, timestamp, rawBody, signatureHeader) {
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader));
}

Can the same event arrive twice?

Yes, rarely, and you should build for it. Deliveries are at-least-once: if our worker is interrupted after your endpoint accepted a payload but before we recorded that it succeeded, or if your endpoint holds the connection open for several minutes, the delivery is re-driven and your endpoint sees the same payload again.

Dedup on X-Stravax-Delivery. That id belongs to the delivery, not to the attempt, so every retry of the same event carries the same value, and two different events never share one. Store the ids you have already processed (a few days is plenty, retries stop within about half an hour) and ignore a repeat:

if (await alreadyProcessed(req.headers["x-stravax-delivery"])) {
  return res.status(200).end(); // already handled, acknowledge and do nothing
}

Answer 2xx as soon as you have durably stored the event rather than after you have finished acting on it. A slow endpoint is the most common cause of a duplicate.

What happens if my endpoint fails or times out?

Stravax Engage retries a failed delivery with exponential backoff, starting at about a minute and doubling up to a 16-minute cap, for up to 5 attempts total before marking that delivery dead. If deliveries to the same endpoint keep dying like this three times in a row, the endpoint is disabled automatically, with a human-readable reason visible in the Developer panel, so you know why it stopped rather than discovering it went quiet.

Does Stravax Engage follow redirects to my endpoint?

No. If your endpoint responds with a redirect, it isn't followed, that delivery is recorded as failed instead. This also means a redirect can't be used to route a delivery somewhere else after registration passed the address check.

Related: API keys, REST API v1 overview, and the public OpenAPI contract.

More in Developers