Webhook reference

Receive a signed HTTPS request when bookings and payments change in your Triviyo account.

Webhooks are available on the Professional plan and above. Add an endpoint under Settings → Webhooks, choose the events you want, and copy the signing secret. You can send a test delivery from the same screen.

Events

EventSent when
BOOKING_CREATEDA booking is created
BOOKING_UPDATEDA booking changes, for example its status or time
BOOKING_CANCELEDA booking is cancelled
PAYMENT_SUCCEEDEDA booking payment succeeds
PAYMENT_FAILEDA booking payment fails
REFUND_PROCESSEDA refund for a booking payment is processed

Request format

Triviyo sends an HTTPS POST with a JSON body:

{
  "event": "BOOKING_CREATED",
  "timestamp": "2026-10-04T10:00:00.000Z",
  "data": {
    "booking": {
      "id": "clx...",
      "bookingNumber": "TRV-...",
      "status": "CONFIRMED",
      "guestEmail": "[email protected]",
      "guestName": "Alex Guest",
      "totalParticipants": 2,
      "total": "120.00",
      "currency": "EUR",
      "createdAt": "2026-10-04T10:00:00.000Z"
    },
    "experience": { "id": "clx...", "title": "Sunset kayak tour" },
    "timeSlot": {
      "id": "clx...",
      "startTime": "2026-10-10T17:00:00.000Z",
      "endTime": "2026-10-10T19:00:00.000Z"
    }
  }
}

Payment events carry a payment object (id, bookingId, amount, currency, stripePaymentIntentId, createdAt) and a short booking object (bookingNumber, guestEmail).

REFUND_PROCESSED carries a refund object (id, bookingId, paymentId, amount, currency, reason, processedAt) and the same short booking object.

Headers sent with every request:

HeaderValue
Content-Typeapplication/json
X-Webhook-SignatureHex-encoded HMAC-SHA256 of the raw request body, keyed with your signing secret
X-Webhook-Signature-Algorithmsha256
User-AgentTriviyo-Webhook/1.0

Verifying the signature

Compute the HMAC over the exact raw body you received, before parsing JSON, and compare it in constant time.

import crypto from "node:crypto";

export function isValidTriviyoWebhook(rawBody, signatureHeader, secret) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const received = Buffer.from(signatureHeader ?? "", "utf8");
  const computed = Buffer.from(expected, "utf8");
  return received.length === computed.length && crypto.timingSafeEqual(received, computed);
}

Delivery, timeouts and retries

  • Respond with any 2xx status within 10 seconds to acknowledge a delivery.
  • A delivery that times out, cannot connect, or gets a 408, 429 or 5xx response is retried automatically, with up to 6 attempts in total: up to three in the first run (immediately, then after about 1 and 5 seconds), then up to two and one on the next two runs of the delivery queue. After the last attempt the delivery is marked failed.
  • Any other 4xx response (for example 400, 401, 404 or 410) is treated as permanent: the delivery is marked failed immediately, its HTTP status is recorded in the delivery log, and it is not retried. Fix the endpoint, then send a test delivery under Settings → Webhooks.
  • After 10 consecutive failed deliveries the endpoint is disabled automatically. Fix the endpoint and re-enable it under Settings → Webhooks.
  • Endpoints must be publicly reachable http(s) URLs; private and internal addresses are rejected.

Deliveries can arrive more than once and out of order. Use the booking or payment id to make your handler idempotent.