Smart Schedules
Discover the Smart Schedules configured for your organization, fetch their full definition (including the intake form schema needed to render your own UI), and submit form values to get matched host + slot availability in one call.
All endpoints require the smart-scheduling:read scope.
Endpoints on this page
| Method | Endpoint | Description |
|---|---|---|
GET | /api/v1alpha1/smart-schedules | List schedules visible to the calling org. Details ↓ |
GET | /api/v1alpha1/smart-schedules/{scheduleId} | Fetch one schedule's full definition — matching form, survey questions, assignees. Details ↓ |
POST | /api/v1alpha1/smart-schedules/{scheduleId}/availability | Submit form values, run host routing, return matched host + slot pairs. Details ↓ |
List Smart Schedules
GET /api/v1alpha1/smart-schedules
Returns smart schedules visible to the calling org.
Query parameters
| Parameter | Type | Description |
|---|---|---|
cursor | string | Opaque pagination cursor. Omit on the first request. |
limit | number | Page size. Default 25, clamped to 1–100. |
sort | string | One of updatedAt, createdAt, name. Prefix with - for descending. Default -updatedAt. |
name | string | (optional) Substring filter on the schedule name; case-insensitive. |
status | string | (optional) active (default) or all. Draft schedules are always excluded. |
Response
Each item is a SmartScheduleSummarymodel.
curl -s "https://altus.cirrusinsight.com/api/v1alpha1/smart-schedules?limit=25" \
-H "X-Cirrus-Api-Key: $TOKEN"import requests
response = requests.get(
"https://altus.cirrusinsight.com/api/v1alpha1/smart-schedules",
headers={"X-Cirrus-Api-Key": token},
params={"limit": 25},
)
response.raise_for_status()
page = response.json()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 query = HttpUtility.ParseQueryString(string.Empty);
query["limit"] = "25";
var uri = new UriBuilder("https://altus.cirrusinsight.com/api/v1alpha1/smart-schedules")
{
Query = query.ToString()
}.Uri;
var response = await client.GetAsync(uri);
response.EnsureSuccessStatusCode();
var page = await response.Content.ReadAsStringAsync();{
"items": [
{
"id": "sched_...",
"name": "Demo Call",
"description": "Schedule a product demo with one of our sales engineers.",
"status": "active",
"durationMinutes": 30,
"timeZone": "America/Los_Angeles",
"publishedAt": "2026-05-01T12:00:00Z",
"updatedAt": "2026-07-14T09:30:00Z"
}
],
"nextCursor": null
}Get Smart Schedule
GET /api/v1alpha1/smart-schedules/{scheduleId}
Returns the full schedule definition including the matching form schema (which drives host routing), the survey-question schema (informational fields captured pre-booking), and the flat list of assignees eligible on this schedule.
Path parameters
| Parameter | Type | Description |
|---|---|---|
scheduleId | string | The smart schedule ID, prefixed sched_. |
Response
See SmartSchedulemodel for full field documentation.
Notes
assigneesis a flat list, not a grouped structure. The routing groups you'll see in an availability response are computed at match-time from the submitted form values — the stored schedule holds only an unordered set of eligible hosts and a distribution strategy, so a grouped shape here would be fabricated. Use the availability response for the real routing view.publishedAtis best-effort: when the schedule is published, this field reflects the schedule's creation timestamp. The underlying data model does not yet persist a separate publish timestamp, so treatpublishedAtas a lower bound rather than the exact moment the schedule went live. If the schedule is not published, the field is omitted.- Survey questions are keyed by text.
surveyQuestions[].keyis derived from the question text because the underlying data model does not currently expose a stable identifier. If the schedule owner renames a question, integrators must update their submitted keys — see survey-question notes.
Errors
404 schedule-not-found— the schedule does not exist or is not visible to this token's org
curl -s "https://altus.cirrusinsight.com/api/v1alpha1/smart-schedules/sched_01H8YKQ2N9DEMO" \
-H "X-Cirrus-Api-Key: $TOKEN"import requests
schedule_id = "sched_01H8YKQ2N9DEMO"
response = requests.get(
f"https://altus.cirrusinsight.com/api/v1alpha1/smart-schedules/{schedule_id}",
headers={"X-Cirrus-Api-Key": token},
)
response.raise_for_status()
schedule = response.json()using System.Net.Http;
using System.Net.Http.Headers;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Cirrus-Api-Key", token);
var scheduleId = "sched_01H8YKQ2N9DEMO";
var response = await client.GetAsync(
$"https://altus.cirrusinsight.com/api/v1alpha1/smart-schedules/{scheduleId}");
response.EnsureSuccessStatusCode();
var schedule = await response.Content.ReadAsStringAsync();{
"id": "sched_...",
"name": "Demo Call",
"description": "Schedule a product demo.",
"status": "active",
"durationMinutes": 30,
"timeZone": "America/Los_Angeles",
"bookingWindow": {
"minAdvanceMinutes": 120,
"maxAdvanceDays": 14
},
"matchingForm": {
"fields": [
{
"key": "region",
"label": "Region",
"type": "select",
"options": ["NA-East", "NA-West", "EMEA"],
"required": true
},
{
"key": "companySize",
"label": "Company size",
"type": "select",
"options": ["1-10", "11-50", "51-200", "201+"],
"required": true
}
]
},
"surveyQuestions": [
{ "key": "whatBrings", "label": "What brings you here today?", "type": "long-text", "required": false }
],
"assignees": [
{ "host": { "userId": "usr_...", "displayName": "Alex Rivera" } },
{ "host": { "userId": "usr_...", "displayName": "Sam Chen" } }
],
"publishedAt": "2026-05-01T12:00:00Z",
"updatedAt": "2026-07-14T09:30:00Z"
}Get availability (match + slots)
POST /api/v1alpha1/smart-schedules/{scheduleId}/availability
Submits form values, runs the schedule's routing logic to identify eligible hosts, and returns each host's available slots within the requested date range.
POST is used rather than GET because form values may be structured or multi-valued and do not encode cleanly in query parameters.
Request body
| Field | Type | Description |
|---|---|---|
formValues | object | Map of matchingForm.fields[].key → answer. Answer is either a scalar (string, number, boolean) for single-select / text fields, or an array of strings for multi-select. |
dateRange | object | (optional) Window to fetch availability for. Defaults to the schedule's default booking window. |
dateRange.start | string | Inclusive start, ISO 8601 UTC. |
dateRange.end | string | Inclusive end, ISO 8601 UTC. |
durationMinutes | number | (optional) Meeting length to offer. Must be one of the schedule's configured booking periods. Omit to use the default. An unsupported value returns 422 availability-request-invalid rather than being silently snapped. |
timeZone | string | (optional) IANA time zone. Informational only — slots are always returned in UTC. Useful if you want the server to log or echo which zone the caller was rendering. |
preview | boolean | (optional, default false) When true, slot tokens issued from this response carry a preview flag. Bookings from preview tokens skip webhook delivery and CRM sync. |
Response
Fields
hostGroups list
A nested list. The outer list is priority groups — group 0 contains the most-preferred hosts, group 1 the next-most-preferred, and so on. The inner list is equally-ranked hosts within a group (typically one host per group for round-robin, multiple for weighted distributions).
If you don't care about priority ordering, flatten with hostGroups.flat(). Agents that want to honor routing intent should iterate groups in order and prefer offering earlier-group hosts.
Host reference fields
Availability responses carry a lightweight host reference — userId and displayName only, not the full host object on a booked meeting. Same key name (host) so consumers can share JSON-path expressions across surfaces; the availability response omits email, firstName, and lastName because they're not needed to render a "book with X" list. Callers who need those fields can look up the host by userId after a booking succeeds.
| Attribute | Type | Description |
|---|---|---|
host.userId | string | The host's identifier, prefixed usr_. Byte-identical to the host.userId on a booked meeting, so identity is consistent across endpoints. |
host.displayName | string | The host's display name (first + last, falling back to email when no name is stored). May be shown directly to end-users. |
slots | list | Available slots for this host within the requested window. Each is an AvailableSlotmodel. |
matchedAt string
The UTC timestamp at which the matcher computed this response. Useful for logging and for correlating a client-side retry with the availability call it was based on.
Slot token semantics
- Tokens are valid for 10 minutes from issue. Older tokens are rejected with
410 slot-token-expired. - A token is bound to the specific
(scheduleId, host.userId, startTime, endTime)it was issued for. Tampering invalidates the signature and returns422 slot-token-invalid. - Slot tokens are opaque strings with no fixed prefix — they encode signed payload data. Do not attempt to parse, modify, or generate them client-side.
- The slot may become unavailable before its TTL expires (e.g., the host accepted another meeting). In that case
/scheduled-meetingsreturns409 slot-conflictwithrerunAvailability: true.
See AvailableSlotmodel for the full slot object.
Errors
404 schedule-not-found— schedule does not exist or is not visible to this org422 availability-request-invalid— the request body was malformed, ordurationMinutesis not one of the schedule's booking periods422 form-validation—formValuesfailed the schedule's matching-form validation (missing required field, value outside allowed option list, etc.). Response body includes afieldErrors[]array.
curl -s -X POST "https://altus.cirrusinsight.com/api/v1alpha1/smart-schedules/sched_01H8YKQ2N9DEMO/availability" \
-H "X-Cirrus-Api-Key: $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"formValues": {
"region": "NA-East",
"companySize": "51-200"
},
"dateRange": {
"start": "2026-06-15T00:00:00Z",
"end": "2026-06-29T00:00:00Z"
},
"durationMinutes": 30
}'import requests
schedule_id = "sched_01H8YKQ2N9DEMO"
response = requests.post(
f"https://altus.cirrusinsight.com/api/v1alpha1/smart-schedules/{schedule_id}/availability",
headers={"X-Cirrus-Api-Key": token},
json={
"formValues": {
"region": "NA-East",
"companySize": "51-200",
},
"dateRange": {
"start": "2026-06-15T00:00:00Z",
"end": "2026-06-29T00:00:00Z",
},
"durationMinutes": 30,
},
)
response.raise_for_status()
availability = response.json()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 scheduleId = "sched_01H8YKQ2N9DEMO";
var body = new
{
formValues = new
{
region = "NA-East",
companySize = "51-200",
},
dateRange = new
{
start = "2026-06-15T00:00:00Z",
end = "2026-06-29T00:00:00Z",
},
durationMinutes = 30,
};
var request = new HttpRequestMessage(
HttpMethod.Post,
$"https://altus.cirrusinsight.com/api/v1alpha1/smart-schedules/{scheduleId}/availability")
{
Content = new StringContent(
JsonSerializer.Serialize(body),
Encoding.UTF8,
"application/json"),
};
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
var availability = await response.Content.ReadAsStringAsync();{
"hostGroups": [
[
{
"host": { "userId": "usr_...", "displayName": "Alex Rivera" },
"slots": [
{
"startTime": "2026-06-16T17:00:00Z",
"endTime": "2026-06-16T17:30:00Z",
"slotToken": "eyJzY2hlZHVsZUlkIjoic2NoZWRf..."
},
{
"startTime": "2026-06-16T19:30:00Z",
"endTime": "2026-06-16T20:00:00Z",
"slotToken": "eyJzY2hlZHVsZUlkIjoic2NoZWRf..."
}
]
}
],
[
{
"host": { "userId": "usr_...", "displayName": "Sam Chen" },
"slots": [
{
"startTime": "2026-06-17T16:00:00Z",
"endTime": "2026-06-17T16:30:00Z",
"slotToken": "eyJzY2hlZHVsZUlkIjoic2NoZWRf..."
}
]
}
]
],
"matchedAt": "2026-06-15T14:22:00Z"
}