Skip to content

Booking Lifecycle

Every booking in The Booking Kit follows a defined state machine. All transitions are recorded in an append-only audit trail.

┌──────────┐
│ pending │
└────┬─────┘
│
┌──────────┼──────────┐
▼ ▼ ▼
┌─────────┐ ┌────────┐ ┌──────────┐
│confirmed│ │rejected│ │(auto- │
└────┬────┘ └────────┘ │ reject) │
│ └───────────┘
┌────────┼────────┬─────────┐
▼ ▼ ▼ ▼
┌─────────┐ ┌──────┐ ┌──────────┐ ┌────────┐
│completed│ │no_show│ │cancelled │ │resched-│
└─────────┘ └──────┘ └──────────┘ │uled │
└────────┘
Status Description
pending Awaiting provider confirmation (confirmation mode only)
confirmed Booking is confirmed and on the schedule
completed Appointment has taken place
cancelled Cancelled by customer or provider
rescheduled Original booking moved to a new time
no_show Customer did not attend
rejected Provider declined the booking (confirmation mode)
From To
pending confirmed, rejected
confirmed completed, cancelled, rescheduled, no_show

Auto-confirm event types skip pending and go directly to confirmed.

Event types can require manual approval before bookings are confirmed:

import { getInitialBookingStatus, getAutoRejectDeadline } from "@thebookingkit/core";
// Returns "pending" or "confirmed" based on event type config
const status = getInitialBookingStatus(eventType.requiresConfirmation);
// Auto-reject deadline (default: 24 hours)
const deadline = getAutoRejectDeadline(booking.createdAt);

See Confirmation Mode for full details.

Every status change is recorded in the booking_events table:

Column Description
booking_id FK to the booking
event_type The type of change (status_change, created, updated, etc.)
old_status Previous status
new_status New status
actor_id Who made the change (provider, customer, or system)
metadata JSONB with additional context
created_at When the change occurred

The booking_events table is append-only — rows can never be directly updated or deleted, and a RESTRICT foreign key prevents deleting a booking while its audit rows exist. For GDPR erasure, use anonymize_customer() which anonymizes PII in place rather than deleting records. This provides a complete, tamper-proof history of every booking for auditing, dispute resolution, and analytics.

A database trigger automatically creates audit entries on booking status changes.

Customers can manage their bookings via signed tokens (no login required):

import { generateBookingToken, verifyBookingToken } from "@thebookingkit/core";
// Generate a token for a booking (e.g., in confirmation email)
const token = generateBookingToken(bookingId, customerEmail, secret);
// Verify and extract the booking ID from a token
const { bookingId, email } = verifyBookingToken(token, secret);

These tokens are used in cancel/reschedule links in emails.