Skip to content
Preview. The endpoints on this page are illustrative and are likely to change as they move toward general availability. Documentation is published in advance so you can start shaping your integration; treat request and response details as subject to revision.

Scheduled Meetings

Book a meeting from a slot returned by /availability, read it back, reschedule it, or cancel it.

OperationScope required
Read (GET)smart-scheduling:read
Book / reschedule / cancelsmart-scheduling:write

Endpoints on this page

MethodEndpointDescription
POST/api/v1alpha1/scheduled-meetingsBook a meeting from a slot token returned by /availability. Idempotency-Key required. Details ↓
GET/api/v1alpha1/scheduled-meetings/{meetingId}Read a booked meeting's current state. Details ↓
PATCH/api/v1alpha1/scheduled-meetings/{meetingId}Reschedule a meeting to a new slot (host may change). Details ↓
DELETE/api/v1alpha1/scheduled-meetings/{meetingId}Cancel a meeting. Idempotent — second call also returns 204. Details ↓

Book a meeting

POST /api/v1alpha1/scheduled-meetings

Creates a meeting from a slot token previously returned by /availability.

Headers

HeaderDescription
Idempotency-KeyRequired. Client-generated opaque string up to 255 chars. Replaying the same key within 24 hours returns the original response (with an X-Idempotent-Replay: true header) without rebooking. A repeated key with a different body is a 422 idempotency-key-conflict.

Idempotency is required — not optional — on booking. A network timeout followed by an unguarded retry would otherwise result in double-bookings against the same host's calendar.

Request body

FieldTypeDescription
slotTokenstringSlot token from /availability. Encodes the schedule, host, start time, and end time — no need to pass them separately.
attendeeobjectThe person the meeting is being booked for. See Attendee.
formValuesobjectThe same form values you submitted to /availability. Map of keyanswer (scalar or array). The server verifies the values match those used to issue the slot token; a mismatch is 422 form-validation. Captured on the calendar event description and the post-booking webhook payload.
surveyResponsesobject(optional) Map of question text → free-text answer. Unknown keys are rejected with 422 — silently dropping a response would make a schedule owner's question rename look like a working integration that had quietly stopped collecting answers. See survey-question notes.

There is deliberately no preview flag on the booking request. Preview mode is inherited from the slot token — if the slot was issued from a preview: true availability call, the booking is preview-mode.

attendee object

AttributeTypeDescription
firstNamestringAttendee's given name.
lastNamestringAttendee's family name.
emailstringRFC 5322-valid email address.
phonestring(optional) E.164-formatted phone number. Presence triggers SMS confirmation; absence suppresses it. There is no separate toggle.
timeZonestring(optional) IANA time zone the attendee is booking from. Echoed in confirmation emails so the calendar event renders in a familiar zone.

Response

See Meetingmodel for the canonical shape, sub-object semantics, and per-feature field documentation.

Confirmation notifications

NotificationTriggered by
Confirmation email to host and attendeeSchedule's email-opt-in setting (configured in the Cirrus Insight admin UI; not overridable via the API)
SMS to attendeePresence of attendee.phone

To suppress both for a given booking, use a slot token issued from a preview: true availability call — preview bookings skip webhook delivery and CRM sync entirely.

Errors

  • 409 slot-conflict — the slot is no longer bookable (host's calendar changed since /availability). Response includes rerunAvailability: true.
  • 410 slot-token-expired — the slot token was issued more than 10 minutes ago. Refresh availability.
  • 422 slot-token-invalid — signature verification failed, or the payload doesn't match the requested schedule / host / times.
  • 422 form-validation — form values differ from those used to issue the slot token, or a required value is missing.
  • 422 booking-validation-failed — the request passed schema checks but was rejected downstream (e.g., unknown survey key).
  • 422 idempotency-key-conflict — the same Idempotency-Key was used with a different request body.
  • 400 idempotency-key-requiredIdempotency-Key header was missing.
  • 429 rate-limit-exceeded — too many requests.

bash
curl -s "https://altus.cirrusinsight.com/api/v1alpha1/scheduled-meetings" \
  -H "X-Cirrus-Api-Key: $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "slotToken": "eyJzY2hlZHVsZUlkIjoic2NoZWRf...",
    "attendee": {
      "firstName": "Sample",
      "lastName":  "Guest",
      "email":     "guest@example.com",
      "phone":     "+14155551234",
      "timeZone":  "America/New_York"
    },
    "formValues": {
      "region": "NA-East",
      "companySize": "51-200"
    },
    "surveyResponses": {
      "What brings you here today?": "Pipeline visibility"
    }
  }'
python
import requests
import uuid

headers = {
    "X-Cirrus-Api-Key": token,
    "Idempotency-Key": str(uuid.uuid4()),
}

response = requests.post(
    "https://altus.cirrusinsight.com/api/v1alpha1/scheduled-meetings",
    headers=headers,
    json={
        "slotToken": "eyJzY2hlZHVsZUlkIjoic2NoZWRf...",
        "attendee": {
            "firstName": "Sample",
            "lastName": "Guest",
            "email": "guest@example.com",
            "phone": "+14155551234",
            "timeZone": "America/New_York",
        },
        "formValues": {
            "region": "NA-East",
            "companySize": "51-200",
        },
        "surveyResponses": {
            "What brings you here today?": "Pipeline visibility",
        },
    },
)
response.raise_for_status()
meeting = response.json()
csharp
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Cirrus-Api-Key", token);

var body = new
{
    slotToken = "eyJzY2hlZHVsZUlkIjoic2NoZWRf...",
    attendee = new
    {
        firstName = "Sample",
        lastName = "Guest",
        email = "guest@example.com",
        phone = "+14155551234",
        timeZone = "America/New_York",
    },
    formValues = new
    {
        region = "NA-East",
        companySize = "51-200",
    },
    surveyResponses = new Dictionary<string, string>
    {
        ["What brings you here today?"] = "Pipeline visibility",
    },
};

var request = new HttpRequestMessage(
    HttpMethod.Post,
    "https://altus.cirrusinsight.com/api/v1alpha1/scheduled-meetings")
{
    Content = new StringContent(
        JsonSerializer.Serialize(body),
        Encoding.UTF8,
        "application/json"),
};
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());

var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
var meeting = await response.Content.ReadAsStringAsync();
HTTP/1.1 201 Created
Content-Type: application/json
json
{
  "id": "mtg_...",
  "orgId": "org_...",
  "host": {
    "userId": "usr_...",
    "email": "alex.rivera@example.com",
    "firstName": "Alex",
    "lastName": "Rivera",
    "displayName": "Alex Rivera"
  },
  "attendee": {
    "email": "guest@example.com",
    "firstName": "Sample",
    "lastName": "Guest",
    "phone": "+14155551234",
    "timeZone": "America/New_York"
  },
  "additionalAttendees": [],
  "title": "Cirrus Insight Demo",
  "startTime": "2026-06-16T17:00:00Z",
  "endTime":   "2026-06-16T17:30:00Z",
  "timeZone":  "America/Los_Angeles",
  "location": {
    "type": "video",
    "provider": "zoom",
    "joinUrl": "https://us02web.zoom.us/j/...",
    "address": null
  },
  "conferencing": {
    "provider": "zoom",
    "providerMeetingId": "1234567890"
  },
  "calendarEventId": "google-event-uid",
  "status": "scheduled",
  "createdAt": "2026-06-15T14:23:01Z",
  "updatedAt": "2026-06-15T14:23:01Z",
  "smartScheduling": {
    "scheduleId": "sched_...",
    "formValues": [
      { "key": "region", "answer": "NA-East" }
    ],
    "surveyResponses": [
      { "question": "What brings you here today?", "answer": "Pipeline visibility" }
    ],
    "rescheduleUrl": "https://...",
    "cancelUrl": "https://...",
    "campaign": {
      "id": null, "source": null, "medium": null,
      "campaign": null, "term": null, "content": null
    },
    "preview": false
  },
  "personalScheduling": null,
  "teamScheduling": null,
  "meetingAi": null
}

Read a scheduled meeting

GET /api/v1alpha1/scheduled-meetings/{meetingId}

Returns a previously booked meeting. Useful for agents that want to confirm state without keeping their own copy — the create response and this read response share exactly one DTO.

Path parameters

ParameterTypeDescription
meetingIdstringThe meeting ID, prefixed mtg_.

Response

Same shape as POST /scheduled-meetings. status is clock-derived (scheduled before end-time, completed after, canceled overrides both) so a cached value may go stale without a write.

Errors

  • 404 meeting-not-found — meeting does not exist, or is not visible to this org

bash
curl -s "https://altus.cirrusinsight.com/api/v1alpha1/scheduled-meetings/mtg_01H8YKQ2N9DEMO" \
  -H "X-Cirrus-Api-Key: $TOKEN"
python
import requests

meeting_id = "mtg_01H8YKQ2N9DEMO"
response = requests.get(
    f"https://altus.cirrusinsight.com/api/v1alpha1/scheduled-meetings/{meeting_id}",
    headers={"X-Cirrus-Api-Key": token},
)
response.raise_for_status()
meeting = response.json()
csharp
using System.Net.Http;
using System.Net.Http.Headers;

var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Cirrus-Api-Key", token);

var meetingId = "mtg_01H8YKQ2N9DEMO";
var response = await client.GetAsync(
    $"https://altus.cirrusinsight.com/api/v1alpha1/scheduled-meetings/{meetingId}");
response.EnsureSuccessStatusCode();
var meeting = await response.Content.ReadAsStringAsync();

Reschedule a meeting

PATCH /api/v1alpha1/scheduled-meetings/{meetingId}

Changes a meeting's time (and optionally host) by providing a new slot token. If the new slot belongs to a different host, the platform performs a host-swap reschedule.

Cannot change the attendee — for that, cancel and rebook. Cannot move a meeting between schedules — the new slot token must belong to the same schedule as the original meeting (422 schedule-mismatch otherwise).

Request body

FieldTypeDescription
slotTokenstringNew slot token from /availability. May belong to a different host than the original meeting, but must belong to the same schedule.
reasonstring(optional) Free-text reason. Stored on the meeting's audit trail and included in the reschedule webhook payload.

Idempotency-Key is required, same rules as booking.

Response

200 OK with the updated ScheduledMeetingmodel.

A scheduling.smartscheduler.rescheduled webhook fires after a successful reschedule.

Errors

Same set as booking, plus:

  • 409 meeting-not-reschedulable — the meeting is already canceled or completed
  • 422 schedule-mismatch — the slot token's scheduleId differs from the meeting's schedule

bash
curl -s -X PATCH "https://altus.cirrusinsight.com/api/v1alpha1/scheduled-meetings/mtg_01H8YKQ2N9DEMO" \
  -H "X-Cirrus-Api-Key: $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "slotToken": "eyJzY2hlZHVsZUlkIjoic2NoZWRf...",
    "reason": "Attendee requested to move to next week"
  }'
python
import requests
import uuid

meeting_id = "mtg_01H8YKQ2N9DEMO"
headers = {
    "X-Cirrus-Api-Key": token,
    "Idempotency-Key": str(uuid.uuid4()),
}

response = requests.patch(
    f"https://altus.cirrusinsight.com/api/v1alpha1/scheduled-meetings/{meeting_id}",
    headers=headers,
    json={
        "slotToken": "eyJzY2hlZHVsZUlkIjoic2NoZWRf...",
        "reason": "Attendee requested to move to next week",
    },
)
response.raise_for_status()
meeting = response.json()
csharp
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Cirrus-Api-Key", token);

var meetingId = "mtg_01H8YKQ2N9DEMO";
var body = new
{
    slotToken = "eyJzY2hlZHVsZUlkIjoic2NoZWRf...",
    reason = "Attendee requested to move to next week",
};

var request = new HttpRequestMessage(
    new HttpMethod("PATCH"),
    $"https://altus.cirrusinsight.com/api/v1alpha1/scheduled-meetings/{meetingId}")
{
    Content = new StringContent(
        JsonSerializer.Serialize(body),
        Encoding.UTF8,
        "application/json"),
};
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());

var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
var meeting = await response.Content.ReadAsStringAsync();

Cancel a meeting

DELETE /api/v1alpha1/scheduled-meetings/{meetingId}

Cancels a previously booked meeting. The calendar event is removed, the attendee receives a cancellation notification (if configured), and a scheduling.smartscheduler.canceled webhook fires.

Query parameters

ParameterTypeDescription
sendNotificationsboolean(optional, default true) When false, suppresses the cancellation email and SMS. Useful for silent cleanup operations.
reasonstring(optional, max 500 chars) Free-text reason. Surfaced in the cancellation webhook payload.

Cancel takes query parameters rather than a body because DELETE bodies aren't universally supported by HTTP clients.

Response

204 No Content on success.

Cancelling an already-canceled meeting also returns 204. DELETE states a desired end condition; that condition already holds, so a retry after a client timeout succeeds silently rather than being treated as a failure. Notifications only fire on the first cancel — a second DELETE does not re-send.

Subsequent GET /scheduled-meetings/{id} returns the meeting with status: "canceled".

Errors

  • 404 meeting-not-found — meeting does not exist or is not visible to this org
  • 410 meeting-completed — cannot cancel a meeting whose end time has already passed
bash
curl -s -X DELETE \
  "https://altus.cirrusinsight.com/api/v1alpha1/scheduled-meetings/mtg_01H8YKQ2N9DEMO?sendNotifications=true&reason=Invitee%20requested%20cancellation" \
  -H "X-Cirrus-Api-Key: $TOKEN"
python
import requests

meeting_id = "mtg_01H8YKQ2N9DEMO"
response = requests.delete(
    f"https://altus.cirrusinsight.com/api/v1alpha1/scheduled-meetings/{meeting_id}",
    headers={"X-Cirrus-Api-Key": token},
    params={
        "sendNotifications": "true",
        "reason": "Invitee requested cancellation",
    },
)
response.raise_for_status()
csharp
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web;

var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Cirrus-Api-Key", token);

var meetingId = "mtg_01H8YKQ2N9DEMO";
var query = HttpUtility.ParseQueryString(string.Empty);
query["sendNotifications"] = "true";
query["reason"] = "Invitee requested cancellation";

var uri = new UriBuilder(
    $"https://altus.cirrusinsight.com/api/v1alpha1/scheduled-meetings/{meetingId}")
{
    Query = query.ToString()
}.Uri;

var response = await client.DeleteAsync(uri);
response.EnsureSuccessStatusCode();

Raleigh, NC — a Cirruspath, Inc. company