Skip to content

Webhooks

DICE sends a signed POST to your endpoint when something happens: a new lead, a status change, a booking, a sale.

JS
import { createHmac, timingSafeEqual } from 'node:crypto';

// rawBody: the request body exactly as received (a string, before JSON parsing)
export function verifyDice(secret, rawBody, header, toleranceSeconds = 300) {
  const parts = Object.fromEntries(String(header).split(',').map((p) => p.split('=')));
  const t = Number(parts.t);
  if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
  const want = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest();
  const got = Buffer.from(parts.v1 ?? '', 'hex');
  return got.length === want.length && timingSafeEqual(got, want);
}

Node.js. Other languages: the same HMAC over "<t>.<raw body>".

Add an endpoint

In Developers → Webhooks, add an HTTPS address and choose the events. The signing secret is shown once. You can also manage endpoints with the API (/api/v1/webhooks, scope webhooks:manage). GET /api/v1/events lists every event with a sample payload.

What a delivery looks like

{ "id": "0192…", "type": "lead.created", "created_at": "2026-09-28T10:00:00.000Z", "business_id": "0191…", "data": { "id": "0192…", "source": "widget" } }

Headers: Dice-Signature, Dice-Event (the type), Dice-Event-Id and Dice-Delivery.

Verify every delivery

Dice-Signature is t=<unix seconds>,v1=<hex>, where v1 is HMAC-SHA256 of "<t>.<raw body>" with the endpoint secret. Compute it over the raw body, compare in constant time, and reject timestamps more than 5 minutes old. The code above does this; the SDK's verifyWebhook does too.

Retries, replays and duplicates

  • Answer with any 2xx within 10 seconds. Anything else is retried after 1 minute, 5 minutes, 15 minutes, 1 hour, 3 hours, 6 hours, 12 hours and 24 hours.
  • Delivery is at least once: store Dice-Event-Id and ignore repeats.
  • After 15 failed deliveries in a row the endpoint is turned off and the business owners get an email. Fix the receiver, then turn it back on in Developers.
  • The delivery log in Developers shows every attempt with its status and time. You can replay a delivery or send a test event from there.

Rotate a secret

Rotate secret issues a new secret at once. Deploy the new secret to your receiver right after rotating; deliveries signed with the old secret stop immediately.