Astrocal
Guides

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

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

ValueDay
0Sunday
1Monday
2Tuesday
3Wednesday
4Thursday
5Friday
6Saturday

Rule fields

FieldTypeDescription
day_of_weeknumberDay of week (0-6, Sunday through Saturday)
start_timestringStart time in HH:MM:SS format
end_timestringEnd 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

ParameterTypeDescription
event_type_idstringThe event type to check availability for
startstringStart date in YYYY-MM-DD format
endstringEnd date in YYYY-MM-DD format
timezonestringIANA timezone for the response (e.g., America/New_York)

Optional parameters

ParameterTypeDescription
durationnumberDuration in minutes. Required for event types with duration_options.
host_idstringFilter 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

FieldTypeDescription
slots[].start_timestringSlot start time in ISO 8601 (UTC)
slots[].end_timestringSlot end time in ISO 8601 (UTC)
slots[].spots_remainingnumberNumber of available spots (for group bookings)
slots[].total_capacitynumberTotal capacity for the slot
slots[].availablebooleanWhether the slot can be booked
slots[].cappedbooleanWhether this slot is capped (booking cap reached)
slots[].waitlist_availablebooleanWhether the waitlist is open for this slot
cappedbooleanWhether the event type has reached its booking cap for the period
waitlist_availablebooleanWhether the waitlist is available at the response level
waitlist_positionnumberNext waitlist position (only present when waitlist_available is true)

How the availability engine works

The availability engine computes bookable slots in three steps:

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

  2. Remove busy times by checking connected calendars (Google, Microsoft, CalDAV). Any slot that overlaps with an existing calendar event is removed.

  3. 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:00 in America/New_York means 9 AM Eastern, regardless of the requester's timezone.
  • Slots are always returned in UTC (Z suffix) but the timezone parameter 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 capped field is true
  • The slots array may be empty (all slots exhausted) or contain slots with capped: true
  • If the event type has waitlists enabled, waitlist_available is true and waitlist_position indicates 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

StatusError CodeDescription
400validation_errorInvalid rule format, time range, or day_of_week value
404not_foundEvent type does not exist
422validation_errorend_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

On this page