Skip to main content
Documentation

Webhooks

Register an HTTPS endpoint and Ticket Tool will POST a signed JSON payload whenever a subscribed event occurs. Manage endpoints from the dashboard or with the webhooks:read / webhooks:write API scopes (see Authentication for obtaining a token and granting scopes, and Endpoints for the rest of the API surface).

Payload

{
  "id": "clr2x9k0a0001s7f0h2p3q4r5",
  "type": "TICKET_CREATED",
  "createdAt": "2026-06-06T12:00:00.000Z",
  "data": { "ticketId": "...", "ticketNumber": 42 }
}

Event catalog

Ticket lifecycle

TICKET_CREATED, TICKET_UPDATED, TICKET_CLOSED, TICKET_REOPENED, TICKET_CLAIMED, TICKET_UNCLAIMED, TICKET_DELETED

Activity

TICKET_MESSAGE_CREATED, TICKET_PARTICIPANT_ADDED, TICKET_PARTICIPANT_REMOVED, TICKET_RATING_CREATED

Subscribe to specific events when you create the endpoint, or leave the list empty to receive all of them.

Verifying signatures

Each delivery includes these signing headers, alongside an X-Webhook-Event header carrying the event type:

X-TicketTool-Signature: <hex hmac-sha256>
X-TicketTool-Timestamp: <unix seconds>
X-Webhook-Event: <event type, e.g. TICKET_CREATED>

The signature is HMAC-SHA256(secret, "{timestamp}.{rawBody}"). Verify it against the signing secret shown once when you created the endpoint:

import crypto from "crypto";

function verify(rawBody: string, headers: Headers, secret: string): boolean {
  const signature = headers.get("X-TicketTool-Signature") ?? "";
  const timestamp = Number(headers.get("X-TicketTool-Timestamp") ?? "0");

  // Reject replays older than 5 minutes
  if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");

  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

Delivery, retries, and replay

Respond with any 2xx status to acknowledge. Failed deliveries retry with exponential backoff (1m, 5m, 30m, 2h, 6h; up to 6 attempts). An endpoint that fails 15 times in a row is disabled automatically. Every attempt is recorded, and you can inspect history or re-send a delivery from the dashboard or the /v1/webhooks/{id}/deliveries endpoints.