| Action Name | Purpose | When to Use |
|---|---|---|
| GHL Upsert Contact | Create or update contacts in CRM | Before scheduling appointments, managing customer data |
| GHL Calendar Free Slots | Retrieve available time slots | When showing availability to customers |
| GHL Create Appointment | Book appointments in calendar | After confirming time slot with customer |
https://crmpage.com/v2/location/eDv3Z93Fnte6jr7ytj/eDv3Z93Fnte6jr7ytj| Action | Required Scopes |
|---|---|
| GHL Upsert Contact | contacts.write |
| GHL Calendar Free Slots | calendars.readonly (or calendars.write) |
| GHL Create Appointment | calendars/events.write |
contacts.write - Create and update contactscalendars.readonly - View calendar availabilitycalendars/events.write - Create appointmentshttps://crmpage.com/v2/location/eDv3Z93Fnte6jr7ytj/calendar/CVokAlI8fgw4WYWoCtQzCVokAlI8fgw4WYWoCtQz| Field | Value | Description |
|---|---|---|
| Tool Name | "GHL Upsert Contact" | A friendly name for your action |
| API Key | [Your API Token] | The token you created in Private Integrations |
| Location ID | [Your Location ID] | From your GHL URL |
| API Version | 2021-04-15 | Default version (pre-selected) |
| Field | Value | Description |
|---|---|---|
| Tool Name | "GHL Calendar Availability" | A friendly name for your action |
| API Key | [Your API Token] | The token you created in Private Integrations |
| Calendar ID | [Your Calendar ID] | From your calendar settings |
| API Version | 2021-04-15 | Default version (pre-selected) |
| Field | Value | Description |
|---|---|---|
| Tool Name | "GHL Book Appointment" | A friendly name for your action |
| API Key | [Your API Token] | The token you created in Private Integrations |
| Calendar ID | [Your Calendar ID] | From your calendar settings |
| Location ID | [Your Location ID] | From your GHL URL |
| API Version | 2021-04-15 | Default version (pre-selected) |

contacts.write| Parameter | Required | Description | Example |
|---|---|---|---|
locationId | ✅ Yes | Your GHL Location ID (auto-filled from template) | eDv3Z93Fnte6jr7ytj |
email | ⚠️ One Required | Contact email address | john@example.com |
phone | ⚠️ One Required | Phone with country code | +1 888-888-8888 |
firstName | No | First name | John |
lastName | No | Last name | Doe |
name | No | Full name | John Doe |
address1 | No | Street address | 123 Main St |
city | No | City | New York |
state | No | State/Province | NY |
postalCode | No | ZIP/Postal code | 10001 |
country | No | Country code | US |
timezone | No | IANA timezone | America/New_York |
tags | No | Array of tags | ["customer", "vip"] |
customFields | No | Custom field values | See docs for format |
email OR phonetags parameter overwrites all existing tags - use the Add/Remove Tag API for incremental updates{
"contact": {
"id": "0007BWpSzSwfiuSl0tR2",
"locationId": "eDv3Z93Fnte6jr7ytj",
"email": "john@example.com",
"phone": "+18888888888",
...
},
"new": false
}id field is the Contact ID you'll need for creating appointments.calendars.readonly (or calendars.write)| Parameter | Required | Description | Example |
|---|---|---|---|
startDate | ✅ Yes | Start of search window (Unix epoch milliseconds) | 1548898600000 |
endDate | ✅ Yes | End of search window (Unix epoch milliseconds) | 1549503400000 |
timezone | No | IANA timezone name for interpreting dates | America/New_York |
startDate must be in the futureendDate should be within 7 days of startDate for best results{
"2021-06-23": {
"slots": [
"09:00 AM - 09:30 AM",
"10:00 AM - 10:30 AM",
"02:00 PM - 02:30 PM"
]
},
"2021-06-24": {
"slots": [
"09:00 AM - 09:30 AM",
"11:00 AM - 11:30 AM"
]
}
}calendars/events.write→ Customer provides their details
→ AI calls "GHL Upsert Contact"
→ Response contains contactId: "0007BWpSzSwfiuSl0tR2"→ Customer asks "when are you available?"
→ AI calls "GHL Calendar Free Slots"
→ Shows available time slots to customer→ Customer: "I'll take the 2 PM slot on June 23rd"
→ AI confirms: date, time, duration→ AI calls "GHL Create Appointment"
→ Uses contactId from Step 1
→ Uses confirmed time slot from Steps 2-3
→ Appointment is booked!| Parameter | Required | Description | Example |
|---|---|---|---|
calendarId | ✅ Yes | Your GHL Calendar ID (auto-filled) | CVokAlI8fgw4WYWoCtQz |
locationId | ✅ Yes | Your GHL Location ID (auto-filled) | eDv3Z93Fnte6jr7ytj |
contactId | ✅ Yes | Contact ID from Upsert Contact | 0007BWpSzSwfiuSl0tR2 |
startTime | ✅ Yes | Appointment start time (ISO 8601 with timezone) | 2021-06-23T14:00:00-04:00 |
endTime | No | Appointment end time (ISO 8601 with timezone) | 2021-06-23T14:30:00-04:00 |
title | No | Appointment title | Consultation Call |
appointmentStatus | No | Status: new, confirmed, cancelled, showed, noshow, invalid | confirmed |
description | No | Appointment description | Initial consultation |
address | No | Meeting location/address | Zoom |
meetingLocationType | No | Type: custom, zoom, gmeet, phone, address, ms_teams, google | zoom |
assignedUserId | No | User ID to assign the appointment to | 0007BWpSzSwfiuSl0tR2 |
ignoreDateRange | No | Skip minimum scheduling notice | false |
toNotify | No | Run automations (true) or skip (false) | true |
ignoreFreeSlotValidation | No | Skip slot availability check (dangerous!) | false |
contactId first from Upsert ContactYYYY-MM-DDTHH:mm:ss±HH:MMaddress is provided, meetingLocationType defaults to customignoreFreeSlotValidation to true can cause double-bookings!{
"event": {
"id": "ocQHyuzHvysMo5N5VsXc",
"calendarId": "CVokAlI8fgw4WYWoCtQz",
"locationId": "eDv3Z93Fnte6jr7ytj",
"contactId": "0007BWpSzSwfiuSl0tR2",
"startTime": "2021-06-23T14:00:00-04:00",
"endTime": "2021-06-23T14:30:00-04:00",
"title": "Consultation Call",
"appointmentStatus": "confirmed",
...
}
}
contactIdcontactId from step 2startTime from confirmed slotAI: Hi! I can help you schedule an appointment. Can I get your name and email?
Customer: Sure, I'm John Doe, john@example.com
AI: Thanks John! Let me check my calendar...
[Calls Upsert Contact - gets contactId]
[Calls Get Calendar Free Slots]
I have availability on:
- June 23rd at 9 AM, 10 AM, or 2 PM
- June 24th at 9 AM or 11 AM
Which works best for you?
Customer: I'll take June 23rd at 2 PM
AI: Perfect! I'll book you for June 23rd at 2:00 PM. This will be a 30-minute consultation.
[Calls Create Appointment]
All set! You're confirmed for June 23rd at 2:00 PM. You'll receive a confirmation email shortly.AI: Hi! How can I help you today?
Customer: I moved and need to update my address
AI: I can help with that. What's your email address?
Customer: john@example.com
AI: Got it. What's your new address?
Customer: 456 Oak Avenue, Los Angeles, CA 90001
AI: [Calls Upsert Contact with new address]
Perfect! I've updated your address to 456 Oak Avenue, Los Angeles, CA 90001.
Is there anything else you'd like to update?Customer: When are you available next week?
AI: Let me check my calendar...
[Calls Get Calendar Free Slots for next 7 days]
I have several openings next week:
- Monday at 9 AM, 10 AM, 2 PM
- Tuesday at 9 AM, 11 AM
- Wednesday at 1 PM, 3 PM
Would you like to book one of these times?
Customer: Let me check my schedule and call back
AI: No problem! Feel free to reach out whenever you're ready to book.id field from the Upsert Contact responseignoreFreeSlotValidation: true unless absolutely necessarystartTime is in ISO 8601 format: YYYY-MM-DDTHH:mm:ss±HH:MM-04:00 or +05:302021-06-23T14:00:00-04:00| Action | Required Scopes |
|---|---|
| Upsert Contact | contacts.write |
| Get Calendar Free Slots | calendars.readonly or calendars.write |
| Create Appointment | calendars/events.write |
| Credential | Where to Find | Used For |
|---|---|---|
| API Token | Settings > Private Integrations | All actions (authentication) |
| Location ID | URL when viewing location | Upsert Contact, Create Appointment |
| Calendar ID | Calendars page URL or settings | Get Free Slots, Create Appointment |
✅ contacts.write → Upsert Contact
✅ calendars.readonly → Get Calendar Free Slots
✅ calendars/events.write → Create Appointment