# Availability Query

### Description
Inspects calendars to determine the common availability for people within the specified periods of time.

> **WARNING:** In order to use the availability API you must have been granted at least the `read_free_busy` scope for each participant you would like to be involved in the availability request.

If you have been granted the `read_events` scope, then you do not need to have both as `read_events` allows access to a higher level of information that covers the `read_free_busy` scope.

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

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

{
  "participants": [
    {
      "members": [
        {
          "sub": "acc_5ba21743f408617d1269ea1e",
          "managed_availability": true
         },
        {
          "sub": "acc_64b17d868090ea21640c914c",
          "managed_availability": true
        }
      ],
      "required": "all"
    },
    {
      "members": [
        { "sub": "res_5ba21743f408617d12693521" },
        { "sub": "res_5ba21743f4000563a26934ea" },
        { "sub": "res_64b17d868090ea21640ad6e0" }
      ],
      "required": 1
    }
  ],
  "required_duration": { "minutes": 60 },
  "query_periods": [
    {
      "start": "2026-04-23T09:00:00Z",
      "end": "2026-04-23T18:00:00Z"
    },
    {
      "start": "2026-04-24T09:00:00Z",
      "end": "2026-04-24T18:00:00Z"
    }
  ],
  "buffer": {
    "before": { "minutes": 30 },
    "after": { "minutes": 15 }
  },
  "response_format": "slots"
}
```

### Example Response
#### Slots
When a `response_format` of `slots` or `overlapping_slots` is specified, the response looks like this.

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

{
  "available_slots": [
    {
      "start": "2026-04-23T09:00:00Z",
      "end": "2026-04-23T10:00:00Z",
      "participants": [
        { "sub": "acc_5ba21743f408617d1269ea1e" },
        { "sub": "acc_64b17d868090ea21640c914c" },
        { "sub": "res_5ba21743f408617d12693521" },
        { "sub": "res_5ba21743f4000563a26934ea" }
      ]
    },
    {
      "start": "2026-04-24T10:00:00Z",
      "end": "2026-04-24T11:00:00Z",
      "participants": [
        { "sub": "acc_5ba21743f408617d1269ea1e" },
        { "sub": "acc_64b17d868090ea21640c914c" },
        { "sub": "res_64b17d868090ea21640ad6e0" }
      ]
    },
    {
      "start": "2026-04-24T11:00:00Z",
      "end": "2026-04-24T12:00:00Z",
      "participants": [
        { "sub": "acc_5ba21743f408617d1269ea1e" },
        { "sub": "acc_64b17d868090ea21640c914c" },
        { "sub": "res_64b17d868090ea21640ad6e0" }
      ]
    }
  ]
}
```

#### Periods
The default `response_format` of `periods` looks like this.

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

{
  "available_periods": [
    {
      "start": "2026-04-23T09:00:00Z",
      "end": "2026-04-23T11:00:00Z",
      "participants": [
        { "sub": "acc_5ba21743f408617d1269ea1e" },
        { "sub": "acc_64b17d868090ea21640c914c" },
        { "sub": "res_5ba21743f4000563a26934ea" }
      ]
    },
    {
      "start": "2026-04-24T11:00:00Z",
      "end": "2026-04-24T17:00:00Z",
      "participants": [
        { "sub": "acc_5ba21743f408617d1269ea1e" },
        { "sub": "acc_64b17d868090ea21640c914c" },
        { "sub": "res_64b17d868090ea21640ad6e0" }
      ]
    }
  ]
}
```

### 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.

##### `response_format` *(optional)*

This can be one of the following values:

- `periods`

- `slots`

- `overlapping_slots`

When not specified, and providing `query_periods`, the default response format is `periods`. In this case, `response_format` works in conjunction with [`start_interval`](#start_interval) to control the distribution of the periods/slots.

`periods` will generate contiguous available periods that are a minimum length of the `required_duration`.

`slots` will generate non-overlapping slots with length equal to the `required_duration`.

`overlapping_slots` will generate slots starting every `start_interval` irrespective of whether they overlap with length equal to the `required_duration`.

When using `query_slots` instead of `query_periods`, we'll always consider all provided slots, effectively behaving like `overlapping_slots`. `periods` is an invalid value in this case.

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

{
  ...
  "response_format": "overlapping_slots",
  "required_duration": { "minutes": 60 },
  "query_periods": [
    {
      "start": "2026-04-23T09:00:00Z",
      "end": "2026-04-23T18:00:00Z"
    }
  ],
  "start_interval": { "minutes": 30 }
}
```

This query will consider 1-hour slot times starting every 30 minutes, with the first slot being at 9AM UTC, then 9:30AM UTC, and so on - with the last slot being at 5PM UTC. Any of those slots would be returned, if available.

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

{
  ...
  "required_duration": { "minutes": 60 },
  "query_slots": [
    { "start": "2026-04-23T09:00:00Z" },
    { "start": "2026-04-23T10:00:00Z" },
    { "start": "2026-04-23T13:30:00Z" },
    { "start": "2026-04-23T14:30:00Z" }
  ]
}
```

This will return, at most, four 1-hour slots starting at the specified times, avoiding the need to use a complex combination of `query_periods` and `start_interval`, or post-processing of the response, to achieve the same result. No other slot times would be considered or returned.

##### `participants` *(required)*

An array of the groups of participants whose availability should be taken into account.

At least one group must be specified, a maximum of 10 accounts may be specified over a combination of groups.

##### `participants.members` *(required)*

An array of participants that should have their availability taken into account as part of this group.

At least one participant must be specified and you must have been granted the `read_free_busy` scope for each participant involved in the availability request.

Note that the `read_events` scope implicitly includes this scope as it allows access to a higher level of information than free/busy so you do not have to have both.

##### `participants.members.sub` *(required)*

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

This can be retrieved by calling the [UserInfo endpoint](/developers/api/identity/userinfo/index.md) with a valid `access_token`

##### `participants.members.available_periods` *(optional)*

An array of 1 to 50 available periods within which the member is available. If omitted it is assumed the member is available whenever they do not have a "busy" event in their calendar.

##### `participants.members.available_periods.start`

The`start` of an available period as a [`Time`](/developers/api/data-types/index.md).

It must represent a future point in time.

> **WARNING:** `available_periods.start` and `available_periods.end` must both be less than or equal to 201 days in the future.

##### `participants.members.available_periods.end`

The`end` of an available period as a [`Time`](/developers/api/data-types/index.md).

Must be at least **1 minute** after the corresponding `start` and within **35 days** of the earliest `start`.

##### `participants.members.calendar_ids` *(optional)*

Restricts the events contributing towards the members availability to those within the set of specified `calendar_id`s.

Calendars are chosen for each member in this order of precedence:

- if this property is present, then only the calendars specified are used. If an empty array is specified then no calendars are chosen and all events in the participants calendars are ignored.

- else, if [`managed_availability`](/developers/scheduling/managed-availability/index.md) is `true` for the member, the calendars from the relevant Availability Rule(s) are used

- else, all calendars for the member are considered

##### `participants.members.buffer` *(optional)*

Buffer values specific to this member. If specified are used instead of any top-level `buffer` when considering the member's availability.

##### `participants.members.buffer.before` *(optional)*

A [`Duration`](/developers/api/data-types/index.md) specifying the minimum number of minutes that must be free for this member before an available period starts.

##### `participants.members.buffer.after` *(optional)*

A [`Duration`](/developers/api/data-types/index.md) specifying the minimum number of minutes that must be free for this member after the available period ends.

##### `participants.members.availability_constraints` *(optional)*

An `Array` of constraints that must be satisfied for each slot or period.

##### `participants.members.availability_constraints.period` *(required)*

A `String` value specifying the time period over which the constraint is to be applied.

You can specify one of the following values:

- `day` will apply the constraint each day. You must also pass the `tzid` parameter to indicate which timezone you want to use to determine when a day starts and ends.

- `week` will apply the constraint over the period of a week. A week is considered to be Monday to Sunday in the UTC time zone, following the ISO standard.

##### `participants.members.availability_constraints.tzid` *(optional)*

A `String` value specifying the time zone to use when the `period` is set to `day`. Must be a known time zone identifier from the [IANA Time Zone Database](https://www.iana.org/time-zones). See the [time zones](/developers/calendars-events/time-zones/index.md) page for more information.

Currently specifying a time zone is only supported with the `day` constraint period.

##### `participants.members.availability_constraints.limit` *(required)*

An `Integer` value specifying the maximum number of events allowable per period. If `tags` are provided then limit will only consider events with all of the given tags.

Must be greater than zero.

##### `participants.members.availability_constraints.tags` *(optional)*

An `Object` describing zero or more contextual [`Tag`](/developers/api/data-types/index.md) values to search for against each event when searching for availability. Tags can be used with constraints to mark an events as being a specific event type, see the [Constraints](/developers/scheduling/constraints/index.md) page for more information.

If more than one tag is provided the events must have all of the specified tags to be considered.

Tags may be treated as an empty set by omitting the `tags` field, setting it to `null`, the empty object `{}`, or leaving the context as an empty array `{ &quot;private&quot;: [] }`.

The context of "private", as seen in the example below, is the only context currently supported.

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

{
  "participants":[{
      "members":[
        {
          "sub": "acc_5ba21743f408617d1269ea1e",
          "availability_constraints":[{
            "tags": {
              "private": [
                { "value": "Interview" }
              ]
            },
            "limit": 3,
            "period": "week"
          }]
        },
      ],
      "required": 1
  }],
  "required_duration": { "minutes": 30 },
  "query_periods": [
    {
      "start": "2026-04-23T09:00:00Z",
      "end": "2026-04-23T18:00:00Z"
    },
    {
      "start": "2026-04-24T09:00:00Z",
      "end": "2026-04-24T18:00:00Z"
    }
  ]
}
```

Tags on events are managed via the [create or update](/developers/api/events/upsert-event/index.md) event endpoint.

##### `participants.members.managed_availability` *(optional)*

A [`Boolean`](/developers/api/data-types/index.md) specifying whether [managed availability](/developers/scheduling/managed-availability/index.md) should be taken into account for this member.

If set to `true` and no Managed Availability models are valid (for example, no [Availability Rules](/developers/api/scheduling/availability-rules/index.md) have been created or all of the [Available Periods](/developers/api/scheduling/available-periods/index.md) do not overlap with the `query_periods`), then no slots will be returned. That's because there is nothing to make times viable.

##### `participants.members.only_managed_events` *(optional)*

A [`Boolean`](/developers/api/data-types/index.md) specifying whether to to only consider events that you are managing when determining busy times for this member. Defaults to `false`.

##### `participants.members.ignore_tentative` *(optional)*

A [`Boolean`](/developers/api/data-types/index.md) specifying whether events where the user is marked as tentatively attending will be considered as free periods or not. By default these events are considered as busy periods.

##### `participants.members.ignored_extended_transparencies` *(optional)*

An `Array` of string values specifying whether events where the user has set an [extended transparency](/developers/api/events/read-events/index.md) will be considered as free periods or not.

Valid values are `&quot;out_of_office&quot;`, `&quot;working_elsewhere&quot;` and `&quot;tentative&quot;`.

If not set, or set to an empty `Array` (i.e. `[]`) then these events are considered as busy periods by default.

##### `participants.members.availability_rule_ids` *(optional)*

An `Array` of `availability_rule_id` values referencing [`Availability Rules`](/developers/api/scheduling/availability-rules/index.md) stored against the `Account`.

If not specified or set to `null`, all availability rules stored against the `Account` will be used.

If an empty `Array` is specified, ie `[]` then all availability rules stored against the `Account` will be ignored.

##### `participants.required` *(required)*

Either a [`String`](/developers/api/data-types/index.md) of `all` to specify that all `members` of the group need to be available for a period to be viable, or an [`Integer`](/developers/api/data-types/index.md) to specify the minimum number of the group that must be available.

##### `required_duration` *(required)*

A [`Duration`](/developers/api/data-types/index.md) describing the minimum period that the participant groups must be satisfied for a period to be deemed as available.

Must be greater than zero minutes in length.

##### `query_periods` *(optional)*

> **WARNING:** Either `query_periods` or `query_slots` must be specified.

An array of 1 to 50 query periods, across up to 35 days of the period of synchronized events, within which suitable matches may be found.

##### `query_periods.start` *(required)*

The `start` of a query period as a [`Time`](/developers/api/data-types/index.md).

It must represent a future point in time.

##### `query_periods.end` *(required)*

The `end` of a query period as a [`Time`](/developers/api/data-types/index.md).

Must be at least **1 minute** after the corresponding `start` and within **35 days** of the earliest `start`.

##### `query_slots` *(optional)*

> **WARNING:** Either `query_periods` or `query_slots` must be specified.

An array of 1 to 50 slot times, across up to 35 days of the period of synchronized events, within which suitable matches may be found.

This is an alternative to specifying `query_periods`, giving you more control over the exact slot times considered.

##### `query_slots.start` *(required)*

The `start` of a query slot as a [`Time`](/developers/api/data-types/index.md).

It must represent a future point in time. The `end` is unspecified, as it is implicit based on the value of the `required_duration` parameter.

##### `available_periods` *(alias)*

This is an alias for [query_periods](#param-query_periods) to maintain backwards compatibility. `available_periods` is the original name for `query_periods` and both represent the same concept, but `query_periods` makes the intent clearer.

We will not remove support for using `available_periods` but it is recommended to use `query_periods`.

##### `buffer.before` *(optional)*

A [`Duration`](/developers/api/data-types/index.md) specifying the minimum number of minutes that must be free before the available period starts.

##### `buffer.after` *(optional)*

A [`Duration`](/developers/api/data-types/index.md) specifying the minimum number of minutes that must be free after the available period ends.

##### `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 one of `5`, `10`, `15`, `20`, `30`, or `60` minutes.

This value is only relevant when using `query_periods`, and is ignored when `query_slots` are passed instead.

##### `max_results` *(optional)*

An [`Integer`](/developers/api/data-types/index.md) describing the maximum number of available periods or slots to return from the query.

Must be between `1` and `512` inclusive. If not provided up to `20` results will be returned.

##### `include_member_statuses` *(optional)*

A [`Boolean`](/developers/api/data-types/index.md) specifying if you want members' synchronization status to be returned in the response.

Sync statuses are returned in an additional `member_statuses` top level key on the response and include all of the members participating in the Availability Query.

This is useful to ensure the returned availability is based on the most up-to-date calendar data for the member.

See the description of the possible values [below](#param-member_statuses).

##### `excluded_events` *(optional)*

An array of objects describing events that should not be considered during the Availability calculation.

```json
{
  ...
  "excluded_events": [
    { "event_id": "interview_123" },
    { "event_uid": "evt_external_64f758b2707e9e455c32e9e" },
  ]
}```
Each item must specify either `event_id` for a Managed Event or the `event_uid` of an External Event (you can learn more about the [difference between these here](/developers/faqs/event-id-event-uid/index.md)).

If the specified events appear in any of the calendars queried, they will not block time from being considered as Available.

This is useful for operations such as querying to reschedule a meeting, where omitting the current event representing the meeting may make some additional slots available.
It can also be used to customize your query based on context, such as allowing a query for an important customer meeting to ignore several reschedulable internal meetings.

### Response parameters
##### `available_periods`

An array of available periods that match the criteria specified in the request.

Up to `20`, or the value specified for `max_results`, periods will be returned with preference being towards the soonest matches.

##### `available_periods.start`

The`start` of an available period as a [`Time`](/developers/api/data-types/index.md).

##### `available_periods.end`

The`end` of an available period as a [`Time`](/developers/api/data-types/index.md).

##### `available_periods.participants`

An array of participants that are available for the given period.

##### `available_periods.participants.sub`

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

##### `member_statuses`

An array of each of the participants in the query, and their synchronization status. Only returned when passing `true` in the [`include_member_statuses` request parameter](#param-include_member_statuses).

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

{
  ...
  "member_statuses": [
    {
      "sub": "acc_64b17d868090ea21640c914c",
      "sync_status": "active"
    },
    {
      "sub": "acc_61815038636bd5c5ce4edd14",
      "sync_status": "pending"
    },
    {
      "sub": "acc_64b186438090ea21640c9160",
      "sync_status": "disconnected"
    }
  ]
}
```

##### `member_statuses.sync_status`

The current synchronization status as a [`String`](/developers/api/data-types/index.md).

If a member has multiple calendar profiles authorized on their account and are participating in the query, this value represents the worst (least connected) profile.

The possible values are:

- `active` - their calendar is syncing and the query has used an up-to-date view of their availability.

- `pending` - the initial sync of their calendar has not completed yet, so the query cannot consider a their full availability yet. The query has run based on the data available.

- `disconnected` - their calendar profile is disconnected (usually due to expired credentials, awaiting relinking), so the query has run on the most recent data held and cannot guarantee a complete picture of their availability.

- `hibernated` - your authorization to their Account is currently in a hibernated state. Including this Account in the query will trigger all Profiles for this Account to be fully synced. You can then reattempt the Availability query to get up to date calendar information.

### Error responses
##### 401 Unauthorized

The request was refused as the provided [authentication credentials](/developers/api/authentication/index.md) were not recognized.

Note that whilst many accounts can be part of the availability request that authentication is performed via the`access_token` for only one of them.

When an OAuth`refresh_token` is available then it should be used to [request a replacement `auth_token`](/developers/api/authorization/refresh-token/index.md) before the request is retried.

##### 402 Payment Required

The request was refused as your plan does not include the required feature.

##### 422 Unprocessable

The request was unable to be processed due to it containing invalid parameters.

The response will contain a JSON object containing one or more errors relating to the invalid parameters.

For example, if you omitted the required `required_duration` parameter, you would receive a response like:

```json
{
  "errors": {
    "required_duration": [
      {
        "key": "errors.required",
        "description": "required"
      }
    ]
  }
}
```

The `key` field is intended for programmatic use and the `description` field is a human-readable equivalent.

## Common validation errors
- **invalid_time_format** - not a recognized time format. `available_periods.start` and `available_periods.end` must be [ISO 8601 compliant Time strings](/developers/api/data-types/index.md).

- **invalid_time_pair** - `end` must be after `start`.

- **max_date_exceeded** - date is too far in the future. `available_periods` must be less than or equal to 201 days in the future.

- **min_date_exceeded** - date is too far in the past. `available_periods` must be in the future.

- **max_period_exceeded** - `available_periods.end` and `query_periods.end` must be within 35 days of the earliest start.



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