Book, Cancel, Reschedule & Callback
API reference for booking, cancelling, rescheduling appointments, and requesting callbacks via FlowCaptain.
Four endpoints covering the full appointment lifecycle.
These endpoints follow your API key, not your assistant's capabilities. The Cancellation and Rescheduling switches under Assistant › Name › Settings govern what the phone assistant does for callers — and they apply to the autopilot endpoint as well. The endpoints described here, and the MCP tools, remain callable even when that capability is switched off on the assistant. What protects against unwanted changes here is your API key and SMS verification.
The verification code for cancellation and rescheduling is a calendar setting (under Notifications) and applies on every path — phone, API and MCP. Not to be confused with the assistant's verification mode (under Appointments & Calendars), which governs how a caller's identity is checked before the assistant names existing appointments at all.
Each of the following requests requires calendarId as a field in the JSON body. You can find it pre-filled under Calendar › Name › API, section Integration Guide. If your platform wraps the body in an envelope (e.g. Retell's args object), pass it as a URL query parameter instead — ?calendarId=YOUR_CALENDAR_ID — because the API only reads calendarId from the top-level body, the query string, or route parameters, never from a nested args object.
Book an Appointment
Creates a new appointment in the connected Google Calendar. FlowCaptain automatically verifies that the requested slot is actually available before booking.
POST /api/v1/book-appointment
Request body:
{
"calendarId": "YOUR_CALENDAR_ID",
"dateTime": "2026-03-03T10:00:00+01:00",
"callerName": "Max Mustermann",
"callerIdNumber": "+4917604069001",
"reason": "Initial consultation"
}
| Field | Type | Required | Description |
|---|---|---|---|
| calendarId | string | Yes | Your calendar ID — determines which calendar the request targets |
| dateTime | string | Yes | Desired appointment time as an ISO 8601 timestamp |
| callerName | string | Yes | Name of the person booking |
| callerPhone | string | No | Phone number as spoken by the caller (for notifications) |
| callerIdNumber | string | No | Caller ID from telephony (recommended — for appointment lookup and SMS) |
| reason | string | No | Appointment reason/description |
| serviceName | string | No | Desired service — determines the appointment duration |
| serviceNames | string[] | No | Multiple desired services |
| language | string | No | "de" or "en" (default: "de") |
Success response (with "language": "en"):
{
"action": "booked",
"success": true,
"humanReadable": "Appointment booked successfully: Tuesday, 03.03 at 10:00 AM",
"result": "Appointment booked successfully",
"day": "Tuesday",
"date": "03.03",
"time": "10:00",
"appointmentId": "550e8400-e29b-41d4-a716-446655440000"
}
Drop-off calendar: On a drop-off calendar only the day counts. The response then has no time field but serviceType: "drop_off" — with a named service e.g. "humanReadable": "Job scheduled: Inspection on Tuesday, 03.03" and serviceName.
Slot taken: The response is action: "suggest" with alternative suggestions (time1–time3) — same as the availability check. If the day is fully booked, you get action: "reject".
Service not found: If serviceName matches no service of this calendar, the API responds with action: "suggest_service" (matching suggestions in suggestedServices) or with action: "clarify"; both responses include the list services of bookable services. Services of the type No appointment are never bookable.
Approval enabled: If the calendar uses Require Approval, the response is action: "pending_approval" instead of booked (e.g. "humanReadable": "Your appointment request for Tuesday, 03.03 at 10:00 AM has been submitted and is being reviewed.") — the appointment is entered as a request and only becomes final once the calendar owner approves it. On drop-off calendars the time is left out here too.
Cancel an Appointment
Cancels an existing appointment. The event is marked as cancelled in Google Calendar but not deleted — so it remains visible for your records.
POST /api/v1/cancel-appointment
Request body:
{
"calendarId": "YOUR_CALENDAR_ID",
"callerIdNumber": "+4917604069001",
"callerName": "Max Mustermann",
"appointmentDate": "2026-03-03"
}
| Field | Type | Required | Description |
|---|---|---|---|
| calendarId | string | Yes | Your calendar ID — determines which calendar the request targets |
| callerIdNumber | string | No* | Caller ID for the appointment lookup |
| callerPhone | string | No* | Phone number as spoken by the caller |
| callerName | string | No* | Helps identify the appointment |
| appointmentDate | string | No | Date of the appointment (ISO or natural language) |
| verificationCode | string | No | SMS verification code, if requested (see below) |
| language | string | No | "de" or "en" (default: "de") |
*FlowCaptain uses multiple attributes to identify the right appointment. The more information you pass (caller ID, name, date), the more reliable the match. If several appointments match, the API responds with action: "clarify" and an appointments[] list for follow-up.
Success response:
{
"action": "cancelled",
"success": true,
"humanReadable": "Appointment cancelled successfully: Tuesday, 03.03 at 10:00 AM",
"result": "Appointment cancelled successfully",
"day": "Tuesday",
"date": "03.03",
"time": "10:00"
}
SMS verification: If the Verification Code is enabled on the calendar, the API requires a code before cancelling:
{
"action": "verification_required",
"success": false,
"humanReadable": "For security, we sent a code to ***4567. Please provide the 4-digit code.",
"verificationPhone": "***4567"
}
The code is sent via SMS to the number on file. Repeat the request with the verificationCode field. A wrong code results in action: "verification_failed".
Reschedule an Appointment
Moves an existing appointment to a new time. FlowCaptain verifies availability at the new time before rescheduling.
POST /api/v1/reschedule-appointment
Request body:
{
"calendarId": "YOUR_CALENDAR_ID",
"callerIdNumber": "+4917604069001",
"callerName": "Max Mustermann",
"newDateTime": "2026-03-04T14:00:00+01:00"
}
| Field | Type | Required | Description |
|---|---|---|---|
| calendarId | string | Yes | Your calendar ID — determines which calendar the request targets |
| newDateTime | string | Yes | New appointment time as an ISO 8601 timestamp |
| callerIdNumber | string | No* | Caller ID for the appointment lookup |
| callerPhone | string | No* | Phone number as spoken by the caller |
| callerName | string | No* | Helps identify the appointment |
| appointmentDate | string | No | Date of the existing appointment (ISO or natural language) |
| verificationCode | string | No | SMS verification code, if requested |
| language | string | No | "de" or "en" (default: "de") |
*Appointment lookup and SMS verification work the same as for cancellation.
Success response:
{
"action": "rescheduled",
"success": true,
"humanReadable": "Appointment rescheduled successfully: from Tuesday, 03.03 at 10:00 AM to Wednesday, 04.03 at 2:00 PM",
"result": "Appointment rescheduled successfully",
"day": "Wednesday",
"date": "04.03",
"time": "14:00",
"previousDay": "Tuesday",
"previousDate": "03.03",
"previousTime": "10:00"
}
New time taken: The response is action: "suggest" with alternative suggestions.
Request a Callback
Requests a callback from the business owner when the voice bot cannot resolve the caller's issue.
POST /api/v1/request-callback
Request body:
{
"calendarId": "YOUR_CALENDAR_ID",
"callerName": "Max Mustermann",
"callerPhone": "+4917604069001",
"issueDescription": "Wants a callback",
"language": "en"
}
| Field | Type | Required | Description |
|---|---|---|---|
| calendarId | string | Yes | Your calendar ID — determines which calendar the request targets |
| callerName | string | No* | Name of the caller |
| callerPhone | string | No* | Phone number of the caller |
| callerIdNumber | string | No* | Caller ID from telephony |
| issueDescription | string | No | Short description of the issue (max. 500 characters) |
| language | string | No | "de" or "en" (default: "de") |
*Pass at least one of callerName, callerPhone, or callerIdNumber so the business can call back.
Success response:
{
"action": "callback_requested",
"success": true,
"humanReadable": "Callback request submitted",
"result": "Callback request submitted"
}
The business owner receives an email with the caller's contact details — sent to the calendar's Notification Email (under Notifications). If no email is set there, the response does not promise a callback. Callback requests are rate-limited to protect against abuse.