Tours & Events
Conventions

Webhooks

Receive event notifications via outbound HTTP callbacks

Beta

Outbound webhooks let your server react to changes (event created, guest RSVP'd, expense logged) without polling. Register endpoints via /api/webhooks.

Delivery format

POST https://your.app/hook
Content-Type: application/json
X-TE-Event: event.created
X-TE-Delivery: 7f3a1c2b-4d8e-49f0-b1e3-2c5f6a8b9d10
X-TE-Signature: t=1714521600,v1=8f4d…
User-Agent: ToursEvents-Webhooks/1.0
{
  "id": "evt_01H7V…",
  "type": "event.created",
  "createdAt": "2026-05-20T10:14:00Z",
  "data": { "id": "event-uuid", "name": "Annual Conference", "tourId": "tour-uuid" }
}

Signature verification

Each delivery is signed with HMAC-SHA256 using your webhook's secret. Always verify the signature before trusting the payload.

import crypto from "node:crypto";

function verify(rawBody, header, secret) {
  const [tPart, v1Part] = header.split(",");
  const t = tPart.slice(2);
  const v1 = v1Part.slice(3);
  const signed = `${t}.${rawBody}`;
  const expected = crypto.createHmac("sha256", secret).update(signed).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}
  • Verify against the raw request body, not the parsed JSON.
  • Reject deliveries where t is more than 5 minutes old to prevent replay.
  • Use timingSafeEqual to avoid timing attacks.

Retries

Non-2xx responses trigger retries with exponential backoff:

AttemptDelay
1immediate
230 s
35 min
41 h
56 h
624 h

After the 6th failure the delivery is marked failed and surfaced on the webhook dashboard.

Idempotency

Retries reuse the same X-TE-Delivery ID. Store seen IDs (e.g. in Redis with a 7-day TTL) and skip duplicates.

Outbound webhooks are currently in beta. Available event types and signing details may evolve — pin against the changelog.

On this page