What are Bookings?
Bookings represent scheduled appointments between your business and customers. Each booking has a time slot, service, contact information, and optional host or team assignment.
Booking Object
{
"id" : "book_abc123xyz" ,
"confirmation_number" : "BOOK_ABC123XYZ" ,
"status" : "confirmed" ,
"start_at" : "2025-12-03T14:00:00Z" ,
"end_at" : "2025-12-03T15:00:00Z" ,
"service_name" : "Haircut" ,
"organization_name" : "Acme Salon" ,
"location" : {
"type" : "onsite" ,
"value" : "123 Main St, Suite 100"
}
}
Booking Fields
Unique identifier for the booking
Human-readable confirmation number (uppercase version of ID)
Booking status: confirmed, pending, canceled
ISO 8601 timestamp of when the booking starts (UTC)
ISO 8601 timestamp of when the booking ends (UTC)
Name of the booked service
Where the appointment takes place
type: onsite, phone, meet_url, or custom
value: Address, phone number, or meeting link
Booking Status Lifecycle
confirmed
Booking is confirmed and the time slot is reserved. Next states : canceled
canceled
Booking was cancelled by customer or business. Final state - Time slot is released
Available Operations
Two Authentication Methods
The Booking API uses different authentication for different scenarios:
1. API Key Authentication
For your application to create bookings on behalf of customers:
curl -X POST https://api.kordless.ai/api/calendar/v1/public/bookings \
-H "x-kordless-key: your_api_key" \
-H "Content-Type: application/json" \
-d '{...}'
Used for : Creating bookings, fetching availability
For customers to manage their own bookings:
curl "https://api.kordless.ai/api/calendar/v1/public/bookings/confirmation/[email protected] "
Used for : Lookup, cancel, reschedule operations
This keeps your API key secure while allowing customer self-service.
Complete Booking Flow
const API_KEY = process . env . KORDLESS_API_KEY ;
const ORG_SLUG = 'acme-salon' ;
// 1. Get services
const orgResponse = await fetch (
`https://api.kordless.ai/api/calendar/v1/public/org/ ${ ORG_SLUG } ` ,
{ headers: { 'x-kordless-key' : API_KEY } }
);
const { services } = await orgResponse . json ();
// 2. Get available slots
const params = new URLSearchParams ({
org_slug: ORG_SLUG ,
service_slug: services [ 0 ]. slug ,
from: '2025-12-03T00:00:00Z' ,
to: '2025-12-03T23:59:59Z'
});
const slotsResponse = await fetch (
`https://api.kordless.ai/api/calendar/v1/public/availability? ${ params } ` ,
{ headers: { 'x-kordless-key' : API_KEY } }
);
const { slots } = await slotsResponse . json ();
// 3. Create booking
const bookingResponse = await fetch (
'https://api.kordless.ai/api/calendar/v1/public/bookings' ,
{
method: 'POST' ,
headers: {
'x-kordless-key' : API_KEY ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
org_slug: ORG_SLUG ,
service_slug: services [ 0 ]. slug ,
starts_at: slots [ 0 ]. startsAt ,
ends_at: slots [ 0 ]. endsAt ,
timezone: 'America/New_York' ,
contact: {
name: 'Jane Doe' ,
email: '[email protected] '
}
})
}
);
const { booking } = await bookingResponse . json ();
console . log ( `Confirmation: ${ booking . confirmation_number } ` );
Customer Self-Service Flow
// Customer looks up their booking
const lookupResponse = await fetch (
`https://api.kordless.ai/api/calendar/v1/public/bookings/confirmation/ ${ confirmationNumber } ?contact= ${ customerEmail } `
);
const { booking } = await lookupResponse . json ();
// Customer cancels
await fetch (
`https://api.kordless.ai/api/calendar/v1/public/bookings/confirmation/ ${ confirmationNumber } /cancel?contact= ${ customerEmail } ` ,
{ method: 'POST' }
);
Best Practices
Always Check Availability First
Before creating a booking, verify the time slot is available: const { slots } = await getAvailability ({
org_slug: 'acme-salon' ,
service_slug: 'haircut' ,
from: startDate ,
to: endDate
});
if ( slots . length === 0 ) {
throw new Error ( 'No available slots' );
}
// Use the first available slot
await createBooking ({
starts_at: slots [ 0 ]. startsAt ,
ends_at: slots [ 0 ]. endsAt ,
...
});
Prevent duplicate bookings when retrying failed requests: const idempotencyKey = `booking- ${ userId } - ${ Date . now () } ` ;
await fetch ( url , {
headers: {
'Idempotency-Key' : idempotencyKey ,
...
},
...
});
The same key returns the same result for 24 hours.
Handle Conflicts Gracefully
Time slots can be booked by others between checking availability and creating: try {
const booking = await createBooking ( data );
return { success: true , booking };
} catch ( error ) {
if ( error . status === 409 ) {
// Slot was just booked
const newSlots = await getAvailability ({ ... });
return {
success: false ,
message: 'Slot no longer available' ,
alternatives: newSlots
};
}
throw error ;
}
Store Confirmation Numbers
Always store confirmation numbers for customer reference: const { booking } = await createBooking ( data );
// Store in your database
await db . appointments . create ({
confirmationNumber: booking . confirmation_number ,
customerId: customer . id ,
bookedAt: new Date ()
});
// Send to customer
await sendEmail ({
to: customer . email ,
subject: 'Booking Confirmed' ,
body: `Your confirmation number: ${ booking . confirmation_number } `
});
Webhooks Integration
Receive real-time notifications when bookings are created, updated, or cancelled:
{
"event" : "booking.created" ,
"timestamp" : "2025-12-03T10:00:00Z" ,
"data" : {
"booking" : {
"id" : "book_abc123" ,
"confirmation_number" : "BOOK_ABC123" ,
"status" : "confirmed" ,
...
}
}
}
Available Events :
booking.created - New booking created
booking.updated - Booking rescheduled
booking.cancelled - Booking cancelled
Set up Webhooks →
Next Steps