# Real-Time Scheduling

#### Description
Returns a URL to a form where a user can select their preferred date and time for an event based upon live availability information.

#### URL format
```
{data_center_url}/v1/real_time_scheduling
```

#### Example Request
```http
POST /v1/real_time_scheduling HTTP/1.1
Host: {data_center_url}
Authorization: Bearer {API_KEY}
Content-Type: application/json; charset=utf-8

{
  "oauth": {
    "redirect_uri": "{REDIRECT_URI}",
  },
  "event": {
    "event_id": "qTtZdczOccgaPncGJaCiLg",
    "summary": "Product Manager Interview at Globex",
    "tzid": "Europe/London"
  },
  "availability": {
    "participants": [
      {
        "members": [
          {
            "sub": "acc_5ba21743f408617d1269ea1e",
            "calendar_ids": ["cal_n23kjnwrw2_jsdfjksn234"]
          }
        ],
        "required": "all"
      }
    ],
    "required_duration": { "minutes": 60 },
    "query_periods": [
      { "start": "2026-04-28T09:00:00Z", "end": "2026-04-28T18:00:00Z" }
    ]
  },
  "target_calendars": [
    {
      "sub": "acc_5ba21743f408617d1269ea1e",
      "calendar_id": "cal_n23kjnwrw2_jsdfjksn234"
    }
  ],
  "callback_urls": {
    "completed_url": "http://www.example.com/callback",
    "no_times_suitable_url": "http://www.example.com/callback"
  },
  "redirect_urls": {
    "completed_url": "http://www.example.com/success"
  },
  "selection_mode": "no_confirm"
}
```

#### Example Response
```http
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "real_time_scheduling": {
    "real_time_scheduling_id": "sch_64b1859e8090ea21640c915f",
    "url": "{REAL_TIME_SCHEDULING_URL}"
  }
}
```

#### Request parameters
##### `data_center_url` *(required)*

The URL for the data center you want to communicate with. Possible choices are:

- `api-au.cronofy.com` - Australia
- `api-ca.cronofy.com` - Canada
- `api-de.cronofy.com` - Germany
- `api-sg.cronofy.com` - Singapore
- `api-uk.cronofy.com` - United Kingdom
- `api.cronofy.com` - United States

Find out more about [Cronofy's data centers](/developers/data-centers/index.md).
##### `API_KEY` *(required)*

The `client_secret` of the client.

##### `oauth.redirect_uri` *(required)*

The HTTP or HTTPS URI you wish the user to be redirected to after their Real-Time Scheduling journey.

##### `event` *(required)*

An object with the details of the event you wish to push into the user's selected calendar. Details of what parameters this object can hold can be found in the [create or update event](/developers/api/events/upsert-event/index.md) documentation.

**Note:**

- `event.attendees` are only supported when [`event_creation`](#event_creation) is set to `single`.

- `event.conferencing` only supports [built-in](/developers/api/conferencing-services/create/index.md) values. You *may* reference specific conferencing profiles for different organizers within [the `target_calendars.event.conferencing` parameter](#param-target_calendars.event.conferencing).

- [Attachments](/developers/api/attachments/index.md) and [Subscriptions](/developers/api/conferencing-services/subscriptions/index.md) are supported as normal.

- When a group requires only some of the members, the order the members are listed in will be used as a soft-preference for who is selected. If you want to evenly distribute events to members across several tokens, you should shuffle this list so each request has the members in a random order.

##### `event.tzid` *(required)*

The time zone to render the event with.

The `start` and `end` parameters should be omitted.

##### `availability` *(required)*

An object with the details of the availability query used to determine the available time periods for the user to choose for the event's date and time. Details of what parameters this object can hold can be found in the [Availability](/developers/api/scheduling/availability/index.md) documentation.

`availability.start_interval` and `availability.response_format` both have an impact on the possible slots presented to the user and are discussed below.

##### `availability.start_interval` *(optional)*

A [`Duration`](/developers/api/data-types/index.md) describing the frequency that a sequence can start on.

For example, "every hour" or "every 15 minutes".

Must be an increment of one of `5`, `10`, `15`, `20`, `30`, or `60` minutes.

By default Real Time Scheduling will use the required duration to derive the interval of slots. For example, 60 minute slots will begin on the hour

- 9:00am – 10:00am

- 10:00am – 11:00am

- 11:00am – 12:00pm

This works well when a calendar is mostly free, however if an hour-long meeting at 9:30am - 10:30am is scheduled we would only have the 11am slot available.

<li class="busy">9:00am – 10:00am</li>
<li class="busy">10:00am – 11:00am</li>
- 11:00am – 12:00pm

To avoid this problem, we can set the slots to begin every 30 minutes for the same period of time would mean the following would be selectable.

<li class="busy">9:00am – 10:00am</li>
<li class="busy">9:30am – 10:30am</li>
<li class="busy">10:00am – 11:00am</li>
- 10:30am – 11:30am

- 11:00am – 12:00pm

##### `availability.response_format` *(optional)*

A [`String`](/developers/api/data-types/index.md) which controls the generation of available slots. Can be one of the following values:

- `slots` - Default, slots are considered per `availability.start_interval` but won't overlap

- `overlapping_slots` - slots are considered per `availability.start_interval` and *can* overlap

##### `minimum_notice` *(optional)*

A [`Duration`](/developers/api/data-types/index.md). No slots starting before the period described after the current time will be displayed to the user when they select slots.

##### `event_creation` *(optional)* **BETA**

One of two values:

- `default` or omitted - creates an event in each calendar listed in the [`target_calendars`](#target_calendars) list.

- `single` - creates an event in one target calendar - if multiple [`target_calendars`](#target_calendars) are a match for the selected slot, then the order of the participants in the [availability query](#availability) is used to choose the preferred calendar.

You can use this capability along with `event.attendees` and `target_calendars.attendee` to set a primary event owner and set all other people as event attendees.

Please see the [fully worked example below](#event-creation-example).

##### `target_calendars` *(optional)*

An array of mappings between Cronofy `sub` values and calendar IDs into which the final event will be inserted, along with other per-account event overrides.

Required for Cronofy to create events.

> **INFO:** When adding multiple calendars where the `calendar_ids` belong to the same `sub`, the event will only be created on one of those calendars and not all provided ones.

##### `target_calendars.sub` *(required)*

The internal Cronofy ID for the account, as an ASCII-only [`String`](/developers/api/data-types/index.md).

##### `target_calendars.calendar_id` *(required)*

The `calendar_id` of the calendar you wish the event to be added to. This ID should belong to one of the profiles attached to the account identified by the `sub`.

##### `target_calendars.attendee` *(optional)*

Required for the account to be added to an event as an attendee based on presence in the result of the Availability Query.

Only used, and only allowed, when `event_creation` is set to `single`.

##### `target_calendars.attendee.email` *(required)*

The email address associated with the attendee as a `String`.

##### `target_calendars.attendee.display_name` *(optional)*

A human-friendly name associated with the attendee as a `String`, may be `null`.

##### `target_calendars.event` *(optional)*

Overrides to the event template used when the account is selected as the organizer of the event.

Only used, and only allowed, when `event_creation` is set to `single`.

##### `target_calendars.event.conferencing` *(optional)*

You may override the conferencing for the event on a per-organizer basis. This allows you to have multiple potential event organizers, each with their own personal conferencing profile. The format follows the [format used when specifying conferencing on an event](/developers/api/conferencing-services/create/index.md).

##### `formatting.hour_format` *(optional)*

A [`String`](/developers/api/data-types/index.md) of either `h` (12-hour format) or `H` (24-hour format). If omitted then the hour format to use will be determined by Cronofy.

##### `callback_url` *(optional)*

Deprecated. An alias for `callback_urls.completed_url`.

##### `callback_urls.completed_url` *(optional)*

A URL to call when a slot has been chosen and the full event details are known.

##### `callback_urls.no_times_displayed_url` *(optional)*

A URL to call when the user was shown a page with no available times.

##### `callback_urls.no_times_suitable_url` *(optional)*

A URL to call when the user indicates that none of the available times are suitable for them.

##### `redirect_urls.completed_url` *(optional)*

A URL to redirect the user to when the user has completed the process and chosen a slot.

A query string parameter of `token` will be added to this URL. The `token` can be used to retrieve the [current status](/developers/api/scheduling/real-time-scheduling/status/index.md) of a Real Time Scheduling link.

##### `selection_mode` *(optional)*

A [`String`](/developers/api/data-types/index.md) indicating how users select their time slot. Supports the following options:

- `no_confirm` (Default) - Selecting a time books the event immediately

- `confirm` - The user is taken to a confirmation page after selecting a time, before the event is booked

#### Response parameters
##### `real_time_scheduling.real_time_scheduling_id`

The Cronofy unique identifier for the Real Time Scheduling link.

##### `real_time_scheduling.url`

The URL to direct the user to in order to authorize their calendar account and have the event inserted into their selected calendar.

### Callback notifications
##### Example Time Chosen callback
```http
POST {CALLBACK_URL_PATH} HTTP/1.1
Host: {CALLBACK_URL_HOST}
Content-Type: application/json; charset=utf-8
Cronofy-HMAC-SHA256: {Base64(HmacSHA256(body_bytes, CLIENT_SECRET))}

{
  "notification": {
    "type": "real_time_scheduling_time_chosen"
  },
  "user": {
    "tzid": "Europe/Paris"
  },
  "event": {
    "event_id": "qTtZdczOccgaPncGJaCiLg",
    "start": {
      "time": "2026-04-28T10:00:00Z",
      "tzid": "Europe/London"
    },
    "end": {
      "time": "2026-04-28T11:00:00Z",
      "tzid": "Europe/London"
    },
    "summary": "Product Manager Interview at Globex"
  },
  "participants": [
    { "sub": "acc_5ba21743f408617d1269ea1e" }
  ]
}
```

##### Example No Times Displayed callback
```http
POST {CALLBACK_URL_PATH} HTTP/1.1
Host: {CALLBACK_URL_HOST}
Content-Type: application/json; charset=utf-8
Cronofy-HMAC-SHA256: {Base64(HmacSHA256(body_bytes, CLIENT_SECRET))}

{
  "user": {
    "tzid": "Europe/Paris"
  },
  "notification": {
    "type": "real_time_scheduling_no_times_displayed"
  }
}
```

##### Example No Times Suitable callback
```http
POST {CALLBACK_URL_PATH} HTTP/1.1
Host: {CALLBACK_URL_HOST}
Content-Type: application/json; charset=utf-8
Cronofy-HMAC-SHA256: {Base64(HmacSHA256(body_bytes, CLIENT_SECRET))}

{
  "user": {
    "tzid": "Europe/Paris"
  },
  "notification": {
    "type": "real_time_scheduling_no_times_suitable"
  }
}
```

#### Callback request headers
##### `Cronofy-HMAC-SHA256`

Can optionally be used to verify that the notification was sent by Cronofy.

This [HMAC](https://en.wikipedia.org/wiki/Hash-based_message_authentication_code) uses the SHA256 algorithm, keyed with the application's client secret, to generate a Base64 encoded hash of the request body.

When an application has multiple active client secrets, a value is generated for each active secret, separated by commas. For example:

```
Cronofy-HMAC-SHA256: {HMAC_FROM_SECRET_1},{HMAC_FROM_SECRET_2}
```

Examples are available in the [cronofy/notification-hmac-examples](https://github.com/cronofy/notification-hmac-examples) GitHub repository.
#### Callback request parameters
##### `notification.type`

A value of indicating the reason for the notification.

One of:

- `real_time_scheduling_no_times_displayed`

- `real_time_scheduling_no_times_suitable`

- `real_time_scheduling_time_chosen`

##### `user.tzid` *(optional)*

An parameter that indicates the time zone of the user that triggered the callback, or the time zone that we were able to automatically detect for the user.

##### `event` *(optional)*

An object with the details of the event created by an available time slot being selected. Details of what parameters this object can hold can be found in the [create or update event](/developers/api/events/upsert-event/index.md) documentation.

Only provided with `real_time_scheduling_time_chosen` notifications.

##### `participants` *(optional)*

An array of all the participants which were selected for the event based on their availability.

Only provided with `real_time_scheduling_time_chosen` notifications.

#### Localization
The scheduling page displayed when a user navigates to the Real Time Scheduling URL will detect the user's browser locale and render accordingly.

Currently supported locales are:

- `ar` Arabic

- `cs` Czech

- `cy` Welsh

- `de` German

- `en` US English (default)

- `es` Spanish

- `fr` French

- `fr-CA` Canadian French

- `he` Hebrew

- `it` Italian

- `ja` Japanese

- `nl` Dutch

- `pl` Polish

- `pt-BR` Brazilian Portuguese

- `ru` Russian

- `sv` Swedish

- `tr` Turkish

- `zh-CN` Simplified Chinese

Use of one of the supported locales can be forced by adding a `locale` query string parameter to the Real Time Scheduling URL, for example:

```
https://app.cronofy.com/add_to_calendar/scheduling/p6Ht4P6_4svo1nrjpIY738bdfk?locale=de```
#### Event creation example
##### Scenario
You wish to provide a booking page for an interview:

- The candidate is known by email but not synchronized in Cronofy. They'll be sent the URL to select a time.

- The recruitment panel contains three members, of which *two* are required to perform the interview.

- Each interviewer has their own preference for conferencing.

##### Payload
```http
POST /v1/real_time_scheduling HTTP/1.1
Host: {data_center_url}
Authorization: Bearer {API_KEY}
Content-Type: application/json; charset=utf-8

{
  "oauth": {
    "redirect_uri": "{REDIRECT_URI}"
  },
  "event_creation": "single",
  "event": {
    "event_id": "ri4vch-45fsd",
    "summary": "Interview panel stage",
    "tzid": "Europe/London",
    "attendees": {
      "invite": [
        {
          "email": "candidate@example.com",
          "display_name": "Jim Candidate"
        }
      ]
    }
  },
  "availability": {
    "participants": [
      {
        "members": [
          {
            "sub": "acc_5e591ae2815c14f86ea55caf"
          },
          {
            "sub": "acc_61092b71f5aa93c71280b010"
          },
          {
            "sub": "acc_61115004f5aa93bb48fc5dd3"
          }
        ],
        "required": 2
      }
    ],
    "required_duration": {
      "minutes": 60
    },
    "available_periods": [
      {
        "start": "2026-04-28T09:00:00Z",
        "end": "2026-04-28T18:00:00Z"
      }
    ]
  },
  "target_calendars": [
    {
      "sub": "acc_5e591ae2815c14f86ea55caf",
      "calendar_id": "cal_Xlka34FcFPhupVxZ_K@fbCQqIXfoVEHSVR06mpg",
      "event": {
        "conferencing": {
          "profile_id": "pro_YABpIfWqk4wjcW5t"
        }
      },
      "attendee": {
        "email": "marty@evenitron.com",
        "display_name": "Marty McFly"
      }
    },
    {
      "sub": "acc_61092b71f5aa93c71280b010",
      "calendar_id": "cal_YQkrbPWqk8cSgLAG_o@ZiqDLP1-zjzDl6zhXwFg",
      "event": {
        "conferencing": {
          "profile_id": "integrated"
        }
      },
      "attendee": {
        "email": "doc@evenitron.com",
        "display_name": "Doc Brown"
      }
    },
    {
      "sub": "acc_61115004f5aa93bb48fc5dd3",
      "calendar_id": "cal_YRFQA@Wqk7tI@F3J_3X4Nll-hxnkdz-wlOTkhIw",
      "event": {
        "conferencing": {
          "profile_id": "integrated"
        }
      },
      "attendee": {
        "email": "sarah@evenitron.com",
        "display_name": "Sarah Connor"
      }
    }
  ],
  "redirect_urls": {
    "completed_url": "https://www.example.com/success"
  }
}
```

##### Notes
Taking each section in turn:

- `&quot;event_creation&quot;: &quot;single&quot;` instructs Cronofy to create a single event in one calendar, and add others as attendees to that event.

- In the `event`, the candidate is listed as an attendee. They will always be invited to the created event as a result.

- `availability` defines the parameters of valid slot choices. The event will be one hour long. Two out of three possible interviewers are required, listed in the `members` array.
<li>We will present slots where any two are available. [One interviewer](/developers/api/scheduling/real-time-scheduling/index.md) will be selected as the organizer of the event, and the other interviewer will be added as an attendee.

- The Real Time Scheduling link's expiration date will match the `query_periods.end`.

</li>
- `target_calendars` lists the same interviewers as present in `availability`.
<li>Which of their calendars the event will be placed in if they are selected as the event organizer (`calendar_id`).

- Overrides to the event if they are selected as the event organizer - allowing each interviewer to specify their own conferencing solution (`event.conferencing`).

- How the interviewer is added to the event as an attendee if they are included in, but not the organizer of, the created event (`attendee`).

</li>

---
[Read in HTML](/developers/api/scheduling/real-time-scheduling/)

## In this section

- [Disable](/developers/api/scheduling/real-time-scheduling/disable/index.md) — Disables a Real Time Scheduling link.
- [Status](/developers/api/scheduling/real-time-scheduling/status/index.md) — Retrieves the current state of a Real Time Scheduling link.
