DEVELOPER DOCS

Demoloop webhook events

Demoloop sends signed outbound webhooks when a demo completes, a visitor qualifies, or a handoff is created. Use these events to trigger CRM updates, Zapier workflows, Slack alerts, enrichment, or sales follow-up.

Start free
EVENTS

Stable event names

demo.completed

A visitor reached the end of a meaningful demo session.

visitor.qualified

The conversation or behavior shows buying intent and should notify revenue workflows.

handoff.created

A handoff was created or tested for webhook, CRM, email, or automation workflows.

DELIVERY

Request contract

Configure an HTTPS endpoint in workspace handoff settings. Demoloop posts JSON with an eight-second timeout. Return any 2xx response to mark delivery successful. Failed deliveries remain saved in Conversations with channel status.

x-demoloop-eventThe event type, for example visitor.qualified.

x-demoloop-deliveryThe unique delivery id. It matches payload.id.

x-demoloop-schema-versionThe payload schema version. Current version: 2026-07-10.

x-demoloop-signatureHMAC-SHA256 signature in the format sha256=<hex>.

SECURITY

Verify the signature

Compute an HMAC-SHA256 digest over the raw request body using the workspace webhook secret. Compare it with the value after sha256= in x-demoloop-signature. Use a constant-time comparison in production.

import crypto from "node:crypto";

function verifyDemoloopWebhook(rawBody, signatureHeader, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");

  const actual = signatureHeader.replace(/^sha256=/, "");
  return crypto.timingSafeEqual(
    Buffer.from(actual, "hex"),
    Buffer.from(expected, "hex")
  );
}
PAYLOAD

Example payload

{
  "type": "visitor.qualified",
  "version": "2026-07-10",
  "id": "evt_018f5b7d4b594b9a93c2e08b1e6d52c2",
  "createdAt": "2026-07-10T12:00:00.000Z",
  "workspace": {
    "id": "wrk_123",
    "name": "Acme workspace",
    "productName": "Acme",
    "websiteUrl": "https://acme.example"
  },
  "visitor": {
    "email": "buyer@example.com",
    "language": "English",
    "qualification": "qualified",
    "profile": {
      "company": "Acme",
      "role": "VP Sales",
      "useCase": "Website product demos"
    }
  },
  "demo": {
    "id": "ses_123",
    "status": "live",
    "productArea": "analytics",
    "startedAt": "2026-07-10T11:55:00.000Z",
    "endedAt": null,
    "summary": null,
    "rating": null,
    "feedback": null,
    "signals": [
      "Asked about rollout timeline"
    ],
    "transcript": [
      {
        "speaker": "visitor",
        "text": "Can this qualify demo visitors?",
        "at": "2026-07-10T11:57:00.000Z"
      },
      {
        "speaker": "agent",
        "text": "Yes. Demoloop records qualification signals and handoff context.",
        "at": "2026-07-10T11:57:03.000Z"
      }
    ]
  },
  "handoff": {
    "source": "demoloop",
    "test": false,
    "reason": "visitor_qualified"
  }
}

PII redaction

If workspace PII redaction is enabled, transcript email addresses are replaced before outbound delivery.

Secret fallback

Webhook signatures use the workspace webhook secret. If one is not configured, Demoloop falls back to the workspace widget key.

Retry expectation

Today, non-2xx responses are recorded as failed handoff channels. Treat webhook handlers as idempotent using payload.id.

SETUP CHECKLIST

Before going live

Use HTTPS and respond within eight seconds.

Store processed payload ids to avoid duplicate side effects.

Verify x-demoloop-signature before trusting payload data.

Test with the Growth handoff test button before routing production leads.