Event Types
Create and manage bookable event types with duration, pricing, and booking caps.
Event types are templates for bookable meetings. Each event type defines a duration, availability rules, and optional settings like pricing, buffer times, and booking caps.
Prerequisites
- An Astrocal account with an API key (Authentication guide)
Creating an event type
Create an event type by sending a POST request to /v1/event-types:
curl -X POST https://api.astrocal.dev/v1/event-types \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "30 Minute Meeting",
"slug": "30-min-meeting",
"duration_minutes": 30
}'const response = await fetch("https://api.astrocal.dev/v1/event-types", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "30 Minute Meeting",
slug: "30-min-meeting",
duration_minutes: 30,
}),
});
const data = await response.json();Try it in the API playground →
Required fields
| Field | Type | Description |
|---|---|---|
title | string | Display name (1-255 characters) |
slug | string | URL-safe identifier (lowercase, hyphens only) |
duration_minutes | number | Meeting length in minutes (5-480) |
Optional fields
| Field | Type | Default | Description |
|---|---|---|---|
description | string | null | Event type description (max 1000 chars) |
buffer_before_minutes | number | 0 | Buffer time before meetings (0-120 minutes) |
buffer_after_minutes | number | 0 | Buffer time after meetings (0-120 minutes) |
color | string | "#3b82f6" | Hex color for calendar display |
max_attendees | number | 1 | Maximum attendees per slot (1-100). Values > 1 enable group bookings. |
duration_options | number[] | null | Available durations for variable-length bookings (e.g., [15, 30, 60]) |
price_amount | number|null | null | Price in cents (min 100). See Payments |
price_currency | string | "usd" | 3-letter ISO currency code |
reminder_intervals | number[] | [1440, 60] | Reminder email intervals in minutes before the meeting |
booking_cap | number|null | null | Maximum bookings allowed per period (1-10000) |
booking_cap_period | string|null | null | Cap period: "daily", "weekly", "monthly", or "total" |
booking_page_enabled | boolean | false | Show this event type on your organization's public booking page |
Updating an event type
Update an event type with a PATCH request. Only include the fields you want to change:
curl -X PATCH https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Quick Chat",
"duration_minutes": 15,
"active": false
}'const response = await fetch(
"https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID",
{
method: "PATCH",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "Quick Chat",
duration_minutes: 15,
active: false,
}),
}
);
const data = await response.json();Try it in the API playground →
The active field is only available on update (not creation). Setting active: false hides the event type from public availability queries.
Booking caps
Booking caps let you limit the number of bookings an event type can receive within a time period. This is useful for limiting consultation availability, capping class sizes per week, or restricting total bookings.
Setting a booking cap
Both booking_cap and booking_cap_period must be set together (or both null):
# Limit to 20 bookings per week
curl -X PATCH https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"booking_cap": 20,
"booking_cap_period": "weekly"
}'const response = await fetch(
"https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID",
{
method: "PATCH",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
booking_cap: 20,
booking_cap_period: "weekly",
}),
}
);
const data = await response.json();Try it in the API playground →
Cap periods
| Period | Description |
|---|---|
daily | Resets at midnight in the event type's timezone |
weekly | Resets at the start of each week (Monday) in the event type's timezone |
monthly | Resets at the start of each month in the event type's timezone |
total | Never resets -- counts all bookings since the cap was set |
How caps are enforced
-
Availability layer: When a cap is reached, the availability endpoint returns an empty
slotsarray and acapped: trueflag. This lets your UI show that the event type is fully booked for the period. -
Booking layer: If a booking is attempted after the cap is reached (e.g., due to a race condition), the API returns a
409 Conflictwith error codebooking_cap_reached.
Checking remaining capacity
The event type response includes a bookings_remaining field when a cap is configured:
curl https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID \
-H "Authorization: Bearer YOUR_API_KEY"const response = await fetch(
"https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID",
{
headers: {
Authorization: "Bearer YOUR_API_KEY",
},
}
);
const data = await response.json();Try it in the API playground →
# Response (with booking cap)
{
"id": "...",
"title": "Weekly Consultation",
"booking_cap": 20,
"booking_cap_period": "weekly",
"bookings_remaining": 14,
...
}bookings_remaining is null when no cap is configured.
Removing a booking cap
Set both fields to null:
curl -X PATCH https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"booking_cap": null,
"booking_cap_period": null
}'const response = await fetch(
"https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID",
{
method: "PATCH",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
booking_cap: null,
booking_cap_period: null,
}),
}
);
const data = await response.json();Try it in the API playground →
Variable-duration bookings
To let invitees choose between multiple meeting lengths, set duration_options:
curl -X POST https://api.astrocal.dev/v1/event-types \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Consultation",
"slug": "consultation",
"duration_minutes": 30,
"duration_options": [15, 30, 60]
}'const response = await fetch("https://api.astrocal.dev/v1/event-types", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "Consultation",
slug: "consultation",
duration_minutes: 30,
duration_options: [15, 30, 60],
}),
});
const data = await response.json();Try it in the API playground →
duration_minutes is the default duration and must be included in duration_options. When checking availability, pass duration to get slots for a specific length.
Listing event types
curl https://api.astrocal.dev/v1/event-types \
-H "Authorization: Bearer YOUR_API_KEY"const response = await fetch("https://api.astrocal.dev/v1/event-types", {
headers: {
Authorization: "Bearer YOUR_API_KEY",
},
});
const data = await response.json();Try it in the API playground →
Filter by active status with ?active=true or ?active=false. Uses cursor-based pagination with starting_after and limit.
Deleting an event type
curl -X DELETE https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID \
-H "Authorization: Bearer YOUR_API_KEY"const response = await fetch(
"https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID",
{
method: "DELETE",
headers: {
Authorization: "Bearer YOUR_API_KEY",
},
}
);
const data = await response.json();Try it in the API playground →
Deletion is a soft delete -- the event type is marked as deleted but existing bookings are preserved.
Booking pages
Each organization has a public booking page at https://book.astrocal.dev/{orgSlug} that lists all eligible event types. Invitees can browse and book directly from this page without needing an API key.
Enabling an event type on the booking page
By default, event types are not shown on the booking page. To include an event type, set booking_page_enabled to true:
curl -X PATCH https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"booking_page_enabled": true}'const response = await fetch(
"https://api.astrocal.dev/v1/event-types/YOUR_EVENT_TYPE_ID",
{
method: "PATCH",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ booking_page_enabled: true }),
}
);
const data = await response.json();Try it in the API playground →
In the dashboard, you can toggle this under Event Types → Settings → Enable booking page.
An event type appears on the booking page only when both active is true and booking_page_enabled is true.
Error handling
| Status | Error Code | Description |
|---|---|---|
| 409 | conflict | Slug already exists within the organization |
| 409 | booking_cap_reached | Booking cap has been reached for the current period |
| 404 | not_found | Event type does not exist or is not accessible |
Next Steps
- Quickstart -- Set up availability and create your first booking
- Bookings -- Create, cancel, and reschedule bookings
- Payments -- Add pricing to event types
- API Reference -- Full endpoint documentation