Every reservation moves through a status machine. The Desk manifest exposes the right buttons for each step so staff don't have to think about the underlying state — but understanding it helps when things go sideways.
The happy-path flow
pending → confirmed → checked_in → active → completed
| Status | Meaning | Trigger |
|---|---|---|
pending | Booking created, payment not finalized | (rare; mostly an internal state) |
confirmed | Booking confirmed, customer expected at pickup time | Created via public booking, or manual confirmation |
checked_in | Customer arrived at the counter, paperwork done | Check in button |
active | Customer riding off with the bike | Start rental button (auto-stamps actual_pickup_at) |
completed | Bike returned, rental over | Complete return button (auto-stamps actual_return_at) |
Walk-in bookings created via the POS wizard
skip directly to active because the customer is right there.
Off-path statuses
| Status | Meaning |
|---|---|
cancelled | Booking cancelled. Auto-refund issued if within free-cancel window. |
no_show | Customer didn't show up. Set by the no-show cron 2h after pickup if never checked_in. |
expired | Pending booking that didn't finalize within its checkout window. |
What happens when you press each button
Check in
- Sets
status = 'checked_in' - No timestamp stamped — the customer is here but hasn't taken the bike yet
- Still time to verify the waiver, swap to a different bike, or apply add-ons
Start rental
- Sets
status = 'active' - Auto-stamps
actual_pickup_at = now()if not already set - The deposit hold remains active; no new charges happen at this step
Complete return
- Sets
status = 'completed' - Auto-stamps
actual_return_at = now()if not already set - Auto-stamps
actual_pickup_at = now()if it was somehow null (e.g., walk-in created without going through "Start rental") - Does NOT yet charge the deposit, capture damage, or apply late fees — those are separate explicit actions
For the explicit damage capture flow, see Damage at return.
Where the buttons appear
Manifest (Desk)
Each row in the today's manifest shows the appropriate single button based on current status. This is the most common path during the day.
Booking detail page
/dashboard/shop-rentals/bookings/[id] has the same status-aware
buttons, plus richer actions like Refund, Cancel, and damage logging.
Calendar (week/day view)
Click a reservation pill on the calendar to drill into its detail page; no inline transition buttons on the calendar grid itself.
Manual override via PATCH
If the buttons don't fit a niche case, the underlying API accepts:
PATCH /api/reservations/[id]
{ "status": "completed" }
This still auto-stamps the actual_* timestamps based on which transition you're entering.
Common edge cases
Customer wants to swap to a different bike at check-in
Don't press "Start rental" yet. Open the booking detail, change the
vehicle_uuid from the assignment dropdown, then return to the manifest
and press Start rental.
Customer wants to extend mid-rental
Open the booking detail, edit return_at. The pricing snapshot is
re-applied if the new total falls outside the original tier's bounds —
otherwise the existing pricing carries through. Operator may want to
collect additional deposit if extending into a higher tier.
Customer never shows up
The no-show cron runs every 15 minutes and flips confirmed →
no_show if pickup_at + 2h < now() and never checked_in. The
cancellation fee may apply depending on policy.
If you want to manually mark no-show before the cron, use:
PATCH /api/reservations/[id]
{ "status": "no_show" }
Bike returned with damage
Don't press "Complete return" first. Use the damage-at-return endpoint which atomically marks complete, logs the damage event, and adjusts the reservation total in one transaction.
Operator pressed wrong button
Status transitions go forward. Going backward (e.g., active → confirmed) isn't directly supported. If you genuinely need to revert, contact support — we can fix bad transitions in the database, but it's rarely the right move.
Customer-visible artifacts
Each status transition triggers downstream effects:
| Transition | Customer sees |
|---|---|
→ checked_in | (no notification today; manual check-in is operator-side) |
→ active | (no notification today; the customer is right there) |
→ completed | Receipt PDF available via the manage-link page |
→ cancelled | Cancellation email + auto-refund processed |
→ no_show | No-show fee email if applicable |
Email triggers depend on your subaccount notification settings; some are configurable per-event.