intermediate
shop-rentals
group-bookings
waivers

Group Bookings & Per-Rider Waivers

Reservations covering multiple bikes or riders — quantity-based pricing, separate waivers per rider, and group discounts

Levy Fleets TeamMay 7, 20265 min read

A "group booking" in Shop Rentals is a reservation with quantity > 1 — same pickup time, same return time, multiple bikes. Common for families, tour groups, or corporate outings.

The data model

A single reservations row covers all bikes in the group:

  • quantity = 4 — four bikes in this booking
  • vehicle_uuid IS NULL — at the model level, not per-vehicle
  • vehicle_model_id — the model they're all renting
  • total_cents reflects the per-unit cost × quantity (with any group discount)

At assignment time, individual vehicles are linked via reservation_assignments rows, one per bike. So a quantity=4 booking can have 4 assigned vehicles, all on the same reservation.

Creating a group booking

Via the public booking page

The public page currently supports quantity = 1 only. Group bookings must be created operator-side.

Via the operator new-booking flow

/dashboard/shop-rentals/new has a quantity selector (1–20). Pick the quantity, location, model, dates → confirm.

Via the walk-in wizard

The wizard creates one reservation per session. For groups arriving at the counter, either:

  1. Run the wizard quantity times (one reservation per rider) — easier for separate billing
  2. Use the new-booking flow with quantity > 1 — easier for one reservation covering all bikes (preferred for tours)

Group discounts

Pricing tiers support quantity-based discounts via the group_pricing_tiers JSON column:

[
  { "min_quantity": 5, "discount_percent": 10 },
  { "min_quantity": 10, "discount_percent": 20 }
]

A quantity = 7 booking gets the 10% threshold; quantity = 12 gets 20%. The pricing engine picks the highest applicable threshold and applies it as a multiplier on the per-unit base cost. See Group / tiered pricing for the full reference.

Per-rider waivers

For a 4-bike group, you may want 4 separate waivers so each rider signs individually with their typed name.

Issue per-rider waivers

On the booking detail page, in the Agreements & Waivers panel:

  1. Click Issue signing link for your active template
  2. The first link is rider_index = 0, generic for the lead booker
  3. To issue per-rider, use the API:
POST /api/reservations/[id]/agreements
{
  "templateId": "...",
  "isPerRider": true,
  "riderIndex": 1
}

Repeat for riderIndex: 2, 3, 4 etc. Each gets a separate token and a separate signed_agreements row.

How customers see them

The signing page shows a "Rider X of Y" badge when is_per_rider=true so the rider knows which slot they're filling. The lead booker sends each link to the corresponding rider via SMS, AirDrop, or — at the counter — a printed QR code per rider.

What you get back

After all rider signatures arrive, the booking detail page shows N signed-agreement rows, one per rider, with each rider's typed name and timestamp.

Operational tips

Counter group flow

  1. Create the group booking with quantity = 4
  2. Issue 4 per-rider waiver links
  3. Print them as 4 QR codes on a single sheet
  4. Hand each rider their QR code
  5. Wait for all 4 to sign on their phones
  6. Verify the booking detail shows 4 signed waivers
  7. Hand over the bikes

This whole flow takes about 5-7 minutes once everyone's at the counter.

Mixed-rider groups (parents + minors)

Minors typically need a parent or guardian signature. Two patterns:

  1. Single template with parent-signed clause — the parent signs once on behalf of all minors in the group. Track minor names in a custom field on the agreement template.
  2. Separate templates per rider type — adult template for adults, minor-with-guardian template for minors. Issue different templates per riderIndex.

Damage handling on group bookings

A damage event ties to the group reservation, not to a specific rider. If you can identify which rider caused it, capture that in the description field of the service log entry. The damage charge adds to the group reservation's total.

If you want per-rider liability, you'll need a contractual mechanism outside the system (e.g., the lead booker is the one financially responsible per your policy).

What's not in group bookings

  • Per-rider pricing differences — all riders in a group reservation pay the same unit rate. You can't have rider 1 at adult pricing and rider 2 at child pricing in one reservation. Make separate bookings if you need this.
  • Per-rider time windows — all riders share pickup_at and return_at. If a tour has staggered start times per rider, each rider needs a separate booking.
  • Per-rider add-ons — add-ons are at the reservation level, not per-rider. If 2 of 4 riders want helmets and 2 don't, configure the group reservation with quantity=2 for helmet, even though quantity=4 for the bikes.

Reporting group bookings

SELECT
  date_trunc('week', pickup_at) AS week,
  count(*) FILTER (WHERE quantity > 1) AS group_bookings,
  sum(quantity) FILTER (WHERE quantity > 1) AS group_riders,
  avg(total_cents / quantity) / 100.0 AS avg_per_rider_revenue
FROM reservations
WHERE pickup_at >= '2026-05-01'
GROUP BY 1
ORDER BY 1 DESC;

Track this metric — group bookings are typically your highest-margin segment because the discount tier is small relative to the operational efficiency of one transaction covering many bikes.