Webhooks
Endpoint registration, event filters, HMAC signature verification, retry schedule, and replay protection for Tripistic webhooks.
Status: beta — endpoint management is available in Settings → Webhooks. Workspace owners can register public HTTPS endpoints, select the supported event types, copy a secret once, rotate it, inspect deliveries and replay a failed delivery. Delivery execution still depends on the scheduled worker being enabled in the target environment.
Webhooks push events to your endpoint as they happen. Prefer them over polling — they are faster, cheaper, and do not consume your rate limit.
Registering an endpoint
Settings → Integrations → Webhooks → Add endpoint.
- Enter an HTTPS URL. Plain HTTP is rejected.
- Select the events to subscribe to.
- Copy the signing secret. It is shown once.
You can register several endpoints — for example one for accounting and one for operations alerts.
Event catalog
| Event | Fires when |
|---|---|
booking.created | A booking is created from any source |
booking.confirmed | Payment verified or manually confirmed |
booking.updated | Participants, add-ons, price, or departure changed |
booking.cancelled | Cancelled by staff or traveller |
booking.completed | Departure finished |
departure.updated | Capacity, timing, or assignment changed |
checkin.completed | A guest check-in completed |
incident.created | Incident reported |
customer.created | New customer record |
customer.updated | Customer details changed |
site.published | A site was published |
domain.activated | A custom domain became active |
Payload
{
"id": "evt_01H8XZQ7",
"type": "booking.confirmed",
"createdAt": "2026-07-01T09:24:11.000Z",
"workspaceId": "ws_01H8",
"apiVersion": "1",
"data": {
"id": "bkg_01H8XZ",
"status": "CONFIRMED",
"paymentStatus": "PAID",
"totalAmount": 24000,
"currency": "USD",
"availabilityId": "avl_01H8XZ",
"customerId": "cus_01H8AB",
"participantCount": 2
}
}
New fields are added without a version bump. Ignore unknown fields.
Verifying the signature
Every delivery carries:
Tripistic-Signature: t=1751362451,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
The signature is HMAC-SHA256 over "{timestamp}.{raw_request_body}" using your endpoint's signing secret.
Verify against the raw request body, before any JSON parsing or framework middleware transforms it. A re-serialised body will not match.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyWebhook(rawBody: string, header: string, secret: string): boolean {
const parts = Object.fromEntries(
header.split(",").map((part) => part.split("=") as [string, string]),
);
const timestamp = Number(parts.t);
const signature = parts.v1;
if (!timestamp || !signature) return false;
// Reject anything older than five minutes.
if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const expected = createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`)
.digest("hex");
const a = Buffer.from(expected, "hex");
const b = Buffer.from(signature, "hex");
return a.length === b.length && timingSafeEqual(a, b);
}
Always compare in constant time. A plain === on the signature leaks timing information.
Responding
- Return
2xxquickly — within 5 seconds. Enqueue the work and process asynchronously. - Any non-
2xx, or a timeout, is treated as a failure and retried. - Do not perform slow work inline. Long handlers cause duplicate deliveries.
Retries
| Attempt | Delay after previous |
|---|---|
| 1 | Immediate |
| 2 | 30 seconds |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 5 | Endpoint is paused after the final failure |
After five failures the endpoint is paused. Deliveries can be replayed from the webhook log once you have fixed the endpoint.
Idempotency and ordering
Deliveries are at least once, so the same id can arrive more than once — store processed event IDs and skip duplicates.
Ordering is not guaranteed. A booking.confirmed can arrive before booking.created. Key your handlers off the resource ID and the event's createdAt, and ignore events older than the state you already hold.
Replay protection
Reject deliveries whose timestamp is more than five minutes from now, as in the example above. Combined with signature verification this prevents replay attacks.
Local development
Use a tunnelling tool to expose your local server, register the tunnel URL as a test endpoint, and trigger real events in a sandbox workspace. The webhook log shows request, response, and timing for every attempt.
Security rules
- Never trust an unverified payload.
- Never use a webhook endpoint as a proxy to third parties.
- Rotate the signing secret if it is exposed; both old and new secrets are accepted during a short overlap.
- Log deliveries without logging the signing secret.