# Errors
Source: https://docs.novacal.io/api-reference/errors
Understand Novacal API error responses, HTTP status codes, and the JSON error format returned when requests fail or validation does not pass.
The API uses standard HTTP status codes and returns error responses in a consistent JSON format.
## Error Response Format
All error responses follow this structure:
```json theme={null}
{
"success": false,
"error": {
"code": "error_code",
"message": "Human-readable error message",
"details": {}
}
}
```
The `details` field is optional and typically only included for validation errors.
## Error Codes
### 401 Unauthorized
Returned when authentication is required but not provided or invalid.
```json theme={null}
{
"success": false,
"error": {
"code": "unauthenticated",
"message": "Unauthenticated."
}
}
```
### 403 Forbidden
Returned when the authenticated user doesn't have sufficient permissions to perform the requested action.
```json theme={null}
{
"success": false,
"error": {
"code": "access_denied",
"message": "Access denied."
}
}
```
Or when the user lacks required abilities:
```json theme={null}
{
"success": false,
"error": {
"code": "missing_ability",
"message": "Insufficient privileges."
}
}
```
### 404 Not Found
Returned when the requested resource doesn't exist.
```json theme={null}
{
"success": false,
"error": {
"code": "resource_not_found",
"message": "Resource not found."
}
}
```
Or:
```json theme={null}
{
"success": false,
"error": {
"code": "not_found",
"message": "Not found."
}
}
```
### 405 Method Not Allowed
Returned when the HTTP method used is not allowed for the requested endpoint.
```json theme={null}
{
"success": false,
"error": {
"code": "method_not_allowed",
"message": "Method not allowed."
}
}
```
### 422 Unprocessable Content
Returned when the request data fails validation.
```json theme={null}
{
"success": false,
"error": {
"code": "validation_failed",
"message": "The given data was invalid.",
"details": {
"name": [
"The name field is required."
],
"slug": [
"The slug has already been taken."
]
}
}
}
```
### 500 Internal Server Error
Returned when an unexpected server error occurs.
```json theme={null}
{
"success": false,
"error": {
"code": "internal_server_error",
"message": "Internal server error."
}
}
```
### Other HTTP Exceptions
For other HTTP exceptions, the API returns:
```json theme={null}
{
"success": false,
"error": {
"code": "http_exception",
"message": "An error occurred."
}
}
```
The status code will match the HTTP exception status code.
# Introduction
Source: https://docs.novacal.io/api-reference/introduction
Learn how the Novacal API works, how authentication is handled, and what to expect from requests and responses.
## 1. Base URL
The Novacal API follows standard REST conventions and is available only over HTTPS
to protect request data and credentials in transit. Plain HTTP is not
supported.
Use the following base URL for all API requests:
```bash theme={null}
https://api.novacal.io
```
## 2. Create an API key
The Novacal API uses API keys to authenticate requests. If a request is sent
without a valid API key, the API will return an authentication error.
Create an API key from the [API Keys settings page](https://app.novacal.io/settings/api-keys),
then include it as a bearer token in your request headers:
```bash theme={null}
Authorization: Bearer YOUR_API_KEY
```
## 3. Test authentication
Make a simple authenticated request to confirm your API key is working:
```bash theme={null}
curl --request GET \
--url https://api.novacal.io/v1/users/me \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Accept: application/json"
```
If the request succeeds, your API key is valid and you are ready to continue.
## Response format
Successful responses use this shape:
```json theme={null}
{
"success": true,
"data": {}
}
```
## Rate limits
The default limit is `60 requests per minute` per API key. If you exceed that, the API returns `429 Too Many Requests`.
## Next steps
* Connect an MCP client with [MCP](/api-reference/mcp)
* Explore the full [Events reference](/api-reference/v1/events/get)
* Explore the full [Event Types reference](/api-reference/v1/event-types/get)
* Review [Errors](/api-reference/errors)
# MCP
Source: https://docs.novacal.io/api-reference/mcp
Connect Novacal to MCP-compatible clients using the hosted Novacal MCP server, enabling authenticated integration between Novacal and supported AI tools through a remote MCP endpoint.
## Hosted endpoint
Use the hosted Novacal MCP server at:
```txt theme={null}
https://mcp.novacal.io/mcp
```
The server uses Streamable HTTP and is intended for MCP-compatible clients.
## Authentication
The MCP server uses OAuth for the MCP connection.
During the first connection, you will be sent to a Novacal authorize page. On that page, enter your Novacal API key from:
[https://app.novacal.io/settings/api-keys](https://app.novacal.io/settings/api-keys)
The MCP server verifies the key with the Novacal API, stores it, and then uses it for future tool calls on your behalf.
## Set up in Claude
To connect Novacal in Claude:
1. Open Claude and add a new custom connector.
2. Enter the MCP server URL:
```txt theme={null}
https://mcp.novacal.io/mcp
```
3. Choose `OAuth` as the authentication method.
4. Leave `Client ID` and `Client Secret` empty.
5. Continue the OAuth flow.
6. When the Novacal authorize page opens, paste your Novacal API key.
7. Finish the connection.
## Available tools
The current MVP toolset includes:
* `get_event_types`
* `get_event_type`
* `create_event_type`
* `get_availability`
* `get_events`
* `create_event`
* `cancel_event`
* `reschedule_event`
## Example prompts
* `Show my Novacal event types.`
* `Show my Novacal event types and include their IDs.`
* `Get my upcoming Novacal events.`
* `Check my availability for event type 123 from 2026-06-01 to 2026-06-07.`
* `Create a new one-on-one event type named Intro Call, 30 minutes long, hidden from profile, with color #2563EB.`
* `Cancel Novacal event 456 because the attendee requested to reschedule.`
* `Reschedule Novacal event 456 to June 2, 2026 at 14:00 Europe/Belgrade.`
## Notes
* Each user should use their own Novacal API key.
* If the saved API key is revoked or becomes invalid, reconnect and authorize again.
# Get Availability
Source: https://docs.novacal.io/api-reference/v1/availability/get
GET /v1/availability
Retrieve availability ranges for a Novacal event type across a selected date window so you can show bookable times in your app.
```bash cURL theme={null}
curl --request GET \
--url 'https://api.novacal.io/v1/availability?start=2026-05-29&end=2026-05-30&event_type_id=123&timezone=UTC' \
--header 'Authorization: Bearer '
```
Pass `timezone` as an optional IANA timezone, such as `Europe/Belgrade`, to receive availability ranges converted to that timezone. If omitted, the response uses `UTC`.
# Create Booking Form Field
Source: https://docs.novacal.io/api-reference/v1/booking-forms/create
POST /v1/event-types/{eventType}/booking-forms
Create a new booking form field for a Novacal event type, including label, field type, placeholder, required state, and options.
# Delete Booking Form Field
Source: https://docs.novacal.io/api-reference/v1/booking-forms/delete
DELETE /v1/event-types/{eventType}/booking-forms/{field}
Delete a booking form field from a Novacal event type by field ID and review the endpoint path, auth requirements, and success response.
# Get Booking Form Fields
Source: https://docs.novacal.io/api-reference/v1/booking-forms/get
GET /v1/event-types/{eventType}/booking-forms
List all booking form fields for a Novacal event type, including labels, input types, placeholders, display order, and options.
# Update Booking Form Field
Source: https://docs.novacal.io/api-reference/v1/booking-forms/update
PUT /v1/event-types/{eventType}/booking-forms/{field}
Update a Novacal booking form field and change its label, input type, placeholder, required state, active status, order, or options.
# Update Booking Form Field Order
Source: https://docs.novacal.io/api-reference/v1/booking-forms/update-order
PUT /v1/event-types/{eventType}/booking-forms/update-order
Reorder booking form fields for a Novacal event type by updating field positions in a single API request with ordered IDs.
# Create Contact
Source: https://docs.novacal.io/api-reference/v1/contacts/create
POST /v1/contacts
Add a contact to your Novacal account with a name, email, and timezone.
## What this endpoint is for
Add someone to your contacts manually, rather than waiting for them to book. Only `email` is required.
## Notes
* If you already have a contact with the same email, its name and timezone are updated instead of creating a duplicate.
* The contact is attached to your account. It does not affect other users or teams.
# Delete Contact
Source: https://docs.novacal.io/api-reference/v1/contacts/delete
DELETE /v1/contacts/{id}
Delete a contact from your Novacal account.
## What this endpoint is for
Permanently remove a contact from your account. This does not delete any events the person booked.
## Access
You can only delete your own contacts. Deleting another account's contact returns `403 access_denied`.
# Get Contact
Source: https://docs.novacal.io/api-reference/v1/contacts/find
GET /v1/contacts/{id}
Retrieve a single Novacal contact by ID.
## What this endpoint is for
Fetch a single contact when you already have its ID.
## Access
You can only retrieve your own contacts. Requesting another account's contact returns `403 access_denied`.
# Get Contacts
Source: https://docs.novacal.io/api-reference/v1/contacts/get
GET /v1/contacts
List the contacts on your Novacal account, with search by name or email and pagination metadata.
## What this endpoint returns
This endpoint returns your contacts. Results are always paginated: the contacts for the current page live in `data.data`, alongside `current_page`, `per_page`, and `total`.
## Filtering and pagination
| Parameter | Description |
| ---------- | ------------------------------------------------------------- |
| `query` | Return only contacts whose name or email contains this string |
| `page` | The page of results to return. Defaults to `1` |
| `per_page` | Contacts per page, between 1 and 100. Defaults to `15` |
## Common use cases
* Sync your Novacal contacts into a CRM
* Look up a contact by email before creating a booking
* Build an internal address book from your bookers
# Update Contact
Source: https://docs.novacal.io/api-reference/v1/contacts/update
PUT /v1/contacts/{id}
Update a Novacal contact's name, email, or timezone.
## What this endpoint is for
Change a contact's details. Send only the fields you want to change.
## Access
You can only update your own contacts. Updating another account's contact returns `403 access_denied`.
# Create Event Type
Source: https://docs.novacal.io/api-reference/v1/event-types/create
POST /v1/event-types
Create a new Novacal event type with settings for duration, availability, booking limits, buffers, redirects, and booking form fields.
## What you can create
Use this endpoint to create a new event type that controls how people book time with you in Novacal.
## Configuration areas
* Core details such as name, slug, and duration
* Scheduling rules such as buffers, limits, and availability
* Booking flow settings such as redirects and booking form fields
# Delete Event Type
Source: https://docs.novacal.io/api-reference/v1/event-types/delete
DELETE /v1/event-types/{id}
Delete a Novacal event type by ID and review the endpoint path, authentication requirements, and no-content success response.
# Get Event Type
Source: https://docs.novacal.io/api-reference/v1/event-types/find
GET /v1/event-types/{id}
Retrieve one Novacal event type by ID, including its scheduling settings, booking limits, visibility, and active booking form fields.
## What this endpoint is for
Use this endpoint to retrieve one specific event type when you already know its ID.
## Returned details
* Scheduling configuration and booking limits
* Visibility and booking behavior settings
* Active booking form fields associated with the event type
# Get Event Types
Source: https://docs.novacal.io/api-reference/v1/event-types/get
GET /v1/event-types
List the Novacal event types available to the authenticated user, including names, durations, visibility settings, and form fields.
## What this endpoint returns
This endpoint lists the event types the authenticated user can access in Novacal.
Use the optional `scope` query parameter when you only want one ownership type:
* `scope=personal` returns event types owned by the authenticated user
* `scope=team` returns team event types
## Common use cases
* Populate an internal event type selector
* Sync booking configuration into another system
* Review visibility, duration, and booking form settings across event types
# Update Event Type
Source: https://docs.novacal.io/api-reference/v1/event-types/update
PUT /v1/event-types/{id}
Update an existing Novacal event type and change scheduling rules, limits, colors, visibility, redirects, and related configuration.
## When to use this endpoint
Use this endpoint to update an existing event type without recreating it from scratch.
## Typical changes
* Adjust duration, buffers, and scheduling limits
* Update colors, visibility, or redirect behavior
* Change configuration tied to the booking experience
# Cancel Event
Source: https://docs.novacal.io/api-reference/v1/events/cancel
PUT /v1/events/{id}/cancel
Cancel an existing Novacal event with the API, including the required public authentication flow and optional cancellation reason payload.
This endpoint requires a public API bearer token.
The authenticated API key identifies the caller integration. It does not replace the existing event booker.
## When to use this endpoint
Use this endpoint to cancel a booked event from your own application or integration flow.
## Cancellation notes
* Pass the correct event ID for the booking you want to cancel
* Include a cancellation reason when your workflow needs to preserve context
* Use the response payload to confirm the event status after the request succeeds
## Access
The authenticated user must be the organizer or a host of the event. Canceling an event you do not host returns `403 access_denied`.
# Book Event
Source: https://docs.novacal.io/api-reference/v1/events/create
POST /v1/events
Book a new Novacal event with the public API by sending the event type, selected time, attendee answers, timezone, and location data.
This endpoint requires a public API bearer token.
The authenticated API key identifies the caller integration. The event booker is still created from the submitted booking payload, for example `form_field_answers.name` and `form_field_answers.email`.
## When to use this endpoint
Use this endpoint when you want to create a new booking from your own product, widget, or backend workflow.
Common use cases include:
* Creating a booking after a customer selects a time in your app
* Passing attendee answers collected in a custom booking flow
* Saving the selected timezone and meeting location in the same request
## Authentication notes
This route uses a public API bearer token. The token authenticates your integration, while the attendee details still come from the booking payload you submit.
# Get Event
Source: https://docs.novacal.io/api-reference/v1/events/find
GET /v1/events/{id}
Retrieve a single Novacal event by ID and inspect its booking details, timing, status, organizer, guests, and submitted form answers.
## What this endpoint is for
Use this endpoint when you already have an event ID and need the full event payload for that specific booking.
## Typical use cases
* Show booking details inside an admin view
* Inspect the current event status before allowing a change
* Read submitted answers, attendee details, and organizer information
# Get Events
Source: https://docs.novacal.io/api-reference/v1/events/get
GET /v1/events
List the Novacal events the authenticated user can access, including scheduling details, attendees, hosts, and current event status.
## What this endpoint returns
This endpoint returns the events the authenticated user hosts or organizes. Use it to review scheduled meetings, sync event data into your own system, or build internal dashboards.
Results are always paginated. The `data` object holds the events for the current page in `data.data`, alongside pagination metadata such as `current_page`, `last_page`, `per_page`, and `total`.
## Filtering and pagination
| Parameter | Description |
| ----------------- | --------------------------------------------------------------------------------------- |
| `status` | `active` returns events that have not been canceled, `canceled` returns canceled events |
| `start` | Only return events ending on or after this date, for example `2026-07-01` |
| `end` | Only return events ending on or before this date. Must be after `start` |
| `page` | The page of results to return. Defaults to `1` |
| `per_page` | Events per page, between 1 and 100. Defaults to `15` |
| `order_direction` | Sort direction for the event start time, `asc` or `desc`. Defaults to `asc` |
```bash theme={null}
curl --request GET \
--url "https://api.novacal.io/v1/events?status=active&start=2026-07-01&end=2026-07-31&per_page=50" \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Accept: application/json"
```
Paginate by requesting the next page until `next_page_url` is `null`.
## Common use cases
* Load a list of upcoming or past events
* Sync Novacal bookings into a CRM or reporting workflow
* Pull only the bookings for a given month with `start` and `end`
* Reconcile cancellations by requesting `status=canceled`
* Review attendee, host, and event status data before follow-up actions
# Reschedule Event
Source: https://docs.novacal.io/api-reference/v1/events/update
PUT /v1/events/{id}
Reschedule an existing Novacal event with the public API by updating the start time, end time, timezone, and allowed booking answers.
This endpoint requires a public API bearer token.
The authenticated API key identifies the caller integration. It does not replace the existing event booker.
## When to use this endpoint
Use this endpoint when an existing booking needs to move to a different time or timezone without creating a brand new event record.
## Before you reschedule
* Confirm you are targeting the correct event ID
* Submit the updated scheduling fields you want to change
* Keep in mind that the authenticated token identifies the integration, not the attendee
## Access
The authenticated user must be the organizer or a host of the event. Rescheduling an event you do not host returns `403 access_denied`.
# Get Team
Source: https://docs.novacal.io/api-reference/v1/teams/find
GET /v1/teams/{id}
Retrieve a single Novacal team by ID, including its name, username, branding details, and other team profile information.
# Get Teams
Source: https://docs.novacal.io/api-reference/v1/teams/get
GET /v1/teams
List all Novacal teams the authenticated user belongs to and review the team data returned by the teams collection endpoint.
# Get Current User
Source: https://docs.novacal.io/api-reference/v1/users/me
GET /v1/users/me
Retrieve the currently authenticated Novacal user, including profile details such as name, email, timezone, avatar, and time format.
# Update Current User
Source: https://docs.novacal.io/api-reference/v1/users/update-me
PUT /v1/users/me
Update the authenticated Novacal user's profile, including username, email, name, avatar, timezone, week start, and time format.
# Create Webhook
Source: https://docs.novacal.io/api-reference/v1/webhooks/create
POST /v1/webhooks
Register a Novacal webhook to receive real-time notifications when events are booked, rescheduled, or canceled, with a signing secret to verify deliveries.
## What this endpoint is for
Register a URL that Novacal calls whenever something happens to an event you host or organize. Webhooks let you react to bookings in real time instead of polling the events endpoint.
## Available events
| Event | Sent when |
| ------------------- | ------------------------------------------- |
| `event.created` | A new event is booked |
| `event.rescheduled` | An existing event moves to a different time |
| `event.canceled` | An event is canceled |
Subscribe to one or more events per webhook. You can register several webhooks pointing at different URLs.
## Delivery format
Novacal sends a `POST` request with a JSON body:
```json theme={null}
{
"event": "event.created",
"created_at": "2026-07-14T10:32:11+00:00",
"data": {
"id": "9b1f...",
"event_type_id": 42,
"start": "2026-07-20T09:00:00.000000Z",
"end": "2026-07-20T09:30:00.000000Z",
"status": "scheduled",
"organizer": {},
"booker": {},
"guests": []
}
}
```
The `data` object is the same event payload returned by the [Get Event](/api-reference/v1/events/find) endpoint.
## Verifying deliveries
Every delivery carries two headers:
| Header | Description |
| --------------------- | ---------------------------------------------------------------------- |
| `X-Novacal-Signature` | HMAC SHA-256 of the raw request body, keyed with your webhook `secret` |
| `X-Novacal-Event` | The event name, for example `event.created` |
Recompute the signature over the raw body and compare it before trusting a request:
```javascript theme={null}
import crypto from "crypto";
const expected = crypto
.createHmac("sha256", process.env.NOVACAL_WEBHOOK_SECRET)
.update(rawBody)
.digest("hex");
const valid = crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(request.headers["x-novacal-signature"])
);
```
Always compare the signature against the **raw** request body, before any JSON parsing or re-serialization.
## Retries
Respond with a `2xx` status code to acknowledge a delivery. Novacal retries a failed delivery up to three times with a short backoff, so your endpoint should be idempotent.
# Delete Webhook
Source: https://docs.novacal.io/api-reference/v1/webhooks/delete
DELETE /v1/webhooks/{id}
Delete a Novacal webhook to permanently stop event deliveries to its endpoint.
## What this endpoint is for
Permanently remove a webhook. Novacal stops sending deliveries to it immediately.
## Before you delete
* Deleting a webhook discards its signing secret. Registering the same URL again issues a new secret.
* To stop deliveries temporarily, set `is_active` to `false` with the [Update Webhook](/api-reference/v1/webhooks/update) endpoint instead.
## Access
You can only delete webhooks registered on your own account. Deleting another account's webhook returns `403 access_denied`.
# Get Webhook
Source: https://docs.novacal.io/api-reference/v1/webhooks/find
GET /v1/webhooks/{id}
Retrieve a single Novacal webhook by ID to inspect its target URL, subscribed events, signing secret, and active status.
## What this endpoint is for
Use this endpoint when you already have a webhook ID and need its full record, including the signing secret used to verify deliveries.
## Typical use cases
* Look up a signing secret when configuring your receiving endpoint
* Check which events a webhook is subscribed to
* Confirm whether a webhook is active before investigating missing deliveries
## Access
You can only retrieve webhooks registered on your own account. Requesting another account's webhook returns `403 access_denied`.
# Get Webhooks
Source: https://docs.novacal.io/api-reference/v1/webhooks/get
GET /v1/webhooks
List the webhooks registered on your Novacal account, including their target URL, subscribed events, signing secret, and active status.
## What this endpoint returns
This endpoint returns every webhook you have registered, newest first. Each entry includes its target URL, the events it is subscribed to, its signing secret, and whether it is currently active.
## Common use cases
* Audit which endpoints are receiving Novacal deliveries
* Retrieve a signing secret you need to verify incoming requests
* Confirm which webhooks are paused before debugging a missing delivery
# Update Webhook
Source: https://docs.novacal.io/api-reference/v1/webhooks/update
PUT /v1/webhooks/{id}
Update a Novacal webhook to change its target URL, adjust which events it subscribes to, or pause deliveries without deleting it.
## What this endpoint is for
Change an existing webhook without re-registering it. Send only the fields you want to change.
## What you can change
* `url` — move deliveries to a different endpoint
* `events` — replace the list of subscribed events
* `is_active` — set to `false` to pause deliveries, and back to `true` to resume
The signing secret does not change when you update a webhook, so your receiving endpoint keeps working.
## Pausing instead of deleting
Set `is_active` to `false` while you deploy or debug your receiver. Novacal stops sending deliveries but keeps the webhook and its secret intact.
## Access
You can only update webhooks registered on your own account. Updating another account's webhook returns `403 access_denied`.