Overview
This guide provides practical examples for common use cases when integrating with the BookingShake API.
Use Case 1: Simple Single Event
Create a basic event with minimal required information.
Scenario: A visitor fills out a simple contact form on your website to request an event.
curl -X POST 'https://api.bookingshake.io/api/events/create' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"bookings": [
{
"date": "20-06-2025",
"startTime": "18:00",
"pax": "25",
"event_type": "Birthday Party"
}
],
"contact": {
"first_name": "Sarah",
"last_name": "Miller",
"email": "[email protected] ",
"phone": "+33612345678"
}
}'
Use Case 2: Group Bookings (Multiple Events)
Create multiple related events in a single request. Perfect for multi-day conferences or workshops.
Scenario: A client wants to book a conference room for a 3-day training session.
curl -X POST 'https://api.bookingshake.io/api/events/create' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"bookings": [
{
"date": "10-04-2025",
"startTime": "09:00",
"endTime": "17:00",
"pax": "40",
"space_id": "space_training_room",
"event_type": "Training Session - Day 1"
},
{
"date": "11-04-2025",
"startTime": "09:00",
"endTime": "17:00",
"pax": "40",
"space_id": "space_training_room",
"event_type": "Training Session - Day 2"
},
{
"date": "12-04-2025",
"startTime": "09:00",
"endTime": "17:00",
"pax": "40",
"space_id": "space_training_room",
"event_type": "Training Session - Day 3"
}
],
"contact": {
"first_name": "Michael",
"last_name": "Brown",
"email": "[email protected] ",
"phone": "+33698765432",
"position": "Training Manager"
},
"source_slug": "direct"
}'
All events created in a single request are automatically grouped together in BookingShake, making it easy to manage multi-day bookings.
Use Case 3: Event with Draft Quotation (Products)
Create an event and generate a draft quotation with products/services.
Scenario: A corporate client requests a conference package with catering and AV equipment.
Important: Pricing Format Product prices and VAT must be provided in specific formats:
Prices (price_without_tax) : In cents/centimes , not euros/dollars
Example: €1,500.00 = 150000 cents
Example: €35.00 = 3500 cents
VAT (vat) : In basis points (1/100th of a percent), not percentages
Example: 20% VAT = 2000 basis points
Example: 10% VAT = 1000 basis points
Range: 0 to 10000 (0% to 100%)
curl -X POST 'https://api.bookingshake.io/api/events/create' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"bookings": [
{
"date": "15-05-2025",
"startTime": "10:00",
"endTime": "16:00",
"pax": "80",
"space_id": "space_grand_ballroom",
"event_type": "Corporate Conference",
"products": [
{
"title": "Full Day Conference Package",
"quantity": 1,
"price_without_tax": 150000,
"vat": 2000
},
{
"title": "Lunch Buffet per Person",
"quantity": 80,
"price_without_tax": 3500,
"vat": 1000
},
{
"title": "AV Equipment Package",
"quantity": 1,
"price_without_tax": 45000,
"vat": 2000
},
{
"title": "Coffee Break (Morning & Afternoon)",
"quantity": 2,
"price_without_tax": 800,
"vat": 1000
}
],
"comments": "Projector needed, dietary requirements to follow"
}
],
"contact": {
"first_name": "Jennifer",
"last_name": "Davis",
"email": "[email protected] ",
"phone": "+33687654321",
"position": "Events Coordinator"
},
"company": {
"name": "TechCorp International",
"siret": "12345678901234",
"address_line_1": "50 Innovation Boulevard",
"postal_code": "75008",
"city": "Paris",
"country": "France"
},
"source_slug": "direct"
}'
Important: Prices are in cents (e.g., €150.00 = 15000) and VAT is multiplied by 100 (e.g., 20% = 2000).
Use Case 4: Dynamic Resource Selection
Retrieve available resources before creating an event to populate dropdowns or validate selections.
Scenario: Build a booking form that shows available spaces and sources dynamically.
// Complete workflow: Fetch resources → Display form → Create event
const BookingFormHandler = {
async initialize () {
// Fetch available resources
const [ sources , spaces , statuses ] = await Promise . all ([
this . fetchSources (),
this . fetchSpaces (),
this . fetchStatuses ()
]);
// Populate form dropdowns
this . populateDropdown ( 'source-select' , sources );
this . populateDropdown ( 'space-select' , spaces );
this . populateDropdown ( 'status-select' , statuses );
},
async fetchSources () {
const response = await fetch ( 'https://api.bookingshake.io/api/sources' , {
headers: {
'Authorization' : `Bearer ${ process . env . BOOKINGSHAKE_API_KEY } `
}
});
return await response . json ();
},
async fetchSpaces () {
const response = await fetch ( 'https://api.bookingshake.io/api/spaces' , {
headers: {
'Authorization' : `Bearer ${ process . env . BOOKINGSHAKE_API_KEY } `
}
});
return await response . json ();
},
async fetchStatuses () {
const response = await fetch ( 'https://api.bookingshake.io/api/status' , {
headers: {
'Authorization' : `Bearer ${ process . env . BOOKINGSHAKE_API_KEY } `
}
});
return await response . json ();
},
populateDropdown ( selectId , items ) {
const select = document . getElementById ( selectId );
items . forEach ( item => {
const option = document . createElement ( 'option' );
option . value = item . value ;
option . textContent = item . label ;
select . appendChild ( option );
});
},
async submitBooking ( formData ) {
const response = await fetch ( 'https://api.bookingshake.io/api/events/create' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ process . env . BOOKINGSHAKE_API_KEY } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
bookings: [{
date: formData . date ,
startTime: formData . startTime ,
endTime: formData . endTime ,
pax: formData . pax ,
space_id: formData . spaceId ,
event_type: formData . eventType
}],
contact: {
firstname: formData . firstname ,
lastname: formData . lastname ,
email: formData . email ,
phone_number: formData . phone
},
source_slug: formData . sourceSlug
})
});
return await response . json ();
}
};
// Initialize when page loads
document . addEventListener ( 'DOMContentLoaded' , () => {
BookingFormHandler . initialize ();
});
Link events to existing contacts instead of creating new ones.
Scenario: A returning customer makes a new booking.
curl -X POST 'https://api.bookingshake.io/api/events/create' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"bookings": [
{
"date": "25-07-2025",
"startTime": "19:00",
"pax": "30",
"event_type": "Anniversary Dinner"
}
],
"contact": {
"contact_id": "contact_xyz789"
}
}'
When contact_id is provided, other contact fields (firstname, lastname, email) are ignored, and the existing contact is used.
Automatic deduplication: Even when creating a new contact (without contact_id), the API automatically checks if a contact with the same email already exists for your venue or venue group. If found, it reuses the existing contact instead of creating a duplicate.
Use Case 6: Event with Custom Fields
Create events with custom field values for contacts, companies, and bookings.
Scenario: Your venue has configured custom fields to capture additional information like budget range, event theme, and company size. You need to pass these values when creating events.
Finding your custom fields: Use the GET /fields endpoint to retrieve all available custom fields for your venue. Custom fields have isCustom: true and are identified by their code property (format: custom_XXXXXXXXXXX). The collection property indicates where to use the field:
clients → use in contact.custom_fields
accounts → use in company.custom_fields
reservations → use in each booking.custom_fields
curl -X POST 'https://api.bookingshake.io/api/events/create' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"bookings": [
{
"date": "15-06-2025",
"startTime": "18:00",
"endTime": "23:00",
"pax": "150",
"event_type": "Gala Dinner",
"custom_fields": {
"custom_a1b2c3d4e5": "20000-50000",
"custom_f6g7h8i9j0": "Black Tie"
}
}
],
"contact": {
"first_name": "Marie",
"last_name": "Dupont",
"email": "[email protected] ",
"phone": "+33612345678",
"custom_fields": {
"custom_k1l2m3n4o5": "fr",
"custom_p6q7r8s9t0": "referral"
}
},
"company": {
"name": "Luxury Events SA",
"address_line_1": "10 Avenue des Champs-Élysées",
"postal_code": "75008",
"city": "Paris",
"country": "France",
"custom_fields": {
"custom_u1v2w3x4y5": "100-500",
"custom_z6a7b8c9d0": "premium"
}
},
"source_slug": "website"
}'
Required custom fields: If a custom field has isRequiredInBO: true, you must provide a value for it. The API will return an error like missing required custom field "Budget Range" for contact if a required field is missing.
Custom field values are stored at the root level of each entity (contact, company, or booking) in BookingShake, alongside standard fields. They can be viewed and edited in the back office.
Use Case 7: Complete Integration Workflow
A full example showing error handling, validation, and best practices.
class BookingShakeAPI {
constructor ( apiKey ) {
this . apiKey = apiKey ;
this . baseURL = 'https://api.bookingshake.io/api' ;
}
async request ( endpoint , options = {}) {
const url = ` ${ this . baseURL }${ endpoint } ` ;
const headers = {
'Authorization' : `Bearer ${ this . apiKey } ` ,
'Content-Type' : 'application/json' ,
... options . headers
};
try {
const response = await fetch ( url , {
... options ,
headers
});
const data = await response . json ();
if ( ! response . ok ) {
throw new Error ( `API Error: ${ data . message } ` );
}
return data ;
} catch ( error ) {
console . error ( 'BookingShake API request failed:' , error );
throw error ;
}
}
// Validate date format (DD-MM-YYYY)
validateDate ( dateString ) {
const regex = / ^ \d {2} - \d {2} - \d {4} $ / ;
if ( ! regex . test ( dateString )) {
throw new Error ( 'Invalid date format. Use DD-MM-YYYY' );
}
return true ;
}
// Validate time format (HH:mm)
validateTime ( timeString ) {
const regex = / ^ \d {2} : \d {2} $ / ;
if ( ! regex . test ( timeString )) {
throw new Error ( 'Invalid time format. Use HH:mm' );
}
return true ;
}
async getSources () {
return this . request ( '/sources' );
}
async getSpaces () {
return this . request ( '/spaces' );
}
async getStatuses () {
return this . request ( '/status' );
}
async getFields () {
return this . request ( '/fields' );
}
async createEvent ( bookingData ) {
// Validate input
bookingData . bookings . forEach ( booking => {
this . validateDate ( booking . date );
this . validateTime ( booking . startTime );
if ( booking . endTime ) {
this . validateTime ( booking . endTime );
}
if ( ! booking . pax ) {
throw new Error ( 'Number of guests (pax) is required' );
}
});
if ( ! bookingData . contact ) {
throw new Error ( 'Contact information is required' );
}
if ( ! bookingData . contact . contact_id ) {
if ( ! bookingData . contact . firstname || ! bookingData . contact . lastname || ! bookingData . contact . email ) {
throw new Error ( 'Contact must have firstname, lastname, and email' );
}
}
// Make API request
return this . request ( '/events/create' , {
method: 'POST' ,
body: JSON . stringify ( bookingData )
});
}
}
// Usage example
const api = new BookingShakeAPI ( process . env . BOOKINGSHAKE_API_KEY );
async function processBooking ( formData ) {
try {
// Get available resources
const spaces = await api . getSpaces ();
console . log ( 'Available spaces:' , spaces );
// Create the event
const result = await api . createEvent ({
bookings: [{
date: formData . date ,
startTime: formData . startTime ,
endTime: formData . endTime ,
pax: formData . guestCount ,
space_id: formData . selectedSpace ,
event_type: formData . eventType
}],
contact: {
firstname: formData . firstname ,
lastname: formData . lastname ,
email: formData . email ,
phone_number: formData . phone
},
source_slug: 'website'
});
console . log ( 'Event created successfully:' , result );
return result ;
} catch ( error ) {
console . error ( 'Booking failed:' , error . message );
throw error ;
}
}
Best Practices
Validate Before Sending Always validate date/time formats and required fields before making API calls to provide better user feedback.
Handle Errors Gracefully Implement proper error handling and provide clear error messages to users.
Use Environment Variables Store API keys securely in environment variables, never in your source code.
Fetch Resources Dynamically Retrieve sources, spaces, and statuses via API instead of hardcoding them.
Next Steps