Build scheduling capabilities into your platform so your users can offer appointment booking to their clients. Perfect for marketplaces, directories, and SaaS platforms.
Use Cases
Professional directories (e.g., anwalt.de, doctors, consultants) - Let listed professionals accept bookings
Marketplaces - Enable service providers to manage appointments
SaaS platforms - Add scheduling as a feature for your customers
Agency tools - Manage booking for multiple client accounts
Architecture Overview
Implementation Steps
First, get your API credentials and set up the admin user:
const MEETERGO_API_KEY = process . env . MEETERGO_API_KEY ;
const headers = {
'Authorization' : `Bearer ${ MEETERGO_API_KEY } ` ,
'Content-Type' : 'application/json'
};
When a user signs up on your platform, create a corresponding meetergo user:
async function createPlatformUser ( platformUser ) {
const response = await fetch ( 'https://api.meetergo.com/v4/user' , {
method: 'POST' ,
headers ,
body: JSON . stringify ({
email: platformUser . email ,
givenName: platformUser . firstName ,
familyName: platformUser . lastName ,
timezone: platformUser . timezone || 'Europe/Berlin' ,
// Custom availability for professionals
availability: {
name: 'Business Hours' ,
timezone: platformUser . timezone || 'Europe/Berlin' ,
schedule: [
{ dayOfWeek: 'monday' , intervals: [{ from: '09:00' , to: '18:00' }] },
{ dayOfWeek: 'tuesday' , intervals: [{ from: '09:00' , to: '18:00' }] },
{ dayOfWeek: 'wednesday' , intervals: [{ from: '09:00' , to: '18:00' }] },
{ dayOfWeek: 'thursday' , intervals: [{ from: '09:00' , to: '18:00' }] },
{ dayOfWeek: 'friday' , intervals: [{ from: '09:00' , to: '17:00' }] }
]
},
// Default meeting type
meetingType: {
name: 'Consultation' ,
duration: 30 ,
slug: ` ${ platformUser . slug } -consultation`
}
})
});
const data = await response . json ();
// Store the mapping in your database
await db . users . update ({
where: { id: platformUser . id },
data: {
meetergoUserId: data . userId ,
meetergoMeetingTypeId: data . meetingTypeId ,
bookingUrl: data . bookingUrl
}
});
return data ;
}
3. Embed Booking on Profile Pages
Option A: Embed the booking widget
<!-- On the professional's public profile page -->
< iframe
src = "https://cal.meetergo.com/embed/{companySlug}/{userSlug}/{meetingTypeSlug}"
width = "100%"
height = "700"
frameborder = "0"
></ iframe >
Option B: Build custom UI with API
// Fetch available slots
async function getAvailableSlots ( meetingTypeId , startDate , endDate ) {
const params = new URLSearchParams ({
meetingTypeId ,
start: startDate ,
end: endDate
});
const response = await fetch (
`https://api.meetergo.com/v4/booking-availability? ${ params } ` ,
{ headers }
);
return response . json ();
}
// Display in your UI
const slots = await getAvailableSlots ( meetingTypeId , '2024-01-15' , '2024-01-22' );
// Render custom calendar component
slots . availableSlots . forEach ( slot => {
// Your custom rendering logic
});
4. Handle Bookings
async function createBooking ( meetingTypeId , slot , clientInfo ) {
const response = await fetch ( 'https://api.meetergo.com/v4/booking' , {
method: 'POST' ,
headers ,
body: JSON . stringify ({
meetingTypeId ,
start: slot . start ,
attendee: {
email: clientInfo . email ,
fullname: clientInfo . name ,
phone: clientInfo . phone
}
})
});
const booking = await response . json ();
// Track in your platform's analytics
await trackBooking ( booking );
return booking ;
}
Multi-Tenant Management
async function getPlatformUsers () {
const response = await fetch ( 'https://api.meetergo.com/v4/user' , {
headers
});
return response . json ();
}
Update User Settings
async function updateUserMeetingType ( userId , meetingTypeId , updates ) {
const response = await fetch (
`https://api.meetergo.com/v4/meeting-type/ ${ meetingTypeId } ` ,
{
method: 'PATCH' ,
headers: {
... headers ,
'x-meetergo-api-user-id' : userId
},
body: JSON . stringify ( updates )
}
);
return response . json ();
}
// Example: Update duration and buffer time
await updateUserMeetingType ( userId , meetingTypeId , {
duration: 45 ,
bufferTimeBefore: 15 ,
bufferTimeAfter: 10
});
Bulk Operations
// Create multiple users at once
async function onboardPlatformUsers ( users ) {
const results = await Promise . allSettled (
users . map ( user => createPlatformUser ( user ))
);
const successful = results . filter ( r => r . status === 'fulfilled' );
const failed = results . filter ( r => r . status === 'rejected' );
console . log ( `Created ${ successful . length } users, ${ failed . length } failed` );
return { successful , failed };
}
Webhook Integration
Get notified of all bookings across your platform:
// Register a webhook for all booking events
const webhook = await fetch ( 'https://api.meetergo.com/webhooks' , {
method: 'POST' ,
headers ,
body: JSON . stringify ({
endpoint: 'https://your-platform.com/webhooks/meetergo' ,
description: 'Platform booking notifications' ,
eventTypes: [ 'booking_created' , 'booking_cancelled' , 'booking_rescheduled' ]
})
});
Handle webhooks to update your platform:
app . post ( '/webhooks/meetergo' , async ( req , res ) => {
res . status ( 200 ). send ( 'OK' );
const { event , data } = req . body ;
const hostUserId = data . hosts [ 0 ]?. id ;
// Find the platform user
const platformUser = await db . users . findFirst ({
where: { meetergoUserId: hostUserId }
});
switch ( event ) {
case 'booking_created' :
// Update platform analytics
await db . bookings . create ({
data: {
platformUserId: platformUser . id ,
clientEmail: data . attendees [ 0 ]. email ,
scheduledAt: data . start ,
meetergoBookingId: data . id
}
});
// Send platform-specific notification
await sendPlatformNotification ( platformUser , 'new_booking' , data );
break ;
case 'booking_cancelled' :
await db . bookings . update ({
where: { meetergoBookingId: data . id },
data: { status: 'cancelled' }
});
break ;
}
});
Customization Options
Custom Branding per User
// Update personal page branding
await fetch ( `https://api.meetergo.com/v4/personal-page` , {
method: 'PATCH' ,
headers: {
... headers ,
'x-meetergo-api-user-id' : userId
},
body: JSON . stringify ({
headerTitle: 'Book a consultation' ,
headerSubtitle: 'Select a time that works for you' ,
primaryColor: '#0066cc'
})
});
Meeting Type Templates
Create templates that all platform users can use:
// Create a template
const template = await fetch ( 'https://api.meetergo.com/v4/meeting-type-template/create' , {
method: 'POST' ,
headers ,
body: JSON . stringify ({
name: 'Initial Consultation' ,
duration: 30 ,
description: 'Free initial consultation to discuss your needs'
})
});
// Assign template to a user (creates a meeting type from template)
await fetch ( `https://api.meetergo.com/v4/meeting-type-template/assign/ ${ templateId } ` , {
method: 'POST' ,
headers ,
body: JSON . stringify ({
userId: platformUserId
})
});
Best Practices
Store user mappings - Keep meetergo user IDs in your database for easy lookup
Use webhooks - Don’t poll for booking changes, use webhooks instead
Handle errors gracefully - API calls can fail; implement retry logic
Respect rate limits - Batch operations where possible
Secure your webhook endpoint - Validate incoming webhook requests
API key security - Never expose your API key in client-side code. All API calls should go through your backend.
Example: Professional Directory
Complete example for a lawyer directory:
// lawyer-directory.js
class LawyerDirectory {
constructor ( apiKey ) {
this . apiKey = apiKey ;
this . headers = {
'Authorization' : `Bearer ${ apiKey } ` ,
'Content-Type' : 'application/json'
};
}
// When a lawyer joins the directory
async onboardLawyer ( lawyer ) {
// Create meetergo user
const meetergoUser = await this . createMeetergoUser ({
email: lawyer . email ,
firstName: lawyer . firstName ,
lastName: lawyer . lastName ,
specialty: lawyer . specialty
});
// Create specialized meeting types
await this . createMeetingTypes ( meetergoUser . userId , lawyer . specialty );
return meetergoUser ;
}
async createMeetergoUser ( lawyer ) {
const response = await fetch ( 'https://api.meetergo.com/v4/user' , {
method: 'POST' ,
headers: this . headers ,
body: JSON . stringify ({
email: lawyer . email ,
givenName: lawyer . firstName ,
familyName: lawyer . lastName ,
timezone: 'Europe/Berlin' ,
meetingType: {
name: 'Erstberatung' ,
duration: 30 ,
slug: ` ${ lawyer . firstName . toLowerCase () } - ${ lawyer . lastName . toLowerCase () } -erstberatung`
}
})
});
return response . json ();
}
async createMeetingTypes ( userId , specialty ) {
const meetingTypes = [
{ name: 'Telefonische Beratung' , duration: 15 },
{ name: 'Ausführliche Beratung' , duration: 60 },
{ name: 'Mandatsgespräch' , duration: 45 }
];
for ( const mt of meetingTypes ) {
await fetch ( 'https://api.meetergo.com/v4/meeting-type' , {
method: 'POST' ,
headers: {
... this . headers ,
'x-meetergo-api-user-id' : userId
},
body: JSON . stringify ( mt )
});
}
}
// Render booking widget on lawyer profile
getEmbedCode ( lawyer ) {
return `
<iframe
src=" ${ lawyer . bookingUrl } ?embed=true"
width="100%"
height="700"
frameborder="0"
title="Termin buchen bei ${ lawyer . firstName } ${ lawyer . lastName } "
></iframe>
` ;
}
}
Next Steps
Embed Booking Widget Learn more about embedding options
Custom Booking Flow Build a fully custom booking experience
Webhooks Set up real-time notifications
Meeting Types Configure meeting types for your users