Booking page

The booking modal lets a customer book a rental by paying a deposit. It is a standalone page served from GreenLeaze, embedded or not by the partner in an <iframe>.

Unlike the widget modal, the booking modal is not configured through a live data event. Everything it needs is derived from a single transaction_id passed in the iframe URL. The modal communicates back to the host page through postMessage events (iframe → parent) so the host can reveal the modal, close it, or react once the booking is paid.

Getting the booking URL

Create a transaction with POST /v1/subscriptions/transaction. The response returns paymentUrl, and bookingUrl only when booking is enabled for your shop (otherwise bookingUrl is null). You can enable booking in your dashboard settings.

{
  "success": true,
  "transactionId": "…",
  "subscriptionId": "…",
  "paymentUrl": "https://pay.greenleaze.com/order/duration?transaction_id=…",
  "bookingUrl": "https://reservation.greenleaze.com?transaction_id=…"
}
FieldDescription
paymentUrlFull subscription payment flow (the default "Subscribe" path). Always returned.
bookingUrlBooking flow (deposit). Returned only when booking is enabled for your shop; otherwise null. Enable it in your dashboard settings.

bookingUrl is returned regardless of how the customer got there — it does not depend on the widget Booking button. The button is only a UI affordance: when buttonMode is booking or both, the widget emits greenleaze:submitGreenleazeModal with action: "booking" so your integration knows the customer chose booking and can open bookingUrl instead of paymentUrl. Your integration decides which URL to open; both are always available on the transaction. paymentUrl cannot be used in an iframe.

Example :

// Widget → host: the customer picked an action in the widget modal.
window.addEventListener("message", async (e) => {
  if (e.data.type !== "greenleaze:submitGreenleazeModal") return;

  const tx = await createTransaction(/* product/cart + e.data.duration */);

  if (e.data.action === "booking") {
    openBookingModal(tx.bookingUrl); // deposit flow
  } else {
    window.location.href = tx.paymentUrl; // full subscription flow
  }
});

Opening the modal

Open bookingUrl in an iframe and listen for its events. The modal emits only when embedded.

window.addEventListener("message", (e) => {
  if (e.origin !== BOOKING_ORIGIN) return; // validate the origin

  switch (e.data?.type) {
    case "greenleaze:reservationInitialized": // ready → reveal the iframe
      break;
    case "greenleaze:submitReservation": // deposit paid 
      break;
    case "greenleaze:closeReservation": // user closed → hide the iframe
      break;
  }
});

URL parameters

ParameterRequiredDescription
transaction_idYesAlready embedded in bookingUrl.
no_subtitleNoHides the hero subtitle (useful in compact embeds).
ptidNoPostHog distinct id, to stitch analytics across pages.

postMessage events

All events go iframe → parent, with a payload limited to { type }. Validate event.origin; the modal does not listen for inbound events.

typeWhenThe host should
greenleaze:reservationInitializedModal loaded and readyReveal the iframe
greenleaze:submitReservationDeposit payment succeededLet the user close the iframe
greenleaze:closeReservationClose button clickedHide / remove the iframe