BentoCal has two scheduling calls:
POST /free_busyreturns when each user is busy.POST /availabilitydoes the maths for you and returns times when people are free.
Both read calendars live from Google and Microsoft, so results are always current.
Which calendars are read
By default, BentoCal reads the primary calendar of every active connection the user has. A user with a work Microsoft account and a personal Google account is busy whenever either calendar is.
To read other calendars, pass calendar_ids (up to 50 per user). Each entry can be:
- a calendar id from any of the user's connections (list them with
GET /connections/{connection_id}/calendars), primary, meaning the default connection's primary calendar, or- an account's email address, meaning that account's primary calendar.
Free/busy
curl -X POST https://api.bentocal.com/au/v1/free_busy \
-H "Authorization: Bearer $BENTOCAL_TEST_KEY" \
-H "Content-Type: application/json" \
-d '{
"user_ids": ["user_123", "user_456"],
"start": "2026-10-20T00:00:00Z",
"end": "2026-10-27T00:00:00Z",
"calendar_ids": { "user_456": ["primary", "team-rota@example.com"] }
}'{
"users": [
{ "user_id": "user_123", "busy": [{ "start": "2026-10-20T01:00:00Z", "end": "2026-10-20T02:30:00Z" }] },
{ "user_id": "user_456", "busy": [] }
],
"errors": []
}- Up to 100 users and a range of up to 62 days.
- Busy means the provider's busy, tentative and out-of-office statuses. Free time and "working elsewhere" don't count.
- Intervals are merged across calendars, sorted, and returned in UTC.
Availability
Availability takes the people who need to attend and the windows to search, and returns times that work:
curl -X POST https://api.bentocal.com/au/v1/availability \
-H "Authorization: Bearer $BENTOCAL_TEST_KEY" \
-H "Content-Type: application/json" \
-d '{
"participants": [{ "user_id": "user_123" }, { "user_id": "user_456" }],
"required": "all",
"periods": [
{ "start": "2026-10-20T09:00:00+11:00", "end": "2026-10-20T17:00:00+11:00" },
{ "start": "2026-10-21T09:00:00+11:00", "end": "2026-10-21T17:00:00+11:00" }
],
"slot_duration_minutes": 45,
"slot_interval_minutes": 15,
"buffer_after_minutes": 10
}'{
"slots": [
{ "start": "2026-10-19T22:00:00Z", "end": "2026-10-19T22:45:00Z", "user_ids": ["user_123", "user_456"] },
{ "start": "2026-10-19T22:15:00Z", "end": "2026-10-19T23:00:00Z", "user_ids": ["user_123", "user_456"] }
],
"errors": []
}Options
| Field | Default | What it does |
|---|---|---|
participants | 1 to 100 users, each with optional calendar_ids. | |
required | all | all: every participant must be free. any: at least one must be; each result lists who is in user_ids. |
periods | 1 to 200 windows to search, spanning at most 62 days in total. Use them for working hours, for example one period per weekday. | |
slot_duration_minutes | Length of each slot: 5 to 1440, a multiple of 5. | |
slot_interval_minutes | slot_duration_minutes | Gap between slot start times: 5 to 1440, a multiple of 5. Slots start on this grid counted from 00:00 UTC. |
buffer_before_minutes | 0 | Free time needed before each slot, up to 240. |
buffer_after_minutes | 0 | Free time needed after each slot, up to 240. |
format | slots | slots or periods. See below. |
A slot is returned only when it fits inside a period and every required participant is free for the whole slot plus its buffers.
Slots or periods
format: "slots"returns bookable slots ofslot_duration_minuteson theslot_interval_minutesgrid. Use it to show a list of times to pick from.format: "periods"returns the longest free stretches (no grid) that are at leastslot_duration_minuteslong. Use it to draw free time on a calendar. Withrequired: "any", a period ends wherever the set of free participants changes.
When a calendar can't be read
Both calls return 200 even when some users fail. Those users are left out of the results and listed in errors:
{
"errors": [
{
"user_id": "user_456",
"connection_id": "conn_7rD1sW8eYq2KjH6b",
"code": "relink_required",
"message": "The calendar connection must be re-linked by the user."
}
]
}code | What to do |
|---|---|
relink_required | Ask the user to reconnect. See Relink a connection. |
provider_unavailable | Google or Microsoft failed. Retry shortly. |
not_found | No such user, or a calendar in calendar_ids doesn't exist. |
no_connections | The user has no active connections. |
required: "all", a participant you can't read means you can't know when everyone is free, so any error gives no results. Check errors before telling a user there are no times available.