Skip to main content
Bookings (appointments) represent scheduled meetings between hosts and attendees. Each booking links a meeting type to a specific time slot.

Booking Lifecycle

Create a Booking

curl -X POST "https://api.meetergo.com/v4/booking" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "meetingTypeId": "770e8400-e29b-41d4-a716-446655440002",
    "start": "2024-01-15T09:00:00+01:00",
    "hostIds": ["550e8400-e29b-41d4-a716-446655440000"],
    "attendee": {
      "email": "customer@example.com",
      "firstname": "Jane",
      "lastname": "Doe",
      "receiveReminders": true,
      "notes": {}
    }
  }'

Request Body

FieldTypeRequiredDescription
meetingTypeIdstringYesMeeting type UUID
startstringYesStart time (ISO 8601 with timezone)
hostIdsstring[]No*Host user UUIDs
queueIdstringNo*Queue ID for round-robin (alternative to hostIds)
attendeeobjectYesAttendee information
durationnumberNoDuration in minutes (must match an allowed duration on the meeting type)
channelstringNoMeeting channel: google, zoom, teamsForBusiness2, phone, phone-incoming, local, local-attendee, connect, webex, whatsapp
locationstringNoFor local channel: selects from configured locations. For local-attendee: can also use attendee.notes.address
icsTitlestringNoCustom calendar invite title (max 200 chars), overrides meeting type default
icsDescriptionstringNoCustom calendar invite description (max 2000 chars), overrides meeting type default
skipNotificationsbooleanNoSkip email notifications (default: false)
phoneOnlyBookingbooleanNoUse phone as identifier instead of email. See Voice AI Bot
*Either hostIds or queueId is required

Attendee Object

FieldTypeRequiredDescription
emailstringYes*Attendee email
firstnamestringNo†First name (†either fullname or firstname/lastname required)
lastnamestringNo†Last name
fullnamestringNo†Full name (alternative to first/last)
phonestringNoPhone number
receiveRemindersbooleanYesWhether the attendee receives reminder emails
notesobjectYesKey-value object for form field responses and UTM parameters. Pass {} if none
languagestringNoLocale for notifications (en, de, etc.)
timezonestringNoAttendee timezone (e.g. Europe/Berlin)
bringalongEmailsstring[]NoAdditional attendee emails (max 5)
*Not required when phoneOnlyBooking is true and the meeting type has allowPhoneOnlyBooking enabled. See Voice AI Bot for details. See Create Booking API Reference for full field documentation, examples with custom ICS content, and UTM tracking.

Response (Standard)

{
  "appointmentId": "appt-uuid-12345",
  "secret": "secret-token-xyz"
}
Store the secret to cancel or reschedule without authentication.

Response (Double Opt-In)

If the meeting type requires email confirmation:
{
  "bookingType": "DoubleOptIn",
  "provisionalBookingId": "provisional-uuid-123"
}
The booking is finalized after the attendee confirms via email.

Get Appointments

Get Paginated Appointments

curl -X GET "https://api.meetergo.com/v4/appointment/paginated/?page=1&limit=20" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-meetergo-api-user-id: {userId}"

Get Single Appointment

curl -X GET "https://api.meetergo.com/v4/appointment/{appointmentId}" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-meetergo-api-user-id: {userId}"

Response

{
  "id": "appt-uuid-12345",
  "start": "2024-01-15T09:00:00+01:00",
  "end": "2024-01-15T09:30:00+01:00",
  "isCancelled": false,
  "meetingType": {
    "id": "770e8400-e29b-41d4-a716-446655440002",
    "name": "Discovery Call",
    "duration": 30
  },
  "attendees": [
    {
      "id": "att-uuid-789",
      "email": "customer@example.com",
      "firstname": "Jane",
      "lastname": "Doe"
    }
  ],
  "hosts": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "email": "john@example.com",
      "givenName": "John",
      "familyName": "Smith"
    }
  ]
}

Cancel an Appointment

As Host (Authenticated)

curl -X POST "https://api.meetergo.com/v4/appointment/{appointmentId}/cancel" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-meetergo-api-user-id: {userId}" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Unable to attend"
  }'

With Secret (Unauthenticated)

For self-service cancellation by attendees:
curl -X POST "https://api.meetergo.com/booking/confirm/cancel/{appointmentId}/{secret}" \
  -H "Content-Type: application/json" \
  -d '{
    "cancellationReason": "Schedule conflict"
  }'
Both methods trigger:
  • Cancellation emails to all parties
  • booking_cancelled webhook event
  • Calendar event removal (if integrated)

Reschedule an Appointment

With Secret (Unauthenticated)

curl -X POST "https://api.meetergo.com/booking/confirm/reschedule/" \
  -H "Content-Type: application/json" \
  -d '{
    "appointmentId": "appt-uuid-12345",
    "secret": "secret-token-xyz",
    "start": "2024-01-16T10:00:00+01:00"
  }'

As Host (Authenticated)

curl -X POST "https://api.meetergo.com/v4/appointment/{appointmentId}/reschedule" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-meetergo-api-user-id: {userId}" \
  -H "Content-Type: application/json" \
  -d '{
    "start": "2024-01-16T10:00:00+01:00"
  }'

Response

{
  "appointmentId": "appt-uuid-12345",
  "secret": "secret-token-xyz"
}
Rescheduling triggers:
  • Updated calendar invites
  • Notification emails
  • booking_rescheduled webhook event

Form Fields and UTM Parameters

Pass form field responses and UTM tracking data via attendee.notes:
{
  "meetingTypeId": "770e8400-e29b-41d4-a716-446655440002",
  "start": "2024-01-15T09:00:00+01:00",
  "hostIds": ["550e8400-e29b-41d4-a716-446655440000"],
  "attendee": {
    "email": "customer@example.com",
    "firstname": "Jane",
    "receiveReminders": true,
    "notes": {
      "company_size": "50-200",
      "referral_source": "Google",
      "utm_source": "website",
      "utm_content": "demo_cta"
    }
  }
}
Notes values are:
  • Included in webhook payloads
  • Visible in the dashboard
  • Synced to CRM integrations (UTM parameters can be mapped to Salesforce fields via Integrations → Salesforce → Settings)

Round-Robin Bookings

For team meeting types, use queueId instead of hostIds:
{
  "meetingTypeId": "770e8400-e29b-41d4-a716-446655440002",
  "start": "2024-01-15T09:00:00+01:00",
  "queueId": "queue-uuid-123",
  "attendee": {
    "email": "customer@example.com",
    "receiveReminders": true,
    "notes": {}
  }
}
The system automatically selects the next available team member based on:
  • Round-robin rotation
  • Current availability
  • Existing bookings

Error Handling

Time Slot Unavailable

{
  "statusCode": 400,
  "message": "The selected time slot is no longer available",
  "error": "Bad Request"
}
Solution: Query fresh availability and select another slot.

Invalid Duration

{
  "statusCode": 400,
  "message": "Duration must match one of the allowed durations for this meeting type",
  "error": "Bad Request"
}
Solution: Check the meeting type’s allowed durations.

Missing Host

{
  "statusCode": 400,
  "message": "hostIds or queueId is required",
  "error": "Bad Request"
}
Solution: Provide either hostIds array or queueId.

Best Practices

Always query availability first - Don’t book without checking available slots
Store the secret - You’ll need it for self-service cancel/reschedule
Handle race conditions - Slots can be booked between availability query and booking
Use webhooks - Get real-time notifications instead of polling
Time format - Always include timezone offset in ISO 8601 format (e.g., +01:00)