Availability
Configure weekly availability windows and query bookable time slots.
Availability rules define when an event type can be booked. Each rule is a recurring weekly time window on a specific day. The availability engine combines your rules with connected calendar busy times to produce bookable slots.
Prerequisites
- An Astrocal account with an API key (Authentication guide)
- At least one event type (Event Types guide)
Setting availability rules
Set availability rules for an event type with a PUT request. This replaces all existing rules:
curl -X PUT https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID/availability \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"timezone": "America/New_York",
"rules": [
{ "day_of_week": 1, "start_time": "09:00:00", "end_time": "17:00:00" },
{ "day_of_week": 2, "start_time": "09:00:00", "end_time": "17:00:00" },
{ "day_of_week": 3, "start_time": "09:00:00", "end_time": "17:00:00" },
{ "day_of_week": 4, "start_time": "09:00:00", "end_time": "17:00:00" },
{ "day_of_week": 5, "start_time": "09:00:00", "end_time": "17:00:00" }
]
}'const response = await fetch(
"https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID/availability",
{
method: "PUT",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
timezone: "America/New_York",
rules: [
{ day_of_week: 1, start_time: "09:00:00", end_time: "17:00:00" },
{ day_of_week: 2, start_time: "09:00:00", end_time: "17:00:00" },
{ day_of_week: 3, start_time: "09:00:00", end_time: "17:00:00" },
{ day_of_week: 4, start_time: "09:00:00", end_time: "17:00:00" },
{ day_of_week: 5, start_time: "09:00:00", end_time: "17:00:00" },
],
}),
}
);
const data = await response.json();Try it in the API playground →
Day of week encoding
| Value | Day |
|---|---|
| 0 | Sunday |
| 1 | Monday |
| 2 | Tuesday |
| 3 | Wednesday |
| 4 | Thursday |
| 5 | Friday |
| 6 | Saturday |
Rule fields
| Field | Type | Description |
|---|---|---|
day_of_week | number | Day of week (0-6, Sunday through Saturday) |
start_time | string | Start time in HH:MM:SS format |
end_time | string | End time in HH:MM:SS format |
The timezone field determines how times are interpreted. All start_time and end_time values are local to this timezone.
Getting availability rules
Retrieve the current rules for an event type:
curl https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID/availability \
-H "Authorization: Bearer YOUR_API_KEY"const response = await fetch(
"https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID/availability",
{
headers: {
Authorization: "Bearer YOUR_API_KEY",
},
}
);
const data = await response.json();Try it in the API playground →
Response:
{
"event_type_id": "evt_abc123",
"timezone": "America/New_York",
"rules": [
{
"id": "rule_1",
"event_type_id": "evt_abc123",
"day_of_week": 1,
"start_time": "09:00:00",
"end_time": "17:00:00",
"created_at": "2026-01-15T10:00:00Z"
}
]
}Querying available slots
The availability endpoint is public (no authentication required). It returns bookable time slots for a date range:
curl "https://api.astrocal.dev/v1/availability?event_type_id=evt_abc123&start=2026-03-01&end=2026-03-07&timezone=America/New_York"const response = await fetch(
"https://api.astrocal.dev/v1/availability?event_type_id=evt_abc123&start=2026-03-01&end=2026-03-07&timezone=America/New_York",
);
const data = await response.json();Try it in the API playground →
Required parameters
| Parameter | Type | Description |
|---|---|---|
event_type_id | string | The event type to check availability for |
start | string | Start date in YYYY-MM-DD format |
end | string | End date in YYYY-MM-DD format |
timezone | string | IANA timezone for the response (e.g., America/New_York) |
Optional parameters
| Parameter | Type | Description |
|---|---|---|
duration | number | Duration in minutes. Required for event types with duration_options. |
host_id | string | Filter slots for a specific host (round-robin event types only). |
Response
{
"event_type_id": "evt_abc123",
"timezone": "America/New_York",
"start": "2026-03-01",
"end": "2026-03-07",
"slots": [
{
"start_time": "2026-03-03T14:00:00Z",
"end_time": "2026-03-03T14:30:00Z",
"spots_remaining": 1,
"total_capacity": 1,
"available": true,
"waitlist_available": false
}
],
"capped": false,
"waitlist_available": false
}Response fields
| Field | Type | Description |
|---|---|---|
slots[].start_time | string | Slot start time in ISO 8601 (UTC) |
slots[].end_time | string | Slot end time in ISO 8601 (UTC) |
slots[].spots_remaining | number | Number of available spots (for group bookings) |
slots[].total_capacity | number | Total capacity for the slot |
slots[].available | boolean | Whether the slot can be booked |
slots[].capped | boolean | Whether this slot is capped (booking cap reached) |
slots[].waitlist_available | boolean | Whether the waitlist is open for this slot |
capped | boolean | Whether the event type has reached its booking cap for the period |
waitlist_available | boolean | Whether the waitlist is available at the response level |
waitlist_position | number | Next waitlist position (only present when waitlist_available is true) |
How the availability engine works
The availability engine computes bookable slots in three steps:
-
Generate candidate slots from your availability rules. For each rule, the engine generates slots at the event type's duration interval within the time window.
-
Remove busy times by checking connected calendars (Google, Microsoft, CalDAV). Any slot that overlaps with an existing calendar event is removed.
-
Apply buffers and constraints. Buffer times before and after each slot are reserved. Existing bookings, booking caps, and max attendee limits are checked.
The result is a list of slots that are genuinely available for booking.
Key concepts
Timezone handling
- Rules are stored in the timezone specified when setting availability. A rule for
09:00:00inAmerica/New_Yorkmeans 9 AM Eastern, regardless of the requester's timezone. - Slots are always returned in UTC (
Zsuffix) but thetimezoneparameter controls which calendar dates are included in the response range. - Daylight saving time is handled automatically. A 9 AM rule stays at 9 AM local time year-round.
Split schedules
You can add multiple rules for the same day to create split schedules (e.g., morning and afternoon blocks with a lunch break):
curl -X PUT https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID/availability \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"timezone": "America/New_York",
"rules": [
{ "day_of_week": 1, "start_time": "09:00:00", "end_time": "12:00:00" },
{ "day_of_week": 1, "start_time": "13:00:00", "end_time": "17:00:00" },
{ "day_of_week": 2, "start_time": "09:00:00", "end_time": "12:00:00" },
{ "day_of_week": 2, "start_time": "13:00:00", "end_time": "17:00:00" }
]
}'const response = await fetch(
"https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID/availability",
{
method: "PUT",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
timezone: "America/New_York",
rules: [
{ day_of_week: 1, start_time: "09:00:00", end_time: "12:00:00" },
{ day_of_week: 1, start_time: "13:00:00", end_time: "17:00:00" },
{ day_of_week: 2, start_time: "09:00:00", end_time: "12:00:00" },
{ day_of_week: 2, start_time: "13:00:00", end_time: "17:00:00" },
],
}),
}
);
const data = await response.json();Try it in the API playground →
Booking caps and waitlists
When a booking cap is reached:
- The response-level
cappedfield istrue - The
slotsarray may be empty (all slots exhausted) or contain slots withcapped: true - If the event type has waitlists enabled,
waitlist_availableistrueandwaitlist_positionindicates the next position
Your UI should check both slot-level and response-level capped/waitlist_available fields to handle all cases.
Variable-duration event types
For event types with duration_options, pass the duration parameter to get slots for a specific meeting length:
"https://api.astrocal.dev/v1/availability?event_type_id=evt_abc123&start=2026-03-01&end=2026-03-07&timezone=America/New_York&duration=60""https://api.astrocal.dev/v1/availability?event_type_id=evt_abc123&start=2026-03-01&end=2026-03-07&timezone=America/New_York&duration=60"
); const data = await response.json(); ```
</Tab>
</Tabs>
_[Try it in the API playground →](/docs/api-reference/availability/v1/availability/get)_
If `duration` is omitted, the event type's default `duration_minutes` is used.
### Round-robin host filtering
For event types using round-robin assignment, pass `host_id` to check availability for a specific host:
<Tabs items={["curl", "TypeScript"]}>
<Tab value="curl">
```bash curl
"https://api.astrocal.dev/v1/availability?event_type_id=evt_abc123&start=2026-03-01&end=2026-03-07&timezone=America/New_York&host_id=mem_abc123""https://api.astrocal.dev/v1/availability?event_type_id=evt_abc123&start=2026-03-01&end=2026-03-07&timezone=America/New_York&host_id=mem_abc123"
); const data = await response.json(); ```
</Tab>
</Tabs>
_[Try it in the API playground →](/docs/api-reference/availability/v1/availability/get)_
Without `host_id`, the engine returns slots where at least one host is available.
## Common patterns
### Standard work week (Mon-Fri, 9-5)
<Tabs items={["curl", "TypeScript"]}>
<Tab value="curl">
```bash
curl -X PUT https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID/availability \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"timezone": "America/New_York",
"rules": [
{ "day_of_week": 1, "start_time": "09:00:00", "end_time": "17:00:00" },
{ "day_of_week": 2, "start_time": "09:00:00", "end_time": "17:00:00" },
{ "day_of_week": 3, "start_time": "09:00:00", "end_time": "17:00:00" },
{ "day_of_week": 4, "start_time": "09:00:00", "end_time": "17:00:00" },
{ "day_of_week": 5, "start_time": "09:00:00", "end_time": "17:00:00" }
]
}'const response = await fetch(
"https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID/availability",
{
method: "PUT",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
timezone: "America/New_York",
rules: [
{ day_of_week: 1, start_time: "09:00:00", end_time: "17:00:00" },
{ day_of_week: 2, start_time: "09:00:00", end_time: "17:00:00" },
{ day_of_week: 3, start_time: "09:00:00", end_time: "17:00:00" },
{ day_of_week: 4, start_time: "09:00:00", end_time: "17:00:00" },
{ day_of_week: 5, start_time: "09:00:00", end_time: "17:00:00" },
],
}),
}
);
const data = await response.json();Weekend-only availability
curl -X PUT https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID/availability \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"timezone": "Europe/London",
"rules": [
{ "day_of_week": 0, "start_time": "10:00:00", "end_time": "16:00:00" },
{ "day_of_week": 6, "start_time": "10:00:00", "end_time": "16:00:00" }
]
}'const response = await fetch(
"https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID/availability",
{
method: "PUT",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
timezone: "Europe/London",
rules: [
{ day_of_week: 0, start_time: "10:00:00", end_time: "16:00:00" },
{ day_of_week: 6, start_time: "10:00:00", end_time: "16:00:00" },
],
}),
}
);
const data = await response.json();Clearing all availability
Pass an empty rules array to remove all availability windows:
curl -X PUT https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID/availability \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"timezone": "America/New_York",
"rules": []
}'const response = await fetch(
"https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID/availability",
{
method: "PUT",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
timezone: "America/New_York",
rules: [],
}),
}
);
const data = await response.json();Try it in the API playground →
Error handling
| Status | Error Code | Description |
|---|---|---|
| 400 | validation_error | Invalid rule format, time range, or day_of_week value |
| 404 | not_found | Event type does not exist |
| 422 | validation_error | end_time is before or equal to start_time |
Next steps
- Calendars -- Connect Google, Microsoft, or CalDAV calendars for automatic busy-time blocking
- Bookings -- Create bookings against available slots
- Event Types -- Configure booking caps, variable durations, and pricing
- API Reference -- Full endpoint documentation