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": "660e8400-e29b-41d4-a716-446655440000",
"timezone": "America/New_York",
"rules": [
{
"id": "aa0e8400-e29b-41d4-a716-446655440000",
"event_type_id": "660e8400-e29b-41d4-a716-446655440000",
"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=660e8400-e29b-41d4-a716-446655440000&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=660e8400-e29b-41d4-a716-446655440000&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": "660e8400-e29b-41d4-a716-446655440000",
"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.
Slots that have already started, and slots that fall inside the event type's minimum notice window, are never returned.
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.
Waitlist entries change state without a request from you — a cancellation can promote an entry to a booking, and an entry expires once its slot passes. Subscribe to the waitlist_entry.* webhooks to react to those changes.
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=660e8400-e29b-41d4-a716-446655440000&start=2026-03-01&end=2026-03-07&timezone=America/New_York&duration=60""https://api.astrocal.dev/v1/availability?event_type_id=660e8400-e29b-41d4-a716-446655440000&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=660e8400-e29b-41d4-a716-446655440000&start=2026-03-01&end=2026-03-07&timezone=America/New_York&host_id=9b2f8c4e-1234-4abc-9def-1a2b3c4d5e6f""https://api.astrocal.dev/v1/availability?event_type_id=660e8400-e29b-41d4-a716-446655440000&start=2026-03-01&end=2026-03-07&timezone=America/New_York&host_id=9b2f8c4e-1234-4abc-9def-1a2b3c4d5e6f"
); 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, a day_of_week outside 0-6, or start_time equal to end_time |
| 404 | not_found | Event type does not exist |
| 422 | validation_error | Slot query only: invalid timezone, end before start, or a date range over 30 days |
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