# Controlling Available Periods with a sub calendar

Available Periods are part of Cronofy's Managed Availability suite of features. They allow you to record specific times that user's are available and have them automatically included whenever that user is included in an Availability query.

One option for allowing users to control their availablity is to link Available Periods to events in a sub calendar. We're not currently recommending this as an approach but several customers are experimenting with this so we thought we'd share how to approach it.

## 1. Create a Sub Calendar
![](/developers/scheduling/available-period-events/sample-calendar.1c28be8d442dc8bcd89ce6988b2406a1a71d4d089e7de232407920fc0b1f151e.png)
First, you will need the `profile_id` for the calendar account to create the calendar in.



```bash
curl -v -G --header "Authorization: Bearer {ACCESS_TOKEN}" \
  -d 'tzid=Etc/UTC' https://api.cronofy.com/v1/profiles
```


```ruby
cronofy = Cronofy::Client.new(access_token: '{ACCESS_TOKEN}')
profiles = cronofy.list_profiles
```



[Profiles docs](/developers/api/identity/profile/index.md)

Then you can create the calendar in that profile.



```bash
curl -v --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --data "{\"profile_id\": \"{PROFILE_ID}\",\"name\": \"Availability\"}" \
    https://api.cronofy.com/v1/calendars
```


```ruby
cronofy = Cronofy::Client.new(access_token: '{ACCESS_TOKEN}')
calendar = cronofy.create_calendar("{PROFILE_ID}", "Availability")

calendar_id = calendar.calendar_id
```



Track the `calendar_id` of the new calendar as you'll need that for the next step.

[Create Calendar docs](/developers/api/calendars/create-calendar/index.md)

## 2. Setup Push Notification Channel
You now need to create a channel to receive notications of any changes to events in that calendar.

The `callback_url` can be any public URL that Cronofy can post to. You will want to include any parameters in this URL to allow you to identify the user it relates to, eg a user id or similar. This will allow you to look up the `access_token` for the user to perform the updates required when ever something changes.



```bash
curl -v --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --data "{\"callback_url\": \"{CALLBACK_URL}\",\"filters\": { \"calendar_ids\": [ \"{CALENDAR_ID}\" }}" \
    https://api.cronofy.com/v1/channels
```


```ruby
cronofy = Cronofy::Client.new(access_token: '{ACCESS_TOKEN}')
cronofy.create_channel("{CALLBACK_URL}", { calendar_ids: [ calendar_id ] })
```



[Push Notification docs](/developers/api/push-notifications/create-channel/index.md)

## 3. Process Change Notifications
The standard pattern for processing notifications comes into play here. Your app will receive notifications similar to the following.

```http
POST {CALLBACK_URL_PATH} HTTP/1.1
Host: {CALLBACK_URL_HOST}
Content-Type: application/json; charset=utf-8

{
  "notification": {
    "type": "change",
    "changes_since": "2026-05-31T07:24:16Z"
  },
  "channel": {
    "channel_id": "chn_54cf7c7cb4ad4c1027000001",
    "callback_url": "{CALLBACK_URL}",
    "filters": {}
  }
}
```

The key value here is the `changes_since` parameter. You pass this to the [Read Events](/developers/api/events/read-events/index.md) endpoint as the `last_modified` parameter to retrieve the events that have changed.



```bash
curl -v -G --header "Authorization: Bearer {ACCESS_TOKEN}" \
  -d 'tzid=Etc/UTC' https://api.cronofy.com/v1/events?last_modified={CHANGES_SINCE}&calendar_ids[]={CALENDAR_ID}&include_deleted=1&include_moved=1
```


```ruby
cronofy = Cronofy::Client.new(access_token: '{ACCESS_TOKEN}')
options = {
  last_modified: {CHANGES_SINCE},
  calendar_ids: [ {CALENDAR_ID} ],
  include_deleted: true,
  include_moved: true
}
events = cronofy.read_events(options)
```



You then iterate over the events and either upsert or delete Available Periods.



```ruby
events.each do |event|
  if event.deleted
    cronofy.delete_available_period(event.event_uid)
  else
    period = {
      available_period_id: event.event_uid,
      start: event.start,
      end: event.end
    }
    cronofy.upsert_available_period(period)
  end
end
```



Because Cronofy is using an upsert pattern that allows you to specify the `available_period_id`, just using the `event.event_uid` value means there is no state to be stored. Your code can just deal with each change as it appears.

[Available Periods docs](/developers/api/scheduling/available-periods/index.md)

## 4. Use in Availability Queries
You can then enable the [Managed Availability](/developers/scheduling/managed-availability/index.md) features for any user you have set up for this kind availability tracking.


---
[Read in HTML](/developers/scheduling/available-period-events/)
