Camper BMS
Login

Webhooks

Push booking, invoice, lease and customer events to your other systems automatically, within seconds of them happening.

When You'd Use Webhooks

Webhooks connect Camper BMS to systems that live outside it - a CRM, a staff chat, a spreadsheet, or a no-code tool like Zapier (which can pass events on to hundreds of other apps without any code). You don't need a developer, and if you don't connect anything, nothing depends on this feature.

Accessing Webhooks

Navigate to Integrations > Webhooks from the main navigation.

Adding an Endpoint

  1. Click to add an endpoint and enter the secure (HTTPS) web address that should receive the events.

  2. Choose which events it should receive, or leave them all selected to receive everything.

  3. Tick the acceptance checkbox to confirm you accept responsibility for data sent to this endpoint.

  4. Copy the signing secret so your receiving system can verify incoming messages.

  5. Click Send test to fire a sample event and confirm the other end is receiving it.

You can pause, resume or delete a connection at any time.

Events You Can Listen For

  • Bookings - created, reserved, pending, confirmed, cancelled, or changed (a new check-in, check-out or site)

  • Arrivals and departures - checked in, checked out

  • Invoices - issued, paid, refunded

  • Leases - created, activated, renewed, ended, or changed (a new date, site, access code or vehicle registration)

  • Customers - a new guest record created

What's in the Data

Each message includes the event name, when it happened, and which campground it relates to, plus the details for that event (the guest and booking for a booking event, the invoice for an invoice event, the lease and its tenants for a lease event).

  • Consent travels with the data. Every guest in a payload carries a marketing-consent flag so your receiving system can respect it.

  • The IDs are safe to share. Identifiers in the payload are public reference codes, never internal database IDs.

  • Arrival details travel with the booking. Every booking payload carries the check-in and check-out dates and times, your park's timezone, and the access code and vehicle registration when they are set.

Security and Reliability

  • HTTPS only - endpoints must be secure web addresses.

  • Every message is signed with HMAC-SHA256 using your endpoint's secret. Your receiving system can recompute the signature to confirm the message genuinely came from Camper BMS. The Webhooks page provides copy-ready PHP, Node and Python verification examples.

  • Automatic retries - if your endpoint doesn't respond, Camper BMS retries a couple of times over the next few minutes. Each connection shows its consecutive-failure count, and a persistently broken endpoint is automatically paused (and you're emailed) so it isn't hammered.

  • Destination checks - Camper BMS verifies the destination is a genuine external server, blocking attempts to point webhooks at internal addresses.

Delivery Log

Every delivery attempt is recorded - the event, where it went, whether it succeeded, the response, and the exact data sent. Each delivery has a Resend button to re-fire a payload if the other system was down. Delivery records are kept for 90 days, then automatically deleted.

Billing and Consent

  • Webhooks are included at no extra charge - not metered. Like the API, they're available on every account and pause automatically while an account is restricted (for example, an unpaid invoice).

  • Webhooks are not gated behind marketing consent - they're operator-directed data flows, so the consent decision belongs to your receiving system (which is why the consent flag travels in every payload).

Developer Detail

Every webhook is an HTTP POST to your endpoint with a JSON body. Payloads are built at the moment the event happens.

Delivery

HeadersContent-Type: application/json, X-CamperBMS-Event (the event name), X-CamperBMS-Signature (see below).
SignatureHex HMAC-SHA256 of the raw request body, keyed with the endpoint's signing secret from the Webhooks page.
Timeout10 seconds. Redirects are not followed.
RetriesThree attempts: immediately, then after 60 seconds, then after a further 5 minutes.
Auto-disableAfter 100 consecutive failed attempts the endpoint is switched off and the park owner is emailed. Re-enable it from the Webhooks page. Events that happened while it was off are not replayed.
Restricted accountsDelivery pauses while the account is restricted and resumes on its own. Events during the pause are not replayed.
Test sendsThe Send test action posts a booking-shaped payload with "test": true and placeholder IDs.

Verify the signature over the exact bytes received, comparing in constant time:

// PHP
$expected = hash_hmac('sha256', $rawBody, $secret);
$valid = hash_equals($expected, $request->header('X-CamperBMS-Signature'));

// Node
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.get('X-CamperBMS-Signature')));

Events

Every payload starts with the envelope below, followed by the block named in the Payload column. To act only on paid bookings, use booking_confirmed. booking_created also fires for unpaid holds and drafts.

EventFires whenPayload
booking_createdAny booking is created, whatever its status. This includes drafts and reserved checkout holds that may expire.booking
booking_reservedA booking is created as, or moves to, reserved.booking
booking_pendingA booking is created as, or moves to, confirmed_pending.booking
booking_confirmedA booking is created as, or moves to, confirmed_paid.booking
booking_cancelledA booking moves to cancelled.booking
booking_changedThe check-in date, check-out date or site changes without a status change.booking
checked_inThe guest is checked in, by staff, self check-in or the API.booking
checked_outThe guest is checked out.booking
invoice_issuedAn invoice is created, whatever its status: rent, utilities and manual lease invoices, and booking invoices.invoice
invoice_paidAn invoice becomes paid.invoice
invoice_refundedAn invoice becomes refunded.invoice
lease_createdA lease is created.lease
lease_activatedA lease becomes active.lease
lease_renewedA lease is renewed.lease
lease_endedA lease ends.lease
lease_changedThe start date, end date, site, end-of-lease action, occupancy start, access code or vehicle registration changes without a status change. Not sent for a renewal, which is lease_renewed.lease
customer_createdA customer record is created.customer

Envelope

Present on every payload.

FieldTypeNotes
eventstringOne of the events listed above.
testbooleantrue only for a test send from the Webhooks page.
occurred_atstringISO 8601 with offset, in UTC.
campground.idstringPublic reference code, never a database ID.
campground.namestring
campground.timezonestringIANA zone, for example Australia/Sydney. Check-in and check-out times are local to this zone.

Booking payload

Events: booking_created, booking_reserved, booking_pending, booking_confirmed, booking_cancelled, booking_changed, checked_in, checked_out.

{
  "event": "booking_confirmed",
  "test": false,
  "occurred_at": "2026-09-09T04:09:39+00:00",
  "campground": {
    "id": "CMG9Q6MGG72J",
    "name": "Equinox Foreshore Reserve",
    "timezone": "Australia/Melbourne"
  },
  "guest": {
    "id": "CT3K8VQ2PL",
    "email": "guest@example.com",
    "first_name": "Sam",
    "last_name": "Taylor",
    "marketing_consented": true
  },
  "booking": {
    "id": "BKZ57Y950WQK",
    "check_in": "2026-09-18",
    "check_out": "2026-09-19",
    "check_in_time": "15:00",
    "check_out_time": "11:00",
    "site_type": "Powered Site",
    "guests": 3,
    "children": 1,
    "infants": 1,
    "status": "confirmed_paid",
    "access_code": "6173",
    "vehicle_registration": "XYZ-123"
  }
}
FieldTypeNotes
guestobject or nullThe booking's customer.
guest.idstringPublic reference code.
guest.email, guest.first_name, guest.last_namestring
guest.marketing_consentedbooleanWhether the guest has given marketing consent. Webhooks are not consent-gated, so honour this before any marketing use.
booking.idstringPublic reference code. The same ID the REST API accepts.
booking.check_in, booking.check_outstringYYYY-MM-DD.
booking.check_in_time, booking.check_out_timestringHH:MM, 24-hour, local to campground.timezone. The booking's own time if one is set, otherwise the park default.
booking.site_typestring or nullThe campsite area name.
booking.guestsintegerAdults and children on the booking.
booking.childrenintegerHow many of guests are children. 0 when there are none.
booking.infantsintegerBabies and toddlers on the booking, counted on top of guests. They stay free. 0 when there are none.
booking.statusstringdraft, reserved, confirmed_pending, confirmed_paid or cancelled.
booking.access_codestring or nullThe access code sent to the guest before arrival, if set.
booking.vehicle_registrationstring or nullThe number plate, upper case with single spaces, if set.

Invoice payload

Events: invoice_issued, invoice_paid, invoice_refunded.

{
  "event": "invoice_paid",
  "test": false,
  "occurred_at": "2026-09-09T04:09:39+00:00",
  "campground": { "id": "CMG9Q6MGG72J", "name": "Equinox Foreshore Reserve", "timezone": "Australia/Melbourne" },
  "guest": {
    "id": "CT3K8VQ2PL",
    "email": "guest@example.com",
    "first_name": "Sam",
    "last_name": "Taylor",
    "marketing_consented": true
  },
  "invoice": {
    "id": "IN7H2M4QWX",
    "amount": 248.00,
    "currency": "AUD",
    "status": "paid",
    "booking_id": "BKZ57Y950WQK",
    "lease_id": null
  }
}
FieldTypeNotes
guestobject or nullThe invoice's customer, in the guest shape above.
invoice.idstringPublic reference code.
invoice.amountnumberDollars, two decimal places.
invoice.currencystringAUD unless the invoice says otherwise.
invoice.statusstringFor invoice_issued, the status the invoice was created with, usually unpaid. paid or refunded for the other two.
invoice.booking_idstring or nullThe booking the invoice belongs to.
invoice.lease_idstring or nullThe lease the invoice belongs to.

Lease payload

Events: lease_created, lease_activated, lease_renewed, lease_ended, lease_changed.

{
  "event": "lease_activated",
  "test": false,
  "occurred_at": "2026-09-09T04:09:39+00:00",
  "campground": { "id": "CMG9Q6MGG72J", "name": "Equinox Foreshore Reserve", "timezone": "Australia/Melbourne" },
  "lease": {
    "id": "LS4P9X1RQ7",
    "start_date": "2026-07-01",
    "end_date": "2027-06-30",
    "status": "active",
    "site_type": "Powered Site",
    "end_of_lease_action": "renew_same_term",
    "occupancy_started_at": "2019-03-15",
    "access_code": "4321",
    "vehicle_registration": "ABC 123"
  },
  "tenants": [
    {
      "id": "CT3K8VQ2PL",
      "email": "tenant@example.com",
      "first_name": "Sam",
      "last_name": "Taylor",
      "marketing_consented": false
    }
  ]
}
FieldTypeNotes
lease.idstringPublic reference code.
lease.start_date, lease.end_datestring or nullYYYY-MM-DD. end_date is null for an open-ended lease.
lease.statusstringdraft, active, expired or cancelled.
lease.site_typestring or nullThe campsite area name.
lease.end_of_lease_actionstringterminate, renew_same_term or month_to_month.
lease.occupancy_started_atstring or nullYYYY-MM-DD. When the tenant first moved in, which can be earlier than start_date on a renewed or migrated lease.
lease.access_codestring or nullThe access code for the tenant, if set.
lease.vehicle_registrationstring or nullThe number plate, upper case with single spaces, if set.
tenantsarrayEvery customer on the lease, each in the guest shape. May be empty.

Customer payload

Events: customer_created. The guest block is as described under the booking payload.

{
  "event": "customer_created",
  "test": false,
  "occurred_at": "2026-09-09T04:09:39+00:00",
  "campground": { "id": "CMG9Q6MGG72J", "name": "Equinox Foreshore Reserve", "timezone": "Australia/Melbourne" },
  "guest": {
    "id": "CT3K8VQ2PL",
    "email": "guest@example.com",
    "first_name": "Sam",
    "last_name": "Taylor",
    "marketing_consented": false
  }
}

Test payload

The Send test action posts a booking payload with "test": true, "id": "test" on the guest and the booking, dates seven and ten days ahead, the park's default check-in and check-out times, and null for access_code and vehicle_registration. Its fields are identical to a real booking payload.

Related articles

Still need a hand?

Our support team is happy to help.

Contact support