Appointments API
Manage appointments throughout their full lifecycle — from booking to completion.
Overview
Appointments are the core of GlowScript. Each appointment connects a client to a service, provider, and time slot.
Appointment Status Flow
scheduled → confirmed → checked_in → in_progress → completed
↓ ↓ ↓ ↓
cancelled cancelled no_show cancelledData Model
Appointment Object
| Field | Type | Description |
|---|---|---|
id | UUID | Unique identifier |
medspa_id | UUID | Organization ID |
client_id | UUID | Client receiving service |
service_id | UUID | Service being performed |
provider_id | UUID | Provider performing service |
room_id | UUID | Treatment room (optional) |
equipment_id | UUID | Equipment required (optional) |
scheduled_at | DateTime | Appointment start time |
duration_minutes | Integer | Length of appointment |
status | Enum | Current status |
notes | String | Client-visible notes |
internal_notes | String | Staff-only notes |
source | String | Booking source (manual, online, shopify) |
created_at | DateTime | When created |
updated_at | DateTime | Last modified |
Status Values
| Status | Description |
|---|---|
scheduled | Newly booked, awaiting confirmation |
confirmed | Client confirmed attendance |
checked_in | Client has arrived |
in_progress | Service is being performed |
completed | Service finished successfully |
cancelled | Appointment was cancelled |
no_show | Client didn't show up |
Actions
Get Appointments
Retrieve appointments with optional filters.
import { getAppointments } from '@/lib/actions/appointments'
const result = await getAppointments({
startDate: '2026-02-01',
endDate: '2026-02-28',
providerId: 'uuid', // optional
clientId: 'uuid', // optional
status: ['scheduled', 'confirmed'], // optional
})
if (result.success) {
console.log(result.data)
}Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
startDate | String | Yes | Start of date range (YYYY-MM-DD) |
endDate | String | Yes | End of date range (YYYY-MM-DD) |
providerId | UUID | No | Filter by provider |
clientId | UUID | No | Filter by client |
status | String[] | No | Filter by status(es) |
Response:
{
"success": true,
"data": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"client": {
"id": "...",
"first_name": "Jane",
"last_name": "Smith"
},
"service": {
"id": "...",
"name": "Botox Treatment",
"duration_minutes": 30
},
"provider": {
"id": "...",
"full_name": "Dr. Johnson"
},
"scheduled_at": "2026-02-15T10:00:00Z",
"duration_minutes": 30,
"status": "confirmed"
}
]
}Get Single Appointment
Retrieve detailed information about a specific appointment.
import { getAppointment } from '@/lib/actions/appointments'
const result = await getAppointment('appointment-uuid')Response includes:
- Full client details
- Service information
- Provider details
- Room and equipment (if assigned)
- Associated consent forms
- Treatment record (if completed)
Create Appointment
Book a new appointment.
import { createAppointment } from '@/lib/actions/appointments'
const result = await createAppointment({
client_id: 'client-uuid',
service_id: 'service-uuid',
provider_id: 'provider-uuid',
scheduled_at: '2026-02-15T10:00:00Z',
duration_minutes: 60,
room_id: 'room-uuid', // optional
equipment_id: 'equip-uuid', // optional
notes: 'First visit', // optional
source: 'manual' // optional
})Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
client_id | UUID | Yes | Client ID |
service_id | UUID | Yes | Service ID |
provider_id | UUID | Yes | Provider ID |
scheduled_at | DateTime | Yes | Start time (ISO 8601) |
duration_minutes | Integer | No | Override service duration |
room_id | UUID | No | Assign treatment room |
equipment_id | UUID | No | Assign equipment |
notes | String | No | Client-visible notes |
internal_notes | String | No | Staff-only notes |
source | String | No | Booking source |
Validations:
- Provider must be available at requested time
- Room must be available (if specified)
- Equipment must be available (if specified)
- Provider must be certified for the service
Update Appointment
Modify an existing appointment.
import { updateAppointment } from '@/lib/actions/appointments'
const result = await updateAppointment('appointment-uuid', {
scheduled_at: '2026-02-15T14:00:00Z', // reschedule
provider_id: 'new-provider-uuid', // change provider
notes: 'Updated notes'
})Update Appointment Status
Change the status of an appointment.
import { updateAppointmentStatus } from '@/lib/actions/appointments'
// Check in a client
const result = await updateAppointmentStatus('appointment-uuid', 'checked_in')
// Start the service
await updateAppointmentStatus('appointment-uuid', 'in_progress')
// Complete the appointment
await updateAppointmentStatus('appointment-uuid', 'completed')Cancel Appointment
Cancel an appointment with an optional reason.
import { cancelAppointment } from '@/lib/actions/appointments'
const result = await cancelAppointment('appointment-uuid', 'Client requested reschedule')Effects:
- Sets status to
cancelled - Records cancellation timestamp
- Stores cancellation reason
- Triggers cancellation webhook (if configured)
Mark No-Show
Mark a client as a no-show.
import { markNoShow } from '@/lib/actions/appointments'
const result = await markNoShow('appointment-uuid')Related Actions
Check Provider Availability
Before booking, verify the provider is available.
import { checkProviderAvailability } from '@/lib/actions/scheduling'
const result = await checkProviderAvailability(
'provider-uuid',
'2026-02-15T10:00:00Z', // start
'2026-02-15T11:00:00Z', // end
)
if (result.isAvailable) {
// Safe to book
}Get Available Slots
Get all available time slots for a provider on a date.
import { getAvailableSlots } from '@/lib/actions/scheduling'
const result = await getAvailableSlots(
'provider-uuid',
'2026-02-15', // date
60, // duration in minutes
15 // slot interval (optional, default 15)
)
// Returns array of { slot_start, slot_end }Webhooks
Appointment events that trigger webhooks:
| Event | Description |
|---|---|
appointment.created | New appointment booked |
appointment.updated | Appointment modified |
appointment.status_changed | Status transition |
appointment.cancelled | Appointment cancelled |
appointment.completed | Service completed |
Best Practices
- Always check availability before creating appointments
- Use transactions for complex booking flows
- Handle conflicts gracefully — race conditions can occur
- Set appropriate reminders via SMS/email integrations
- Track source for marketing attribution
Error Codes
| Code | Message | Resolution |
|---|---|---|
PROVIDER_UNAVAILABLE | Provider is not available at this time | Choose different time/provider |
ROOM_UNAVAILABLE | Room is already booked | Choose different room/time |
SERVICE_NOT_FOUND | Service does not exist | Verify service ID |
CLIENT_NOT_FOUND | Client does not exist | Verify client ID |
INVALID_STATUS_TRANSITION | Cannot change status this way | Follow status flow |