Webhooks
DICE sends a signed POST to your endpoint when something happens: a new lead, a status change, a booking, a sale.
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-Idand 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.