# Calendly webhook trigger

> Start a workflow when a Calendly invitee schedules or cancels a meeting: setup, events, payload shape, and signature verification.

Source: https://cotera.co/docs/reference/webhooks/calendly

---

Run a workflow when a Calendly invitee schedules or cancels a meeting. The invitee event — who booked, which event type, when — becomes the workflow's input.

For behavior shared by every provider (the delivery URL, deduplication, testing), see the [webhook triggers reference](https://cotera.co/docs/reference/webhooks.md).

## Prerequisites

Calendly webhooks are **auto-registered**: Cotera creates the webhook subscription in Calendly for you over its API. That requires a connected Calendly account first.

* **apiKey** `string` — a Calendly Personal Access Token. Create one under **Integrations & Apps → [API & Webhooks](https://calendly.com/integrations/api_webhooks) → Personal Access Tokens**. Organization-scoped subscriptions require an admin token.

If no Calendly account is connected when you add the trigger, install fails with `calendly_credentials_missing`.

## Setup

1. Add a **From an app** trigger to your workflow and pick **Calendly**.
2. Choose the event: **Invitee created** or **Invitee canceled**.
3. Save. Cotera registers an organization-scoped `webhook_subscription` with Calendly pointed at the trigger's unique URL, signed with the trigger's Cotera-generated key.

Deleting the trigger tears the subscription back down in Calendly, so you don't leave orphaned webhooks behind.

## Events

| Event key          | Fires when                           | Calendly event type |
| ------------------ | ------------------------------------ | ------------------- |
| `invitee.created`  | An invitee schedules an event        | `invitee.created`   |
| `invitee.canceled` | An invitee cancels a scheduled event | `invitee.canceled`  |

Neither event needs extra configuration.

## Payload

The raw Calendly delivery is passed straight through as the workflow input. An `invitee.created` delivery looks like:

```json
{
  "event": "invitee.created",
  "created_at": "2023-07-15T10:30:00.000000Z",
  "payload": {
    "uri": "https://api.calendly.com/scheduled_events/EVENT/invitees/INVITEE",
    "email": "jane@example.com",
    "name": "Jane Doe",
    "status": "active",
    "event": "https://api.calendly.com/scheduled_events/EVENT",
    "scheduled_event": {
      "uri": "https://api.calendly.com/scheduled_events/EVENT",
      "name": "30 Minute Meeting",
      "start_time": "2023-07-20T15:00:00.000000Z",
      "end_time": "2023-07-20T15:30:00.000000Z"
    }
  }
}
```

| Field                            | Description                                                                    |
| -------------------------------- | ------------------------------------------------------------------------------ |
| `event`                          | The event type — `invitee.created` or `invitee.canceled`.                      |
| `created_at`                     | When Calendly emitted the event.                                               |
| `payload.uri`                    | The invitee's Calendly URI. Cotera uses it to deduplicate repeated deliveries. |
| `payload.email` / `payload.name` | The invitee's contact details.                                                 |
| `payload.status`                 | `active` for a booking, `canceled` for a cancellation.                         |
| `payload.scheduled_event`        | The meeting: name, and `start_time` / `end_time` in UTC.                       |

An `invitee.canceled` delivery has the same shape with `event: "invitee.canceled"` and `payload.status: "canceled"`.

## Signature verification

Calendly signs each delivery with the trigger's signing key and sends the signature in the `Calendly-Webhook-Signature` header, in the form:

```
Calendly-Webhook-Signature: t=<timestamp>,v1=<hex-hmac>
```

The signature is an HMAC-SHA256, in hexadecimal, over the string `<timestamp>.<raw-request-body>`. Cotera recomputes and verifies it on every delivery — a request with a missing or invalid signature is rejected before your workflow runs. You don't handle any of this yourself.

