Webhooks
Create a webhook in Settings → Webhooks or via POST /api/v1/webhooks. Deliveries are JSON POSTs, signed, retried five times with exponential backoff, and every attempt is visible in the deliveries log.
Events
booth.created
booth.updated
booth.deleted
booth.status_changed
booth.assigned
booth.unassigned
booth.on_hold
exhibitor.created
exhibitor.updated
exhibitor.deleted
order.created
order.paid
order.cancelled
order.expired
floorplan.published
session.created
session.updated
session.deleted
extra.assigned
extra.removedPayload
{
"id": "wd_…", "type": "booth.status_changed", "createdAt": "2026-09-14T10:00:00.000Z", "eventId": "ev_…",
"data": { "booth": { "id": "bo_…", "label": "A101", "status": "sold", "exhibitorIds": ["ex_…"], … }, "previousStatus": "held" }
}Verify the signature
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map((kv) => kv.split("=")));
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return timingSafeEqual(Buffer.from(v1, "hex"), Buffer.from(expected, "hex")) && Math.abs(Date.now() / 1000 - Number(t)) < 300;
}
// headers: X-Tessera-Signature: t=1726300000,v1=… X-Tessera-Event: booth.status_changed X-Tessera-Delivery: wd_…ExpoFP integrations that expect booth_reserved/booth_assigned/exhibitor_upserted map onto booth.status_changed, booth.assigned and exhibitor.updated; the payload carries our ids plus externalId.