Every public booking generates a manage link — a personal,
unguessable URL like /manage/abc123def456... that the customer can
use to view their booking, cancel it, or sign waivers. No account
required.
What it includes
The manage page shows:
- Booking summary — number, status badge
- Customer name + bike model
- Pickup and return times
- Pickup location with address
- Add-ons with quantities and prices
- Charges breakdown — total, paid, refunded, balance due
- Pending waivers — with signing links
- Cancel this booking button (if within cancellable status)
Where the link comes from
When a customer books via the public page, the backend issues a
30-day-expiring reservation_access_tokens row with purpose = 'manage'.
The token is returned in the booking confirmation response and embedded
in the confirmation email as https://fleets.levyelectric.com/manage/<token>.
What customers can do
View
Open the link → see all booking details. No verification step. The token IS the credential.
Cancel
If the booking is in pending or confirmed status, the customer sees
a Cancel this booking button. Click → reason field → confirm.
The cancel API runs the same cancelReservation logic as operator-side
cancels, including auto-refund-to-wallet for free-cancel-window
cancellations. See Cancellation handling.
Sign pending waivers
If the booking has any pending waivers (e.g., issued via the
walk-in wizard or by an operator on the booking detail), an "Action
needed — please sign the rental waiver" banner appears with a link to
the public sign page.
What customers cannot do via manage-link
- Edit dates / extend — for now, contact the shop directly. We're considering exposing this in a future release.
- Reassign vehicle — operator-only.
- Apply gift card / promo code — the manage page is read-mostly; add-ons, gift cards, and promos are applied at booking time, not after.
- Add or remove add-ons — same; locked at booking.
- See operator notes (admin_notes) — those are internal-only.
- Switch payment method — they need to handle this through the next booking's flow.
Token security
- 30-day expiration by default — long enough for typical pre-pickup reschedules
- Random 192 bits of entropy — unguessable
- Stored hashed-or-cleartext (cleartext today; we may move to SHA-256 in a future release for breach hygiene)
- One token per booking; tokens aren't shared across reservations
If a customer forwards the link to a friend, the friend gets full access to manage that booking. Frame this as a feature, not a bug — many bookings are made by one person on behalf of a group.
Operator visibility
Operators see the token URL on the booking detail page (if a token exists). To re-send to a customer, copy the link and email it. We don't yet have a "re-send confirmation email" button — planned.
Issuing extra tokens
For special cases (a customer lost their email, you want a tokenized "view-only" link to share with their group):
INSERT INTO reservation_access_tokens (
reservation_uuid,
token,
purpose,
expires_at
)
VALUES (
'<reservation-id>',
encode(gen_random_bytes(24), 'base64'),
'view',
now() + interval '7 days'
);
The purpose field can be view, cancel, or manage. Currently the
manage page treats them all the same — purpose-scoped permissions are
on the roadmap.
What customers see if the token is invalid
Cannot load booking
Invalid link
For:
- Bad token (typo or expired)
- Reservation deleted
- Token already consumed (we don't burn tokens today, but might in the future for security)
Operators can issue a new token via the SQL above and resend.
Common scenarios
Customer lost the confirmation email
Look up their booking on the operator dashboard, copy the manage URL from the booking detail page, and forward it.
Customer wants to cancel after the cron auto-flipped no-show
The cancel API requires status to be cancellable. Once no_show, the
button on the manage page disappears. Customer needs to contact you
for a manual review.
Customer wants to extend their rental at pickup time
Easier handled at the counter — the customer arrives, you extend in the dashboard. The manage-link page doesn't have an "extend" feature today.
Privacy / GDPR
The manage-link is a passive URL — it doesn't track the customer or log clicks. The page makes one API call to fetch the booking details on load. No third-party trackers.
If a customer requests their data deleted, deleting the customer row cascades the access tokens. The link stops working immediately.