# Scheduling Request webhooks

## Receiving webhooks
Cronofy sends a webhook to your application whenever one of its Scheduling Requests changes, however the request was created. Where the webhook URL is set depends on how you integrate; for example, the [Scheduler Embed](https://docs.cronofy.com/api-reference/managed-scheduling/embedded-scheduler/installing-and-embedding/index.md) sets it in your application's settings.

All webhooks sent from Cronofy include a HMAC header described in [Webhook authentication](https://docs.cronofy.com/api-reference/authorization/webhook-authentication/index.md). This header can be used to verify the notification was sent by Cronofy and has not been tampered with.

### Webhook example
```json
{
  "scheduling_request": {
      "scheduling_request_id": "srq_80f7fece4f37897d62d86d80",
      "slot_selection": "complete",
      "primary_select_url": "https://app.cronofy.com/rts/LOiwlKXQ",
      "dashboard_url": "https://app.cronofy.com/scheduler/requests/80f7fece4f37897d62d86d80",
      "summary": "Product Manager Interview at Globex",
      "recipient_operations": {
          "view_url": "https://app.cronofy.com/rts/LOiwlKXQ",
          "decline_url": "https://app.cronofy.com/rts/LOiwlKXQ?reschedule=true",
          "reschedule_url": "https://app.cronofy.com/rts/LOiwlKXQ?decline=true"
      },
      "recipients": [
        {
          "email": "eb@example.com",
          "display_name": "Dr Emmet Brown",
          "slot_selector": true,
          "select_url": "https://app.cronofy.com/rts/1234abc"
        }
      ],
      "collaborators": [
        {
          "sub": "acc_64b17d868090ea21640c914c"
        }
      ],
      "event": {
          "start": {
            "time": "2026-11-14T15:30:00Z",
            "tzid": "Europe/London"
          },
          "end": {
            "time": "2026-11-14T17:00:00",
            "tzid": "Europe/London"
          },
          "summary": "Product Manager Interview at Globex",
          "metadata": {
            "scheduler": {
                "correlation_id": "foobar"
            }
          },
          "host": {
            "email": "host@example.com",
            "display_name": "example user",
            "sub": "acc_64b17d868099ea21640c914b",
            "status": "accepted"
          },
          "attendees": [
            {
             "email": "invite@example.com",
             "display_name": "example user",
             "status": "needs_action"
            },
            {
             "email": "collaborator@example.com",
             "display_name": "example user",
             "status": "needs_action",
             "sub": "acc_64b17d868090ea21640c914c"
            }
          ]
      },
      "duration": {
        "minutes": 30
      },
      "coordinator_sub": "acc_64b17d868099ea21640c914b",
      "metadata": {
        "scheduler": {
          "correlation_id": "foobar"
        }
      }
  },
  "notification": {
      "type": "scheduling_request_time_chosen",
      "triggered_at": "2026-11-11T09:24:16Z"
  }
}
```

The notifications types are:

- `scheduling_request_time_chosen` - When an initial time slot is selected via the link

- `scheduling_request_rescheduled` - When the time of a scheduled Request changes, either because the recipient chose a new time via the link, or because the host moved the event in their own calendar. `notification.subtype` tells you which

- `scheduling_request_cancelled` - When a Request is cancelled

- `scheduling_request_declined` - When a Request is declined by the recipient

- `scheduling_request_host_declined` - When a Request is declined by the host

- `scheduling_request_event_edited` - When a Request event is edited through the dashboard

- `scheduling_request_recipient_unavailable` - When the recipient clicks the "I can't do any of those days" button on the slot selection page, indicating they aren't available for any of the offered times.

- `scheduling_request_more_times_requested` - When no availability can be found for this request and the recipient presses the "Request more times" button to ask the host to make more times available.

`notification.triggered_at` is the timestamp of when the webhook was triggered. If Cronofy receives a HTTP error status when trying to send your application a webhook, it will backoff and retry. Failed notifications will be retried for several hours, so this timestamp can be used to establish notifications which have been superseded already.

### Notification subtypes
Some notifications carry a `notification.subtype` that tells you what caused them. Not every notification has one, and this list will be extended over time, so treat any value you do not recognize as unknown.

For `scheduling_request_rescheduled`:

- `with_select_url` - The recipient chose a new time through their scheduling link

- `host_calendar_change` - The host moved the event in their own calendar

For `scheduling_request_cancelled`:

- `recipient_declined` - The recipient declined the Request, which cancelled its events

```json
{
  "notification": {
      "type": "scheduling_request_rescheduled",
      "subtype": "host_calendar_change",
      "triggered_at": "2026-11-11T09:24:16Z"
  }
}
```

The schema of `scheduling_request` can be found in [Scheduling Request query](https://docs.cronofy.com/api-reference/managed-scheduling/scheduling-requests/query/index.md) documentation.



---
[Read in HTML](https://docs.cronofy.com/api-reference/managed-scheduling/scheduling-requests/webhooks/)