Skip to content

Documentation · Concepts

Booking rules

8 min read · Concepts · Updated 2026-05-15

Concepts8 minShare
Documentation sections

Booking rules are how you express “who can book what, when, at what price.” Every resource has a default rule (any member, any time, the flat hourly rate); you layer additional rules on top for tier gating, blackouts, member-only periods, and surge pricing.

This guide is conceptual — we don't walk through a specific UI. The conceptis what generalises across the rule builder, the API, and the bulk importer. Once you understand the model, the surface you build it from doesn't matter.

All examples are demo content. Pricing in JSON snippets is in NZD for readability — your rules use whatever currency you set at workspace level.

Section 1

Per-tier rules, blackouts, member-only resources

The three shapes that cover ~90% of operator needs

Most operators only ever need three rule shapes. We've seen rule builders that ship with 20 — and operators only ever use these three. Build for the common case first.

1. Per-tier pricing

Charge members different rates depending on their tier. Free tier pays a guest rate, paid tier gets included hours, premium tier gets unlimited access. Always evaluated as an override on the resource's default rate.

2. Blackouts

Block bookings for a window. Examples: building closed for a public holiday, room reserved for staff training, weekly cleaning slot. Blackouts are hard: the room is simply not bookable. They take precedence over every other rule.

3. Member-only resources

Restrict a resource so it's only visible to active members. Guest bookings via the public URL never see member-only resources. Useful for premium spaces (recording studios, the “quiet” floor) that you want to reserve as part of the membership value.

The resource detail view — three toggles for tier gating, blackout windows, and member-only visibility.
The resource detail view — three toggles for tier gating, blackout windows, and member-only visibility.

Section 2

Rule builder walkthrough

Abstract concept · same shape across UI / API / bulk import

Whatever surface you build rules from, they all serialise to the same JSON shape under the hood. The shape is intentionally narrow — five top-level fields, no surprises.

The fields

  • scope. Which resources this rule applies to. Either a single resource_id, an array of ids, or "*" for all-resources.
  • actor. Who the rule targets. Tier id, member id, the string "guest", or "*" for everyone.
  • time.When it's active. ISO 8601 ranges, recurring cron-like windows (“mon-fri 09:00-17:00”), or specific dates.
  • effect. What happens. allow, deny, price, require_approval.
  • priority. Integer 0–100. Higher wins. Defaults explained in the conflicts section.

See /v2/preview/app/settings for where you configure global workspace defaults that interact with per-resource rules.

Section 3

Four example rules

Copy-pasteable JSON · representative shapes

Four real-shape examples — change the ids and you can paste these into the bulk import endpoint as-is.

Example 1 — Premium tier gets 50% off the boardroom

rule_premium_discount.json
json
{
  "id": "rule_demo_premium_boardroom_50",
  "scope": { "resource_id": "res_boardroom_demo" },
  "actor": { "tier_id": "tier_premium" },
  "time": "*",
  "effect": {
    "type": "price",
    "amount_cents": 2250,
    "currency": "NZD",
    "per": "hour"
  },
  "priority": 50
}

Example 2 — All resources closed for the Anzac Day public holiday

rule_anzac_blackout.json
json
{
  "id": "rule_demo_anzac_2026",
  "scope": "*",
  "actor": "*",
  "time": {
    "start": "2026-04-25T00:00:00+12:00",
    "end":   "2026-04-26T00:00:00+12:00"
  },
  "effect": { "type": "deny", "reason": "Anzac Day — building closed" },
  "priority": 90
}

Example 3 — Recording studio is members-only on weeknights

rule_studio_member_only.json
json
{
  "id": "rule_demo_studio_member_only_weeknights",
  "scope": { "resource_id": "res_studio_demo" },
  "actor": "guest",
  "time": "mon-fri 17:00-22:00 Pacific/Auckland",
  "effect": { "type": "deny", "reason": "Members only after-hours" },
  "priority": 60
}

Example 4 — Free-tier members pay a guest-equivalent rate on weekends

rule_free_tier_weekend.json
json
{
  "id": "rule_demo_free_tier_weekend_surcharge",
  "scope": { "resource_id": "res_boardroom_demo" },
  "actor": { "tier_id": "tier_free" },
  "time": "sat,sun Pacific/Auckland",
  "effect": {
    "type": "price",
    "amount_cents": 5500,
    "currency": "NZD",
    "per": "hour",
    "label": "Weekend rate"
  },
  "priority": 40
}

Section 4

Conflict resolution

Priority wins · then specificity · then most-recent

Two rules can apply to the same booking attempt. The resolver picks one. The order is deterministic — if the input doesn't change, the output doesn't either.

The resolution order

  1. Higher priority wins. Blackouts default to 90, member-only to 60, price overrides to 40. You can override.
  2. Tie-break on specificity. A rule scoped to a single resource_id beats "*". A rule scoped to a single member beats one scoped to a tier.
  3. Tie-break on recency. The most recently created rule wins. Surface which rule fired in the booking detail view so operators can see which one applied.

Worst-case behaviour

If two rules tie on all three criteria (priority + specificity + recency, which is impossible without manual id forging), the resolver picks the rule with the lexicographically earlier id. We surface a console warning when this happens.

Section 5

Overrides (front-desk + automatic surge)

Manual + automatic escape hatches · always audit-logged

Rules cover the steady-state. Overrides cover the exception. Two flavours: a manual override that staff can apply at the front desk, and an automatic override that responds to demand.

Front-desk override

Front-desk staff can override a deny or a blackout for the next 24 hours, with a reason. The override is logged and notifies the operator-owner via a digest email.

frontdesk_override.example.json
json
POST /v1/bookings/{booking_id}/override
{
  "reason": "Vendor onsite for elevator maintenance — using boardroom as staging",
  "valid_until": "2026-05-23T18:00:00Z",
  "scope": "this_booking_only"
}

Automatic surge

Workspace-wide, optional. When occupancy crosses 85%, surge pricing applies the next slot a guest tries to book. Surge is a percentage multiplier on the base rate (configurable, default 1.5x), capped at 2x. Surge never applies to existing members — only to new guest bookings.