WaveRez can automatically send booking and waiver information to another system, like Zapier, Make, or your own CRM, whenever something important happens. This is done using a webhook, which lets two systems talk to each other automatically without anyone clicking a button.
Setting Up Your Webhook
Go to the Admin Area of WaveRez
Click Integrations > Webhooks
Check the box for Use Webhook
Paste your Zapier, Make, or custom URL into the Webhook Endpoint field
That's it. WaveRez will begin sending data to that URL as events occur.
What Triggers a Webhook
Every webhook includes a type field (what kind of record it is) and an event field (what happened to it). Check both before processing.
|
| Fires when |
|
| A new booking is made — through WaveRez, or through a connected channel like TripShock, Viator, or GetYourGuide |
|
| An existing booking changes — date, time, guest count, guest details, payment status |
|
| A booking is cancelled |
|
| A guest finishes and signs a waiver |
Actions that don't change the booking itself — sending an SMS or email, a declined payment attempt — do not trigger a webhook.
Coming soon: crew management webhooks, which will fire when a crew member is assigned to a trip and again when they accept or decline.
How Delivery Works
A few things to understand before you build an automation:
Webhooks send the current state, not a list of changes. An updated event contains the booking as it exists right now. It does not tell you which fields changed. If you need to detect what changed, store the previous version on your side and compare.
Rapid changes are batched. If a booking is edited several times in quick succession, you'll typically receive one webhook reflecting the final state rather than one per edit. This keeps your integration from being flooded, but it means the webhook is a snapshot, not an audit trail.
Booking Webhooks
Fields you'll use most
Field | Notes |
| The stable, permanent booking ID. Use this as your record key. |
| The human-readable confirmation code shown to guests (e.g. |
|
|
| The lead booker's details |
| Total value of the booking |
| When the booking was created |
| Direct link to the order in WaveRez admin - great for CRM records |
| Guest-facing link to manage the booking |
|
|
|
|
| UTC offset for your business location |
Fields inside each cart item
A booking contains one or more cart_items — each one is a trip on a specific date and time.
Field | Notes |
| The stable line-item ID. Use this to match waivers (see below). |
| Which activity was booked |
| Full departure and return time with time zone offset, e.g. |
| Human-readable summary, e.g. |
| The boat, vehicle, or unit assigned |
| Each ticket type with its |
| Identifies the departure, not the booking — see the note below |
| Populated when this item is cancelled |
| Guest voucher URL |
About calendar_id
calendar_id identifies a specific departure slot, and every booking on that same departure shares the same value. It is not unique to a booking, and it changes if a booking is moved to a different date or time.
Don't use it as a record key, you'll merge two different customers into one record.
Do use it to group bookings by departure. It's the right key for automations like "text everyone on tomorrow morning's 9:00am boat."
Example: booking created
{
"type": "Booking",
"event": "created",
"booking": {
"id": "1368612",
"format_id": "EJH-1368612",
"user_id": "495016",
"is_direct": true,
"is_office": "0",
"payment_method": "cash",
"rs_agent": "Amber",
"ts_agent": null,
"accesskey": "rqnrgssy",
"made": "2026-07-24 13:38:20",
"state": "confirmed",
"was_refunded": "0",
"refund_amount": "0.00",
"gift_certificate": "",
"has_different_days": false,
"customer_last_name": "Sample",
"customer_first_name": "Jane",
"customer_email": "[email protected]",
"customer_phone": "+15550000000",
"customer_phone2": "",
"customer_address": "123 Example Street",
"customer_city": "Destin",
"customer_zip": "32541",
"customer_state_id": "0",
"customer_state_name": "FL",
"customer_country_id": "5",
"subtotal": 140,
"surcharges": 0,
"subtotal_tax": 0,
"subtotal_fee": 0,
"net_total": 140,
"transaction_info": [
{
"card_type": null,
"card_number": null,
"transaction_id": null
}
],
"discount": [],
"cart_items": [
{
"id": "5495980",
"is_integrated": "0",
"is_overnight": false,
"is_wr_aff": "0",
"state": "confirmed",
"is_gift": false,
"trip_activity": "",
"comment_guest": "",
"comment_partner": "",
"trip_id": "6100",
"trip_name": "Destin Dolphin Watching Cruise",
"trip_slug": "",
"trip_google_place_id": "",
"trip_tax": "0",
"trip_fee": "6",
"booking_fee": "0",
"trip_need_tickets_guests": "0",
"arrival_date": "2026-07-31",
"calendar_id": "151370299",
"booked_format": "1 x $20.00 Child, 3 x $40.00 Adult",
"subtotal": 140,
"surcharges": 0,
"subtotal_tax": 0,
"subtotal_fee": 0,
"net_total": "140.00",
"cancel_reason": "",
"invitation_sent": "0",
"voucher_link": "https://reservations.waverez.com/id0000000/voucher/1368612/5495980/example/",
"rate": [],
"inventory": {
"id": "2885",
"name": "Dolphin Cruise Boat 1",
"duration": "120",
"description": ""
},
"schedule": {
"id": "49564",
"time": "9:00am"
},
"tickets": [
{
"id": "44992",
"name": "Child",
"duration": "120",
"description": "Ages 2-15",
"rs_internal": "",
"is_overnight": false,
"booked": "1",
"price": "20",
"wholesale": "0",
"comission": "0",
"guests": [],
"barcodes": []
},
{
"id": "44993",
"name": "Adult",
"duration": "120",
"description": "Ages 16 and up",
"rs_internal": "",
"is_overnight": false,
"booked": "3",
"price": "40",
"wholesale": "0",
"comission": "0",
"guests": [],
"barcodes": []
}
],
"additional_options": [],
"has_multipass": null,
"start_at": "2026-07-31T09:00:00-05:00",
"end_at": "2026-07-31T11:00:00-05:00",
"clx_fee": 0
}
],
"access_link": "https://reservations.waverez.com/id0000000/access/1368612/user-example",
"clx_fee": 0,
"customer_country_name": "US",
"cancelled": false,
"new": false,
"timezone": "-0500",
"detailsURL": "https://admin-new.waverez.com/orders/1368612"
}
}An updated event looks identical, with "event": "updated", "new": false, and the changed values in place.
Cancellations
A cancellation arrives as "event": "cancelled" with "cancelled": true, "state": "cancelled" at both the booking and cart-item level, and a cancel_reason on the affected cart item.
Monetary totals are zeroed on a cancelled booking. subtotal, net_total, subtotal_tax, subtotal_fee, and surcharges will all read 0.
If you need the original value of a cancelled booking for reporting, you have two options:
Store it when the booking is created. This is the reliable approach, and another reason to build your automation as an upsert — you keep the value from the
createdevent and simply flag the record as cancelled.Reconstruct it from the tickets. The
tickets[]array keeps itspriceandbookedvalues, andbooked_formatremains readable. In the example below, 2 × $20 + 7 × $40 gives you $320 in gross ticket revenue. Note that this excludes taxes, fees, and discounts.
Example: booking cancelled
{
"type": "Booking",
"event": "cancelled",
"booking": {
"id": "1368591",
"format_id": "EJH-1368591",
"made": "2026-07-24 13:28:12",
"state": "cancelled",
"was_refunded": "0",
"refund_amount": "0.00",
"customer_last_name": "Sample",
"customer_first_name": "Jane",
"customer_email": "[email protected]",
"customer_phone": "+15550000000",
"subtotal": 0,
"surcharges": 0,
"subtotal_tax": 0,
"subtotal_fee": 0,
"net_total": 0,
"discount": {
"total": 0,
"total_with_tax": 0
},
"cart_items": [
{
"id": "5495949",
"state": "cancelled",
"trip_id": "6100",
"trip_name": "Destin Dolphin Watching Cruise",
"arrival_date": "2026-07-31",
"calendar_id": "151370299",
"booked_format": "2 x $20.00 Child, 7 x $40.00 Adult",
"subtotal": 0,
"net_total": "0.00",
"cancel_reason": "Guest requested",
"inventory": {
"id": "2885",
"name": "Dolphin Cruise Boat 1",
"duration": "120"
},
"schedule": {
"id": "49564",
"time": "9:00am"
},
"tickets": [
{
"id": "44992",
"name": "Child",
"booked": "2",
"price": "20"
},
{
"id": "44993",
"name": "Adult",
"booked": "7",
"price": "40"
}
],
"start_at": "2026-07-31T09:00:00-05:00",
"end_at": "2026-07-31T11:00:00-05:00"
}
],
"cancelled": true,
"new": false,
"timezone": "-0500",
"detailsURL": "https://admin-new.waverez.com/orders/1368591"
}
}Trimmed for readability — the full payload carries the same fields as a created event.
Waiver Webhooks
This is new. When a guest completes a waiver, WaveRez sends that guest's information to your webhook. Previously you only received data for the lead booker; now you receive a separate webhook for every guest who signs.
This is what makes it possible to:
Send review invitations to everyone on the trip, not just the person who paid
Build birthday and trip-anniversary campaigns from real guest data
Maintain an accurate marketing list with per-guest consent
Structure
Waiver payloads use "type": "Waiver" and put everything under a data object — not booking. Branch on type first in your automation.
Field | Notes |
| Unique per signer. The suffix increments for each guest on the same booking ( |
| The individual guest's details |
|
|
| Format is |
| Which waiver was signed |
|
|
| When and on what device the waiver was signed |
| Custom questions you added to your waiver. The key is generated from the question and will differ per waiver. |
Example: waiver completed
{
"type": "Waiver",
"event": "completed",
"data": {
"arrivalAt": "2026-07-31 09:00:00",
"fillId": "example12345678-abcd-efgh1_0",
"inventory": "Dolphin Cruise Boat 1",
"orderId": "1368612",
"productId": "6100",
"productTitle": "Destin Dolphin Watching Cruise",
"purchaseId": "5495980",
"sellerId": "0000000",
"waiverId": "0000000_r_xxxx",
"waiverTitle": "Standard Liability Waiver",
"firstName": "Jane",
"lastName": "Sample",
"birthDate": "11/28/1985",
"phoneNumber": "+15550000000",
"getPhonePromotions": "1",
"email": "[email protected]",
"getEmailPromotions": "1",
"address": "123 Example Street",
"zip": "32541",
"gender": "female",
"hasMinors": "no",
"isDriver": "yes",
"medicalConditions": "no",
"emergencyFullName": "Alex Sample",
"emergencyContactPhone": "+15550000001",
"emergencyContactAddress": "123 Example Street",
"emergencyContactZip": "32541",
"heardAboutUs": "returnCustomer",
"field_4i-t__ack-1": "1",
"completed": "1",
"waiverVersion": "0000000_r_xxxx",
"signatureMetadata": {
"signedAt": "2026-07-24T18:40:06.400Z",
"device": "macOS Chrome",
"timezone": "America/Chicago",
"platform": "macOS"
}
}
}Connecting Waivers to Bookings
Waiver payloads carry the IDs you need to match a signed waiver back to the booking it belongs to:
Waiver field | Matches |
|
|
|
|
|
|
| Your WaveRez account |
Three things to keep in mind:
Deduplicate on fillId, not email. Guests frequently enter the lead booker's email address for the whole party, and some enter nothing meaningful at all. fillId is the only value guaranteed unique per signer.
For trip date and time, always read the booking — not the waiver. The waiver's arrivalAt reflects the trip date at the moment it was signed. If the booking is later rescheduled, the waiver record is not resent and its date will be out of date. Join on orderId and take the date from the booking's start_at.
There is no "everyone has signed" event. Each waiver arrives on its own, and minors typically don't sign, so ticket counts won't reliably tell you how many waivers to expect. Treat each waiver as an independent record.
Reading the Data Correctly
A few conventions worth knowing before you build:
Dates come in several formats. Use start_at and end_at when you need a precise, time zone-aware moment. arrival_date is date-only. arrivalAt on a waiver has no time zone attached. signedAt is UTC. birthDate is MM/DD/YYYY.
Many yes/no values are sent as text. You'll see "0" and "1" as strings alongside true JSON booleans like is_direct: true. Zapier and Make treat "0" as a non-empty text value, so test your filters — a check for "is true" won't behave the way you expect on these fields.
Use booking.id and cart_items[].id as your keys. They're permanent. calendar_id, schedule.id, and format_id can all change or repeat.
Security and Privacy
Waiver payloads can contain sensitive personal information, depending on how you've configured your waiver — dates of birth, driver's license numbers, emergency contacts, and any medical or health questions you've added.
That data is sent to whatever URL you enter, and it will be stored by whatever service receives it, including in task and run histories.
Before you turn on waiver webhooks:
Treat your endpoint URL as a secret. Anyone with the URL can receive or spoof data. Don't share it or paste it into public forums.
Use a service you'd be comfortable storing guest ID data in, and confirm who on your team can view its logs.
Only collect what you need. If your waiver asks for a driver's license number or health details you don't actually use, remove the question rather than routing it to a third-party system.
Honor
getEmailPromotionsandgetPhonePromotions. A signed waiver is not marketing consent on its own.
If you're unsure whether your setup is appropriate for the data you collect, reach out to WaveRez support before enabling waiver webhooks.
Need Help?
Contact WaveRez support.
