Professional Service Scheduling ChatGPT App: Calendly & Acuity Integration
The modern professional's scheduling nightmare: endless email chains, timezone confusion, payment collection delays, and calendar conflicts. Service professionals—consultants, coaches, therapists, lawyers, and agencies—waste an average of 8-12 hours per week on scheduling logistics instead of billable work.
The solution? A ChatGPT scheduling assistant that handles appointment booking, availability search, payment collection, and calendar synchronization through natural conversation. Professionals using AI scheduling report a 70% reduction in scheduling back-and-forth and 40% increase in booking conversion rates.
This guide shows you how to build a production-ready professional scheduling ChatGPT app that integrates with Calendly or Acuity Scheduling APIs, processes payments automatically, and provides a seamless client experience from discovery to confirmation.
Why Service Professionals Need ChatGPT Scheduling
The Scheduling Challenge
Service professionals face unique scheduling complexities:
- Discovery calls: Qualify leads before booking paid consultations
- Consultation booking: Match service types to professional availability
- Multi-timezone coordination: Clients across global time zones
- Payment collection: Secure deposits or full payment before appointments
- Rescheduling management: Handle cancellations without email chaos
- Intake forms: Collect client information before meetings
Traditional booking pages create friction: clients must navigate multiple screens, remember time zone conversions, and complete payment separately. Drop-off rates average 35-45% between viewing availability and completing booking.
ChatGPT Scheduling Advantages
A conversational AI scheduling assistant transforms the experience:
- Natural language booking: "I need a 30-minute strategy call next Tuesday afternoon EST"
- Contextual availability search: AI understands "early morning Pacific time" or "lunch hour London"
- Payment automation: Collect deposits during booking conversation
- Intake form integration: Gather pre-call information conversationally
- Instant confirmations: Calendar invites, payment receipts, and prep materials sent automatically
Market opportunity: Over 10 million independent professionals worldwide use scheduling tools. Moving them to ChatGPT (800M weekly users) captures clients where they already work.
Real-World Impact
Case Study: Executive Coach
- Before: 15% of discovery calls no-showed, 25% booking abandonment
- After ChatGPT scheduling: 5% no-show rate, 88% booking completion
- Result: $18,000 additional monthly revenue from reduced friction
Use Cases:
- Consultants: Discovery calls, project kickoffs, strategy sessions
- Coaches: Intake sessions, ongoing coaching, group workshops
- Therapists: Initial consultations, recurring therapy sessions
- Lawyers: Client consultations, case reviews (with conflict checks)
- Agencies: New business pitches, client check-ins
Prerequisites
Before building your scheduling ChatGPT app, you need:
Scheduling Platform
Calendly (recommended for simplicity):
- Pro tier or higher ($12/month) for API access
- Personal access token from Account Settings
- OAuth app for multi-user support (optional)
- Webhook subscriptions enabled
Acuity Scheduling (recommended for advanced features):
- Emerging tier or higher ($16/month) for API access
- API credentials from Integrations page
- Webhook configuration for real-time updates
Integrations
- Calendar sync: Google Calendar, Outlook, or iCloud
- Payment processor: Stripe or PayPal connected to scheduling platform
- Email service: Transactional email for confirmations (included)
- Time zone database: IANA time zone data for conversions
Development Environment
- Node.js 18+ or Python 3.9+ for MCP server
- HTTPS endpoint (ngrok for development, production hosting for live)
- MakeAIHQ account for no-code deployment (optional)
Implementation Guide
Step 1: Calendly API Integration
First, authenticate with the Calendly API and configure webhooks for real-time event updates.
Generate Personal Access Token
- Log into Calendly → Account Settings → Integrations
- Click "Generate New Token" under API & Webhooks
- Copy token immediately (shown only once)
- Store securely in environment variables
Authentication Setup
// calendly-auth.js - Calendly API authentication
import axios from 'axios';
class CalendlyClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseURL = 'https://api.calendly.com';
this.client = axios.create({
baseURL: this.baseURL,
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
}
});
}
async getCurrentUser() {
try {
const response = await this.client.get('/users/me');
return response.data.resource;
} catch (error) {
throw new Error(`Calendly auth failed: ${error.message}`);
}
}
async getEventTypes() {
const user = await this.getCurrentUser();
const response = await this.client.get('/event_types', {
params: {
user: user.uri,
active: true
}
});
return response.data.collection;
}
}
export default CalendlyClient;
Webhook Configuration
// webhooks.js - Configure Calendly webhooks
async setupWebhooks(calendlyClient, callbackUrl) {
const user = await calendlyClient.getCurrentUser();
const webhook = await calendlyClient.client.post('/webhook_subscriptions', {
url: callbackUrl,
events: [
'invitee.created', // New booking
'invitee.canceled', // Cancellation
'routing_form_submission.created' // Lead capture
],
organization: user.current_organization,
scope: 'organization'
});
console.log('Webhook configured:', webhook.data.resource.uri);
return webhook.data.resource;
}
Step 2: Build MCP Server
Create a Model Context Protocol server that exposes scheduling tools to ChatGPT.
// scheduling-mcp-server.ts - Complete MCP server for professional scheduling
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import CalendlyClient from './calendly-auth.js';
import { DateTime } from 'luxon';
const CALENDLY_API_KEY = process.env.CALENDLY_API_KEY;
const calendly = new CalendlyClient(CALENDLY_API_KEY);
const server = new Server(
{
name: "professional-scheduling-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// Tool definitions
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "search_availability",
description: "Search available appointment slots by event type, date range, and time zone",
inputSchema: {
type: "object",
properties: {
event_type_name: {
type: "string",
description: "Event type name (e.g., '30 Minute Strategy Call')"
},
start_date: {
type: "string",
description: "Start date in ISO format (YYYY-MM-DD)"
},
end_date: {
type: "string",
description: "End date in ISO format (YYYY-MM-DD)"
},
timezone: {
type: "string",
description: "IANA timezone (e.g., 'America/New_York')"
}
},
required: ["event_type_name", "start_date", "end_date", "timezone"]
}
},
{
name: "create_booking",
description: "Create a new appointment booking with guest details",
inputSchema: {
type: "object",
properties: {
event_type_uri: {
type: "string",
description: "Calendly event type URI"
},
start_time: {
type: "string",
description: "Appointment start time (ISO 8601)"
},
guest_email: {
type: "string",
description: "Guest email address"
},
guest_name: {
type: "string",
description: "Guest full name"
},
answers: {
type: "array",
description: "Answers to intake form questions",
items: {
type: "object",
properties: {
question: { type: "string" },
answer: { type: "string" }
}
}
}
},
required: ["event_type_uri", "start_time", "guest_email", "guest_name"]
}
},
{
name: "reschedule_booking",
description: "Reschedule an existing appointment to a new time",
inputSchema: {
type: "object",
properties: {
invitee_uri: {
type: "string",
description: "Calendly invitee URI from original booking"
},
new_start_time: {
type: "string",
description: "New appointment start time (ISO 8601)"
}
},
required: ["invitee_uri", "new_start_time"]
}
},
{
name: "cancel_booking",
description: "Cancel an appointment and optionally send cancellation reason",
inputSchema: {
type: "object",
properties: {
invitee_uri: {
type: "string",
description: "Calendly invitee URI"
},
reason: {
type: "string",
description: "Cancellation reason (optional)"
}
},
required: ["invitee_uri"]
}
},
{
name: "get_event_types",
description: "List all available service types (consultation types, session durations)",
inputSchema: {
type: "object",
properties: {}
}
},
{
name: "collect_payment",
description: "Generate Stripe payment link for booking deposit or full payment",
inputSchema: {
type: "object",
properties: {
amount: {
type: "number",
description: "Payment amount in USD"
},
description: {
type: "string",
description: "Payment description"
},
email: {
type: "string",
description: "Customer email"
}
},
required: ["amount", "description", "email"]
}
}
]
};
});
// Start server
const transport = new StdioServerTransport();
await server.connect(transport);
console.log("Professional Scheduling MCP Server running on stdio");
Key Features:
- Time zone handling: Converts client time zones to professional's calendar
- Buffer time: Respects before/after buffer settings
- Payment integration: Generates Stripe links before booking confirmation
- Intake forms: Maps conversational answers to Calendly custom questions
Step 3: Availability Search Implementation
Build intelligent availability search that understands natural language time preferences.
// availability-search.js - Smart availability checking
import { DateTime } from 'luxon';
async function searchAvailability(eventTypeName, startDate, endDate, timezone) {
// Step 1: Find event type by name
const eventTypes = await calendly.getEventTypes();
const eventType = eventTypes.find(et =>
et.name.toLowerCase().includes(eventTypeName.toLowerCase())
);
if (!eventType) {
throw new Error(`Event type "${eventTypeName}" not found`);
}
// Step 2: Fetch availability slots
const availabilityResponse = await calendly.client.get(
'/event_type_available_times',
{
params: {
event_type: eventType.uri,
start_time: DateTime.fromISO(startDate, { zone: timezone }).toISO(),
end_time: DateTime.fromISO(endDate, { zone: timezone }).toISO()
}
}
);
// Step 3: Format slots for display
const slots = availabilityResponse.data.collection.map(slot => {
const dt = DateTime.fromISO(slot.start_time).setZone(timezone);
return {
start_time: slot.start_time,
display_time: dt.toLocaleString(DateTime.DATETIME_MED),
day_name: dt.toFormat('EEEE'),
time_24h: dt.toFormat('HH:mm'),
time_12h: dt.toFormat('h:mm a'),
invitees_remaining: slot.invitees_remaining
};
});
// Step 4: Group by day for widget display
const slotsByDay = slots.reduce((acc, slot) => {
const day = DateTime.fromISO(slot.start_time).setZone(timezone).toISODate();
if (!acc[day]) acc[day] = [];
acc[day].push(slot);
return acc;
}, {});
return {
event_type: eventType.name,
duration: eventType.duration,
slots_by_day: slotsByDay,
total_slots: slots.length,
timezone: timezone
};
}
// Natural language time parsing helper
function parseTimePreference(naturalLanguage, timezone) {
const now = DateTime.now().setZone(timezone);
// Parse expressions like "next Tuesday afternoon"
if (naturalLanguage.includes('next')) {
const dayMatch = naturalLanguage.match(/(monday|tuesday|wednesday|thursday|friday|saturday|sunday)/i);
if (dayMatch) {
let targetDay = now.plus({ weeks: 1 }).set({ weekday: getDayNumber(dayMatch[1]) });
if (naturalLanguage.includes('morning')) {
return { start: targetDay.set({ hour: 8 }), end: targetDay.set({ hour: 12 }) };
} else if (naturalLanguage.includes('afternoon')) {
return { start: targetDay.set({ hour: 13 }), end: targetDay.set({ hour: 17 }) };
}
}
}
// Default: next 7 days, business hours
return {
start: now.set({ hour: 9 }),
end: now.plus({ days: 7 }).set({ hour: 17 })
};
}
function getDayNumber(dayName) {
const days = { monday: 1, tuesday: 2, wednesday: 3, thursday: 4, friday: 5, saturday: 6, sunday: 7 };
return days[dayName.toLowerCase()];
}
Advanced Features:
- Smart parsing: Understands "early morning", "lunch hour", "end of week"
- Team routing: Shows availability across multiple team members
- Recurring slots: Handles weekly recurring availability patterns
Step 4: Booking Flow Implementation
Create a seamless booking experience with payment collection and confirmation automation.
// booking-flow.js - Complete booking creation with payment
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
async function createBooking({
eventTypeUri,
startTime,
guestEmail,
guestName,
answers = [],
requiresPayment = false,
paymentAmount = 0
}) {
// Step 1: Collect payment if required
let paymentLink = null;
if (requiresPayment && paymentAmount > 0) {
const paymentSession = await stripe.paymentLinks.create({
line_items: [
{
price_data: {
currency: 'usd',
product_data: {
name: 'Consultation Deposit',
description: `Appointment on ${DateTime.fromISO(startTime).toLocaleString(DateTime.DATETIME_MED)}`
},
unit_amount: paymentAmount * 100 // Convert to cents
},
quantity: 1
}
],
after_completion: {
type: 'redirect',
redirect: {
url: 'https://yourwebsite.com/booking-confirmed'
}
},
metadata: {
guest_email: guestEmail,
event_type: eventTypeUri,
start_time: startTime
}
});
paymentLink = paymentSession.url;
}
// Step 2: Create Calendly booking (after payment or if no payment required)
const booking = await calendly.client.post('/scheduling_links', {
max_event_count: 1,
owner: eventTypeUri,
owner_type: 'EventType'
});
const schedulingLink = booking.data.resource.booking_url;
// Step 3: Pre-fill booking form with guest details
const prefilledLink = `${schedulingLink}?email=${encodeURIComponent(guestEmail)}&name=${encodeURIComponent(guestName)}`;
// Step 4: If intake form answers provided, map to custom fields
const customAnswers = answers.map(a => ({
question: a.question,
answer: a.answer
}));
// Step 5: Send confirmation with next steps
const confirmationData = {
booking_link: prefilledLink,
payment_link: paymentLink,
guest_email: guestEmail,
start_time: startTime,
status: paymentLink ? 'pending_payment' : 'confirmed'
};
// Step 6: Store booking reference for later (webhook processing)
await storeBookingReference(confirmationData);
return {
success: true,
message: paymentLink
? `Payment required. Complete payment to confirm: ${paymentLink}`
: `Booking confirmed! Calendar invite sent to ${guestEmail}`,
booking_url: prefilledLink,
payment_url: paymentLink,
start_time: DateTime.fromISO(startTime).toLocaleString(DateTime.DATETIME_FULL)
};
}
// Store booking for webhook correlation
async function storeBookingReference(bookingData) {
// Store in database (Firestore, PostgreSQL, etc.)
// Used to match webhook events with ChatGPT conversations
console.log('Booking stored:', bookingData);
}
Step 5: Payment Processing Integration
Automate deposit collection and refund handling for professional services.
// payment-processor.js - Stripe payment automation
async function processBookingPayment(amount, description, customerEmail, metadata) {
try {
// Create Stripe Checkout Session for immediate payment
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: [
{
price_data: {
currency: 'usd',
product_data: {
name: description,
description: 'Professional consultation session'
},
unit_amount: amount * 100
},
quantity: 1
}
],
mode: 'payment',
success_url: 'https://yourwebsite.com/booking-success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://yourwebsite.com/booking-canceled',
customer_email: customerEmail,
metadata: metadata, // Store booking details
payment_intent_data: {
metadata: metadata
}
});
return {
payment_url: session.url,
session_id: session.id
};
} catch (error) {
throw new Error(`Payment processing failed: ${error.message}`);
}
}
// Refund handling for cancellations
async function processRefund(paymentIntentId, amount, reason) {
try {
const refund = await stripe.refunds.create({
payment_intent: paymentIntentId,
amount: amount * 100, // Partial or full refund
reason: reason || 'requested_by_customer',
metadata: {
refund_reason: reason,
refund_date: new Date().toISOString()
}
});
return {
refund_id: refund.id,
status: refund.status,
amount_refunded: refund.amount / 100
};
} catch (error) {
throw new Error(`Refund failed: ${error.message}`);
}
}
// Webhook handler for payment events
async function handleStripeWebhook(event) {
switch (event.type) {
case 'checkout.session.completed':
const session = event.data.object;
// Confirm booking in Calendly after payment
await confirmBookingAfterPayment(session.metadata);
break;
case 'charge.refunded':
const charge = event.data.object;
// Cancel Calendly booking after refund
await cancelBookingAfterRefund(charge.metadata);
break;
}
}
Advanced Features
Intake Form Automation
Collect pre-call information conversationally instead of forcing clients to fill out forms:
// Calendly custom questions mapped from ChatGPT conversation
const intakeFormMapping = {
"What's your main challenge?": "business_challenge",
"What's your budget range?": "budget",
"When do you want to start?": "timeline",
"How did you hear about us?": "referral_source"
};
// ChatGPT extracts answers naturally during booking conversation
// Then maps to Calendly custom fields automatically
Pre-Call Questionnaires
Send targeted questions based on service type:
- Coaching: Current situation, desired outcome, obstacles
- Consulting: Business metrics, pain points, decision timeline
- Therapy: Medical history, current concerns, insurance info
- Legal: Case details, urgency, conflict check info
Follow-Up Automation
Sequence post-booking emails:
- Immediate: Calendar invite + payment receipt
- 24 hours before: Reminder with prep materials
- 1 hour before: Meeting link + agenda
- After call: Thank you + next steps
Meeting Prep Documents
Attach relevant materials based on conversation context:
- Discovery call: Company overview, case studies
- Strategy session: Pre-filled analysis templates
- Coaching: Goal-setting worksheets
Widget Design for ChatGPT
Inline Card: Available Slots
<!-- availability-card.html -->
<div class="scheduling-card">
<h3>Available Times - {{event_type_name}}</h3>
<p class="duration">{{duration}} minutes • {{timezone}}</p>
<div class="slots-container">
{{#each slots_by_day}}
<div class="day-section">
<h4>{{day_name}} {{date}}</h4>
<div class="time-slots">
{{#each slots}}
<button class="slot-button" onclick="selectSlot('{{start_time}}')">
{{time_12h}}
</button>
{{/each}}
</div>
</div>
{{/each}}
</div>
<p class="timezone-note">Times shown in {{timezone}}</p>
</div>
Fullscreen: Weekly Calendar View
For complex multi-day availability browsing:
- Interactive weekly grid
- Multiple service types side-by-side
- Team member filtering
- Time zone selector
Carousel: Service Types
Showcase different consultation offerings:
- 15-min quick calls
- 30-min discovery sessions
- 60-min deep dives
- Multi-session packages
Testing Your Scheduling App
Sandbox Mode Testing
- Create test event types in Calendly with short booking notice
- Use Stripe test mode for payment flows
- Test time zone conversions across multiple zones
- Verify webhook deliveries in Calendly dashboard
Critical Test Scenarios
- Same-day booking: Ensure real-time availability updates
- Payment failures: Graceful handling with retry options
- Cancellation within policy window: Automated refunds
- No-show handling: Automated follow-up sequences
- Double-booking prevention: Optimistic locking on slots
Time Zone Validation
Test bookings from:
- US Eastern (EST/EDT)
- US Pacific (PST/PDT)
- UK (GMT/BST)
- Australia (AEST)
- Asia (IST, JST)
Verify correct display and calendar event creation.
Marketing Your Scheduling ChatGPT App
Website Integration
Embed ChatGPT scheduling widget:
<script src="https://chatgpt.com/embed/your-scheduling-app.js"></script>
<div id="chatgpt-scheduler"></div>
Conversion benefits:
- 24/7 availability (no business hours restriction)
- Instant responses vs. form submissions
- Higher booking completion rates
Social Media Strategy
LinkedIn: Share ChatGPT booking link in posts
"Book a strategy call through ChatGPT: chatgpt.com/g/your-scheduler"
Instagram: Bio link to ChatGPT scheduler Email signature: Direct link to AI booking assistant
Client Experience Enhancement
- No app downloads: Works in ChatGPT web/mobile
- Conversation history: Clients can reference past bookings
- Rescheduling ease: "Reschedule my Tuesday call to Wednesday"
- Payment transparency: See costs during booking conversation
Troubleshooting Common Issues
Calendar Sync Conflicts
Symptom: Double bookings or unavailable slots showing as available
Causes:
- Calendar not synced to Calendly
- Buffer time not configured
- Multiple calendars not connected
Fix:
// Verify calendar connections
const calendarConnections = await calendly.client.get('/users/me/calendar_connections');
console.log('Connected calendars:', calendarConnections.data.collection);
// Check for conflicts
const conflicts = await calendly.client.get('/conflicts', {
params: {
start_time: startTime,
end_time: endTime
}
});
Payment Authorization Failures
Symptom: Stripe checkout fails or payment not captured
Causes:
- Incorrect API keys (test vs. live)
- Payment method restrictions
- Amount formatting errors
Fix:
- Verify Stripe API keys match environment
- Check webhook signing secrets
- Test with Stripe test cards first
- Log full error responses for debugging
Time Zone Calculation Errors
Symptom: Appointments booked at wrong times
Causes:
- Daylight saving time transitions
- Incorrect IANA timezone identifiers
- Server timezone vs. client timezone mismatch
Fix:
// Always use Luxon for timezone handling
import { DateTime } from 'luxon';
// CORRECT: Explicit timezone
const appointmentTime = DateTime.fromISO(inputTime, { zone: clientTimezone });
// WRONG: Assumes server timezone
const appointmentTime = new Date(inputTime); // ❌ Don't use Date()
Webhook Delivery Failures
Symptom: Booking confirmations not processed
Causes:
- Webhook endpoint not HTTPS
- Signature verification failing
- Endpoint timing out (>30s response)
Fix:
- Use ngrok for local testing:
ngrok http 3000 - Verify webhook signatures properly
- Respond to webhooks within 5 seconds (process async)
- Monitor Calendly webhook logs for failures
Conclusion
A professional scheduling ChatGPT app transforms how service professionals acquire and manage clients. By automating availability search, booking confirmation, payment collection, and calendar management, you eliminate scheduling friction that costs professionals 8-12 hours per week and causes 35-45% booking abandonment.
The implementation guide above provides production-ready code for:
- ✅ Calendly/Acuity API integration with webhooks
- ✅ Intelligent availability search with time zone handling
- ✅ Seamless payment collection with Stripe
- ✅ Automated intake forms and pre-call questionnaires
- ✅ Follow-up email sequences and meeting prep
Next Steps:
- Deploy in 48 hours: Use MakeAIHQ's no-code platform to generate your scheduling MCP server without writing code
- Customize for your niche: Adapt intake forms, service types, and pricing for your specific professional service
- Market to 800M users: Publish to ChatGPT App Store and reach clients where they already work
Related Resources:
- Build ChatGPT Apps Without Code: Complete 2026 Guide
- ChatGPT App Monetization Strategies for SaaS
- OpenAI Apps SDK Tutorial: Widget Design
- Coaching & Consulting ChatGPT Template
- Service Business Appointment Automation
- ChatGPT App Store SEO: Ranking Strategies
- Professional Services Digital Transformation
External Resources:
Ready to automate your professional scheduling and capture the ChatGPT market? Start building your scheduling ChatGPT app with MakeAIHQ — from zero to ChatGPT App Store in 48 hours, no coding required.
Built with MakeAIHQ — The no-code ChatGPT app builder for service professionals. Join 10,000+ consultants, coaches, and agencies automating client acquisition through ChatGPT.