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.

Webhook Subscriptions

Manage webhook endpoints that receive scheduling-lifecycle events from the Platform API. The underlying delivery infrastructure is documented in full on the Webhook Basics page — HMAC-SHA256 signatures, retries with exponential backoff, and delivery logs.

The Platform API surfaces a programmatic CRUD interface so AI agents and integrations can manage their own subscriptions without going through the developer dashboard.

OperationScope required
List, get, list deliverieswebhooks:read
Create, deletewebhooks:write

Endpoints on this page

MethodEndpointDescription
GET/api/v1alpha1/webhook-subscriptionsList subscriptions owned by the calling org. Details ↓
POST/api/v1alpha1/webhook-subscriptionsCreate a subscription. Signing secret is revealed once in the response. Details ↓
GET/api/v1alpha1/webhook-subscriptions/{subscriptionId}Read one subscription's current state (no signing secret). Details ↓
DELETE/api/v1alpha1/webhook-subscriptions/{subscriptionId}Soft-delete a subscription. Idempotent — second call also returns 204. Details ↓
GET/api/v1alpha1/webhook-subscriptions/{subscriptionId}/deliveriesRead delivery-attempt history for a subscription. Details ↓

Available event types

Every event is delivered inside a canonical Eventmodel envelope. The event.data shape depends on the event type — see the per-family pages linked in the last column for the full field reference.

Scheduling (details)

event.data is a canonical Meetingmodel object.

Event typeWhen it fires
scheduling.smartscheduler.scheduledA Smart Scheduler meeting is booked
scheduling.smartscheduler.rescheduledA Smart Scheduler meeting is rescheduled
scheduling.smartscheduler.canceledA Smart Scheduler meeting is canceled
scheduling.personalscheduling.scheduledA personal-scheduling-page meeting is booked
scheduling.personalscheduling.rescheduledA personal-scheduling-page meeting is rescheduled
scheduling.personalscheduling.canceledA personal-scheduling-page meeting is canceled
scheduling.teamscheduling.scheduledA team-scheduling-page meeting is booked
scheduling.teamscheduling.rescheduledA team-scheduling-page meeting is rescheduled
scheduling.teamscheduling.canceledA team-scheduling-page meeting is canceled

Configuration (details)

event.data is a change-history record with previous, current, and modifiedBy fields.

Event typeWhen it fires
organization.setting.changedAn organization-level setting is modified
organization.profile.changedThe company profile (name, web address, logo) is modified
organization.service_account.changedA service-account configuration is added, modified, or removed
organization.domains.changedThe organization's domain list is modified

Developer (details)

Delivered automatically as part of the subscription-validation flow — not opt-in via the events array. Every new subscription receives one regardless of what business events it subscribed to.

Event typeWhen it fires
developer.webhook.testA new subscription enters the validating state

List webhook subscriptions

GET /api/v1alpha1/webhook-subscriptions

Returns subscriptions owned by the calling org.

Query parameters

ParameterTypeDescription
cursorstringOpaque pagination cursor.
limitnumberPage size. Default 25, clamped to 1–100.
sortstringcreatedAt or updatedAt, prefix - for descending. Default -updatedAt.

Response

status is one of:

  • active — accepting and delivering events
  • disabled — administratively paused (typically after repeated delivery failures put the subscription in probation, then failed to recover)
  • validating — set on initial create until the system successfully pings the endpoint

lastDeliveryAt is the timestamp of the most recent delivery attempt (successful or failed) and is the primary "is my webhook healthy" signal.

signingSecret is never returned by this endpoint — it's revealed exactly once, on create.


bash
curl -s "https://altus.cirrusinsight.com/api/v1alpha1/webhook-subscriptions?limit=25" \
  -H "X-Cirrus-Api-Key: $TOKEN"
python
import requests

response = requests.get(
    "https://altus.cirrusinsight.com/api/v1alpha1/webhook-subscriptions",
    headers={"X-Cirrus-Api-Key": token},
    params={"limit": 25},
)
response.raise_for_status()
page = response.json()
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 query = HttpUtility.ParseQueryString(string.Empty);
query["limit"] = "25";

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

var response = await client.GetAsync(uri);
response.EnsureSuccessStatusCode();
var page = await response.Content.ReadAsStringAsync();
json
{
  "items": [
    {
      "id": "sub_...",
      "endpointUrl": "https://example.com/cirrus-webhook",
      "events": [
        "scheduling.smartscheduler.scheduled",
        "scheduling.smartscheduler.rescheduled",
        "scheduling.smartscheduler.canceled"
      ],
      "status": "active",
      "description": "Production booking sync",
      "createdAt": "2026-06-01T12:00:00Z",
      "lastDeliveryAt": "2026-07-28T09:12:00Z"
    }
  ],
  "nextCursor": null
}

Create a webhook subscription

POST /api/v1alpha1/webhook-subscriptions

Request body

FieldTypeDescription
endpointUrlstringThe HTTPS endpoint that will receive event deliveries. Must be https://; localhost and RFC1918 addresses are rejected server-side.
eventslistOne or more allowed event types (see above). Must be a non-empty subset of the v1alpha1 catalog.
descriptionstring(optional, max 200 chars) Free-text label to help you identify the subscription in list views.

The signing secret is generated by the server — you do not provide it. See the response below.

Response

201 Created:

The signingSecret is returned exactly once, on this response. It is never included in subsequent GET responses. Store it in your secrets manager immediately; a lost secret cannot be recovered — delete the subscription and create a new one.

New subscriptions start in status: "validating". The system pings your endpoint before treating it as active; a subscription that never validates transitions to disabled and stops receiving events.

Errors

  • 422 webhook-endpoint-invalidendpointUrl is not HTTPS, or targets a private / loopback address
  • 422 webhook-events-invalid — empty event list, or contains an event not in the v1alpha1 catalog
  • 422 webhook-limit-reached — your org already has the maximum number of subscriptions (10 in v1)

Verifying deliveries

Deliveries include:

  • X-Cirrus-Signature: sha256=<hex> — HMAC-SHA256 of the raw request body signed with your subscription's signingSecret
  • X-Cirrus-Event-Type — e.g., scheduling.smartscheduler.scheduled
  • X-Cirrus-Correlation-Id — shared across all retry attempts for one event

Always verify the signature before processing the payload. See Webhook Security for the verification recipe.


bash
curl -s -X POST "https://altus.cirrusinsight.com/api/v1alpha1/webhook-subscriptions" \
  -H "X-Cirrus-Api-Key: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "endpointUrl": "https://example.com/cirrus-webhook",
    "events": [
      "scheduling.smartscheduler.scheduled",
      "scheduling.smartscheduler.rescheduled",
      "scheduling.smartscheduler.canceled"
    ],
    "description": "Production booking sync"
  }'
python
import requests

response = requests.post(
    "https://altus.cirrusinsight.com/api/v1alpha1/webhook-subscriptions",
    headers={"X-Cirrus-Api-Key": token},
    json={
        "endpointUrl": "https://example.com/cirrus-webhook",
        "events": [
            "scheduling.smartscheduler.scheduled",
            "scheduling.smartscheduler.rescheduled",
            "scheduling.smartscheduler.canceled",
        ],
        "description": "Production booking sync",
    },
)
response.raise_for_status()
subscription = 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
{
    endpointUrl = "https://example.com/cirrus-webhook",
    events = new[]
    {
        "scheduling.smartscheduler.scheduled",
        "scheduling.smartscheduler.rescheduled",
        "scheduling.smartscheduler.canceled",
    },
    description = "Production booking sync",
};

var request = new HttpRequestMessage(
    HttpMethod.Post,
    "https://altus.cirrusinsight.com/api/v1alpha1/webhook-subscriptions")
{
    Content = new StringContent(
        JsonSerializer.Serialize(body),
        Encoding.UTF8,
        "application/json"),
};

var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
var subscription = await response.Content.ReadAsStringAsync();
json
{
  "id": "sub_...",
  "endpointUrl": "https://example.com/cirrus-webhook",
  "events": [
    "scheduling.smartscheduler.scheduled",
    "scheduling.smartscheduler.rescheduled",
    "scheduling.smartscheduler.canceled"
  ],
  "status": "validating",
  "description": "Production booking sync",
  "createdAt": "2026-06-10T14:22:01Z",
  "signingSecret": "whsec_...",
  "signingSecretNote": "Save this now — it will not be shown again."
}

Get a webhook subscription

GET /api/v1alpha1/webhook-subscriptions/{subscriptionId}

Returns one subscription's current state.

Path parameters

ParameterTypeDescription
subscriptionIdstringSubscription ID, prefixed sub_.

Response

200 OK with the same shape as one entry in the list response (no signingSecret).

Errors

  • 404 webhook-subscription-not-found — the subscription does not exist or does not belong to this org

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

subscription_id = "sub_01H8YKQ2N9WEBHK"
response = requests.get(
    f"https://altus.cirrusinsight.com/api/v1alpha1/webhook-subscriptions/{subscription_id}",
    headers={"X-Cirrus-Api-Key": token},
)
response.raise_for_status()
subscription = 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 subscriptionId = "sub_01H8YKQ2N9WEBHK";
var response = await client.GetAsync(
    $"https://altus.cirrusinsight.com/api/v1alpha1/webhook-subscriptions/{subscriptionId}");
response.EnsureSuccessStatusCode();
var subscription = await response.Content.ReadAsStringAsync();

Delete a webhook subscription

DELETE /api/v1alpha1/webhook-subscriptions/{subscriptionId}

Path parameters

ParameterTypeDescription
subscriptionIdstringSubscription ID, prefixed sub_.

Response

204 No Content on success. The subscription is soft-deleted — the audit trail is preserved, but the row is no longer visible to any endpoint and subsequent events are not delivered to it.

Deleting an already-deleted subscription also returns 204. DELETE states a desired end condition; a retry after a client timeout succeeds silently.

There is no PATCH endpoint in v1 — to change a subscription's URL or event set, delete it and create a new one.

Errors

  • 404 webhook-subscription-not-found — the subscription is not visible to this org (never existed, or belongs to another org)

bash
curl -s -X DELETE "https://altus.cirrusinsight.com/api/v1alpha1/webhook-subscriptions/sub_01H8YKQ2N9WEBHK" \
  -H "X-Cirrus-Api-Key: $TOKEN"
python
import requests

subscription_id = "sub_01H8YKQ2N9WEBHK"
response = requests.delete(
    f"https://altus.cirrusinsight.com/api/v1alpha1/webhook-subscriptions/{subscription_id}",
    headers={"X-Cirrus-Api-Key": token},
)
response.raise_for_status()
csharp
using System.Net.Http;
using System.Net.Http.Headers;

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

var subscriptionId = "sub_01H8YKQ2N9WEBHK";
var response = await client.DeleteAsync(
    $"https://altus.cirrusinsight.com/api/v1alpha1/webhook-subscriptions/{subscriptionId}");
response.EnsureSuccessStatusCode();

List delivery attempts

GET /api/v1alpha1/webhook-subscriptions/{subscriptionId}/deliveries

Returns the history of delivery attempts for a subscription, ordered most-recent first. Useful for diagnosing missed events or failed deliveries.

Query parameters

ParameterTypeDescription
cursorstringPagination cursor.
limitnumberPage size. Default 25, clamped to 1–100.
sortstringattemptedAt only, prefix - for descending. Default -attemptedAt.
statusstring(optional, repeatable) succeeded | failed | pending.
eventTypestring(optional) Filter to one event type.
sincestring(optional) ISO 8601 UTC timestamp. Deliveries after this time only. Max lookback 90 days.
correlationIdstring(optional) Match a specific event's retry chain — every delivery for one event shares one correlation id.

Response

Delivery items omit request and response bodies to keep list responses small.

Failed deliveries (status: "failed") are automatically retried with exponential backoff for up to 24 hours; see Webhook Lifecycle for the retry policy.

Errors

  • 404 webhook-subscription-not-found — the subscription is not visible to this org
bash
curl -s "https://altus.cirrusinsight.com/api/v1alpha1/webhook-subscriptions/sub_01H8YKQ2N9WEBHK/deliveries?limit=25&status=failed" \
  -H "X-Cirrus-Api-Key: $TOKEN"
python
import requests

subscription_id = "sub_01H8YKQ2N9WEBHK"
response = requests.get(
    f"https://altus.cirrusinsight.com/api/v1alpha1/webhook-subscriptions/{subscription_id}/deliveries",
    headers={"X-Cirrus-Api-Key": token},
    params={"limit": 25, "status": "failed"},
)
response.raise_for_status()
page = response.json()
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 subscriptionId = "sub_01H8YKQ2N9WEBHK";
var query = HttpUtility.ParseQueryString(string.Empty);
query["limit"] = "25";
query["status"] = "failed";

var uri = new UriBuilder(
    $"https://altus.cirrusinsight.com/api/v1alpha1/webhook-subscriptions/{subscriptionId}/deliveries")
{
    Query = query.ToString()
}.Uri;

var response = await client.GetAsync(uri);
response.EnsureSuccessStatusCode();
var page = await response.Content.ReadAsStringAsync();
json
{
  "items": [
    {
      "id": "wd_...",
      "eventType": "scheduling.smartscheduler.scheduled",
      "eventId": "mtg_...",
      "correlationId": "corr_...",
      "attemptNumber": 1,
      "status": "succeeded",
      "responseCode": 200,
      "responseTimeMs": 87,
      "attemptedAt": "2026-07-28T09:12:00Z",
      "nextRetryAt": null
    },
    {
      "id": "wd_...",
      "eventType": "scheduling.smartscheduler.canceled",
      "eventId": "mtg_...",
      "correlationId": "corr_...",
      "attemptNumber": 3,
      "status": "failed",
      "responseCode": null,
      "responseTimeMs": null,
      "attemptedAt": "2026-07-28T08:33:01Z",
      "nextRetryAt": "2026-07-28T08:38:01Z"
    }
  ],
  "nextCursor": "eyJmaWVsZCI6ImF0dGVtcHRlZEF0Iiw..."
}

Raleigh, NC — a Cirruspath, Inc. company