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=…"
}| Field | Description |
|---|---|
paymentUrl | Full subscription payment flow (the default "Subscribe" path). Always returned. |
bookingUrl | Booking 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
| Parameter | Required | Description |
|---|---|---|
transaction_id | Yes | Already embedded in bookingUrl. |
no_subtitle | No | Hides the hero subtitle (useful in compact embeds). |
ptid | No | PostHog 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.
type | When | The host should |
|---|---|---|
greenleaze:reservationInitialized | Modal loaded and ready | Reveal the iframe |
greenleaze:submitReservation | Deposit payment succeeded | Let the user close the iframe |
greenleaze:closeReservation | Close button clicked | Hide / remove the iframe |
