beginner
shop-rentals
status
workflow

Check-in, Start Rental, Complete Return

The reservation status machine — when each transition happens, what gets stamped, and how to handle edge cases

Levy Fleets TeamMay 7, 20265 min read

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
StatusMeaningTrigger
pendingBooking created, payment not finalized(rare; mostly an internal state)
confirmedBooking confirmed, customer expected at pickup timeCreated via public booking, or manual confirmation
checked_inCustomer arrived at the counter, paperwork doneCheck in button
activeCustomer riding off with the bikeStart rental button (auto-stamps actual_pickup_at)
completedBike returned, rental overComplete 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

StatusMeaning
cancelledBooking cancelled. Auto-refund issued if within free-cancel window.
no_showCustomer didn't show up. Set by the no-show cron 2h after pickup if never checked_in.
expiredPending 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 confirmedno_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:

TransitionCustomer sees
checked_in(no notification today; manual check-in is operator-side)
active(no notification today; the customer is right there)
completedReceipt PDF available via the manage-link page
cancelledCancellation email + auto-refund processed
no_showNo-show fee email if applicable

Email triggers depend on your subaccount notification settings; some are configurable per-event.