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