Errors
Complete reference of Astrocal API error codes, HTTP statuses, and handling guidance.
Every Astrocal API error returns a consistent JSON structure. This page documents all error codes, when they occur, and how to handle them.
Error response format
All errors follow this shape:
{
"error": {
"code": "not_found",
"message": "Booking 'bk_abc123' not found",
"details": {}
}
}| Field | Type | Description |
|---|---|---|
code | string | Machine-readable error code (use this for programmatic branching) |
message | string | Human-readable description of what went wrong |
details | object | Optional field-level errors or additional context (varies by code) |
Validation errors
Validation errors occur when the request body or query parameters are malformed or contain invalid values.
validation_error (400 / 422)
Returned when request parameters fail schema validation or contain semantically invalid values.
{
"error": {
"code": "validation_error",
"message": "Invalid request parameters",
"details": {
"title": "Required",
"duration_minutes": "Number must be greater than or equal to 5"
}
}
}Common causes:
- Missing required fields
- Values out of range (e.g.,
duration_minutesbelow 5 or above 480) - Invalid format (e.g.,
start_timenot in ISO 8601,timezonenot a valid IANA zone) end_timebeforestart_timein availability rules- Date range exceeds the maximum allowed days for availability queries
How to handle: Fix the request based on the details field. Each key in details is the field name, and the value describes what's wrong.
bad_request (400)
Returned for business logic validation that goes beyond schema checks.
{
"error": {
"code": "bad_request",
"message": "Invalid duration: 45. Allowed values: 15, 30, 60"
}
}Common causes:
- Invalid
durationvalue for a variable-duration event type - Too many attendees for a group booking
- Duplicate attendee emails in a multi-attendee booking
- Waitlist not enabled for the event type
- Paid event type but no Stripe account connected
- Expired or revoked invitation
- Invalid CalDAV preset or missing
server_url
How to handle: Read the message field for specific guidance. These are not retryable -- fix the request.
Authentication errors
unauthorized (401)
Returned when authentication is missing, invalid, or expired.
{
"error": {
"code": "unauthorized",
"message": "Invalid API key"
}
}Common causes:
- Missing
Authorization: Bearerheader - API key not found in the database
- API key has been revoked
- API key has expired
- Invalid or missing cancel token on cancel/reschedule endpoints
How to handle: Check that you're sending a valid API key. For cancel/reschedule endpoints, ensure the ?token= parameter matches the cancel_token from the booking response. Do not retry -- fix the credentials.
Authorization errors
forbidden (403)
Returned when the authenticated user lacks permission for the requested action.
{
"error": {
"code": "forbidden",
"message": "Insufficient permissions"
}
}How to handle: The API key is valid but doesn't have the required permission. Check that the key belongs to the correct organization and that the user's role allows the action.
org_suspended (403)
Returned when the organization has been suspended.
{
"error": {
"code": "org_suspended",
"message": "Organization is suspended"
}
}How to handle: Contact support to resolve the suspension.
plan_limit_exceeded (403)
Returned when the organization has reached its plan's booking limit.
{
"error": {
"code": "plan_limit_exceeded",
"message": "Monthly booking limit reached. Upgrade your plan."
}
}How to handle: Upgrade the organization's plan or wait for the limit to reset.
Not found errors
not_found (404)
Returned when the requested resource doesn't exist or isn't accessible to the current API key.
{
"error": {
"code": "not_found",
"message": "Event type 'evt_abc123' not found"
}
}Common resources: event types, bookings, calendar connections, webhook endpoints, webhook deliveries, API keys, team members, invitations, waitlist entries.
How to handle: Verify the resource ID is correct. The resource may have been deleted, or it may belong to a different organization.
Conflict errors
Conflict errors indicate the request can't be completed because it contradicts the current state of the system.
conflict (409)
The most common conflict scenarios:
Slot no longer available:
{
"error": {
"code": "conflict",
"message": "The selected time slot is no longer available"
}
}This occurs when two requests try to book the same slot simultaneously. Handle by refreshing available slots and asking the user to pick again.
Duplicate slug:
{
"error": {
"code": "conflict",
"message": "Event type with slug 'quick-call' already exists"
}
}Cannot reschedule cancelled booking:
{
"error": {
"code": "conflict",
"message": "Cannot reschedule a cancelled booking"
}
}Other conflict causes:
- Slot is full (group booking at max attendees)
- Calendar account already connected
- Duplicate team invitation
- Invitation already accepted
- Member already a host for the event type
- Webhook delivery not in
failedstatus (for retries)
How to handle: Read the message to understand the specific conflict. For slot conflicts, refresh availability and retry with a new slot. For duplicate resources, use a different identifier.
booking_cap_reached (409)
Returned when the event type's booking cap has been reached for the current period.
{
"error": {
"code": "booking_cap_reached",
"message": "This event type has reached its booking limit for the current period"
}
}How to handle: Check availability first -- the capped: true flag indicates the cap has been reached. If the event type has waitlists enabled, offer the user to join the waitlist instead.
Rate limit errors
rate_limit_exceeded (429)
Returned when you've exceeded the request rate for your plan tier.
Authenticated endpoints (API key):
{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Your limit is 60 requests/minute (starter tier).",
"details": {}
},
"limit": 60,
"window": "1m",
"reset_at": "2026-03-15T14:01:00Z",
"retry_after": 45,
"tier": "starter"
}Public endpoints (per-IP):
{
"error": {
"code": "rate_limit_exceeded",
"message": "Too many requests. Please try again later."
},
"retry_after": 30
}Rate limit responses include these headers:
| Header | Description |
|---|---|
Retry-After | Seconds to wait before retrying |
X-RateLimit-Limit | Maximum requests allowed in the window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
Plan limits:
| Plan | Requests/minute | Requests/day |
|---|---|---|
| Free | 30 | 200 |
| Starter | 60 | 1,000 |
| Pro | 500 | 10,000 |
| Business | 2,000 | 50,000 |
How to handle: Back off and retry after the Retry-After duration. Implement exponential backoff for sustained rate limiting. See the Rate Limits guide for strategies.
Payment errors
bad_gateway (502)
Returned when an upstream payment provider (Stripe) fails during booking creation.
{
"error": {
"code": "bad_gateway",
"message": "Failed to create payment — please try again"
}
}How to handle: This is a transient error. Retry the request after a short delay. If it persists, check Stripe's status page.
Server errors
internal_error (500)
Returned for unexpected server-side failures.
{
"error": {
"code": "internal_error",
"message": "An unexpected error occurred"
}
}How to handle: This indicates a bug or infrastructure issue on Astrocal's side. Retry once after a short delay. If it persists, contact support.
Best practices
- Branch on
error.code, noterror.message. Messages may change; codes are stable. - Check
error.detailsfor field-level errors. Validation errors include per-field descriptions to help you fix the request. - Always handle 409 on bookings. Slot conflicts are expected in concurrent systems. Refresh availability and let the user pick again.
- Respect
Retry-Afterheaders. Rate limit responses tell you exactly when to retry. - Don't retry 400/401/403/404 errors. These require fixing the request or credentials, not retrying.
- Retry 429/500/502 with backoff. These are transient and may resolve on their own.
Next steps
- Authentication -- Set up API keys
- Rate Limits -- Understand rate limiting and plan tiers
- Bookings -- Handle booking lifecycle errors
- API Reference -- Full endpoint documentation