Crystallize logo

Booking policies: buffers, cancellation windows and holds

Set your booking rules once and apply them to every room, rental or service you sell. Booking policies add setup and cleanup time around each booking and set how far ahead customers can book and how late they can cancel. They also hold a slot during checkout, or until a slow payment like a bank transfer arrives, so you never double-book or lose a sale.

A booking policy is a named, reusable set of time rules that a bookable product is configured against: the buffers reserved around each booking, and the windows that govern when a booking can be made, when it can still be cancelled, and how long a slot is held while a shopper checks out. One policy usually covers a whole class of product — a hotel, a rental, a service — so you set the rules once and point many products at them.

You manage booking policies in Settings › Booking policies. This page covers the policies themselves. Applying a policy to a specific product, together with pools and capacity, is done from the product and is covered on Bookable products.

The policy list

The sidebar lists every policy in the tenant, sorted by name. Next to each name is a usage count — the number of products whose booking configuration currently references that policy. A policy that nothing references shows no count and is safe to delete. Selecting a policy opens it in the editor; the “+” button opens a blank editor for a new one.

Creating a policy

Select “+”, give the policy a name — unique within the tenant — set its buffers and windows, and choose Create. A new policy opens on sensible defaults: no buffers, a 24-hour cancellation window, a 90-day advance window, a 15-minute pending hold and no placed-hold extension. Adjust any of them before saving.

Renaming a policy

Open the policy, edit its name in the toolbar and Save. Renaming does not affect the products that reference the policy.

Deleting a policy

Open the policy and choose Delete. A policy that is still referenced by one or more products cannot be deleted — before you confirm anything, the app tells you how many products reference it and asks you to remove the policy from those products’ booking sections first. Once nothing references it, deletion is permanent and cannot be undone. Bookings already made are unaffected: each reservation keeps the frozen terms it was booked under.

The editor

The editor is built around two cards — Buffers and Windows. Every field is a duration, entered as a number plus a unit (seconds, minutes, hours or days). Each field has a live preview that shows what the duration does to a booking, so you can see the effect of a change before you save it.

note

Durations are entered by hand, stored in seconds

You type each duration in whichever unit is convenient, but every value is stored and carried as a whole number of seconds. Over the API each field is read and written in seconds — the hours or days you enter in the app cross the wire as their equivalent in seconds. The app simply restates those seconds in the largest unit that divides them exactly (3600 shows as 1 hour, 5401 shows as 5401 seconds), so what you see always round-trips to the stored value.

Buffers

A buffer is dead time reserved around every booking — for turnaround, cleaning, travel or setup — that no one can book over. Buffers widen the block a booking actually takes on the resource: a two-hour booking with a 15-minute after-buffer occupies two hours and fifteen minutes, and the next booking cannot start until that padding has passed. Buffers apply on both sides of a booking, and a candidate booking is refused when its own buffer would collide with an existing one. The preview draws the buffer as part of the booking’s block so you can see the reserved range grow.

Before booking

Time reserved immediately before each booking starts. Use it when a resource has to be prepared ahead of the customer — a room set up, a vehicle fetched, a technician travelling in. The slot stays unbookable for this long before every booking’s start.

After booking

Time reserved immediately after each booking ends — cleaning, turnaround, a technician travelling out. The next booking cannot begin until this padding has passed.

Windows

The Windows card holds four durations that govern when a booking may be made, how late it can still be cancelled, and how long a slot is held while a shopper moves through checkout.

Cancellation window

How close to the booking’s start a customer may still cancel. A 24-hour window means a customer can cancel freely up until 24 hours before the start; after that point the booking is locked and can no longer be cancelled from the storefront.

Advance window

How far ahead of time a booking may be made. A 90-day window means a slot opens for booking 90 days before it starts and no earlier — anything further out reads as “too far ahead” and is refused until it comes within range.

Pending hold

How long a slot is held for a shopper who has added it to a cart but not yet placed the order. While the hold is live the slot is unavailable to everyone else; if the shopper never checks out, the hold expires after this duration and the slot is released back to availability.

Placed hold

How long a placed-but-unpaid cart keeps its slot — the extension that takes over once checkout is submitted but before payment has cleared. It defaults to 0, which means “do not extend”: the slot simply keeps its original pending expiry. Zero is the right setting whenever payment clears immediately. Raise it only when payment can take a while to arrive — invoices or bank transfers — so the slot is not released before the money lands.

tip

Pending hold vs placed hold

These are the two people most often get wrong. The pending hold covers the shopper while they are still in checkout. The placed hold takes over after the cart is placed but before payment clears, extending the hold from that moment. If you take payment immediately, leave the placed hold at 0. If you invoice or accept bank transfers, set it long enough to cover how long the money realistically takes to arrive.

Editing a policy does not touch existing products

Editing a policy changes it only for bookings configured from now on. Products already configured against the policy keep the exact terms they captured when they were last saved — the policy is frozen onto the product at that moment, and later edits do not reach back to it. To bring a product onto the new terms, reapply the policy from that product’s booking section. Existing reservations never change either: each keeps the policy it was booked under, even after the product reapplies.

Reapplying a policy is a product-side action — see Bookable products for the full flow.

Permissions

Booking policies have their own set of role permissions. A role needs the matching one for each action:

  • Read — view the policy list and open a policy.
  • Create — add a new policy.
  • Update — edit or rename an existing policy.
  • Delete — remove a policy.

Without Read, the Booking policies section is unavailable. The create control appears only with Create; a policy opened without Update shows every field but keeps them read-only with the save button disabled; and Delete gates the delete action. Because booking policies are a newer resource, a custom role created before the feature may not list them yet — add the Booking policies permissions to any such role if a user who should have access is denied.

Through the API

The same policies are available over the PIM API. Read them with the bookingPolicies and bookingPolicy queries, and manage them with the createBookingPolicy, updateBookingPolicy and deleteBookingPolicy mutations. Every duration is an integer number of seconds. placedHoldDuration is optional — omitting it stores 0 (“do not extend”). Names are unique per tenant, and deleting a policy that products still reference fails rather than cascading.

mutation {
createBookingPolicy(input: {
name: "Standard 1h"
bufferBefore: 0
bufferAfter: 900 # 15 minutes
cancellationWindow: 86400 # 24 hours
advanceWindow: 2592000 # 30 days
pendingHoldDuration: 600 # 10 minutes
placedHoldDuration: 0 # do not extend
}) {
... on BookingPolicy { id name version }
... on BasicError { message errorName }
}
}