Calendar & Booking
Internal calendar with bookable resources and bookings: appointments, restaurant tables and hotel rooms, ICS feed sync, and bookings by AI assistants or site visitors. All datetimes in UTC.
Try it with your AI assistant
Once WebsitePublisher is connected to your AI assistant, paste one of these into the chat. Replace the parts in [brackets] with your own details.
@WebsitePublisher add a booking page where clients pick a free time slot for [a haircut]@WebsitePublisher set my booking hours to [Monday to Friday, 9:00 to 17:00] with [30] minutes per appointment@WebsitePublisher show my bookings for next weekWith WebsitePublisher, add a booking page where clients pick a free time slot for [a haircut]With WebsitePublisher, set my booking hours to [Monday to Friday, 9:00 to 17:00] with [30] minutes per appointmentWith WebsitePublisher, show my bookings for next weekWith WebsitePublisher, add a booking page where clients pick a free time slot for [a haircut]With WebsitePublisher, set my booking hours to [Monday to Friday, 9:00 to 17:00] with [30] minutes per appointmentWith WebsitePublisher, show my bookings for next weekEndpoints (21)
Create or update a calendar. Without calendar_id = create (name required), with calendar_id = update.
| Field | Type | Required | Description |
|---|---|---|---|
calendar_id |
integer | No | ID of an existing calendar (omit when creating). |
name |
string | No | Calendar name. Required when creating. |
slug |
string | No | URL slug. Derived from name when empty; unique per project. |
timezone |
string | No | IANA timezone for display (default Europe/Amsterdam). Storage stays UTC. |
color |
string | No | Hex color for the UI, e.g. #1B4332. |
source_of_truth |
boolean | No | This calendar wins on sync conflicts. |
block_on_events |
array | No | Which events on this calendar count as busy time for its resources: ["ics"] (imported with set-import-feed, e.g. the owner's Google Calendar), ["internal"] (created with upsert-event), or both. get-slots then leaves those times out and book refuses them. Cancelled events and the events of bookings never block; an all-day event blocks the whole local day. Recurring (RRULE) feed events are not imported, so they do not block. null or [] = off (default). |
All calendars of this project.
No input parameters required.
Delete a calendar including its events. Refused while resources are still attached.
| Field | Type | Required | Description |
|---|---|---|---|
calendar_id |
integer | ✓ Yes | ID of the calendar to delete. |
Create or update an event. Without event_id = create (calendar_id, title, start_at, end_at required). Datetimes without an offset are read as UTC.
| Field | Type | Required | Description |
|---|---|---|---|
event_id |
integer | No | ID of an existing event (omit when creating). |
calendar_id |
integer | No | Target calendar. Required when creating. |
title |
string | No | Title. Required when creating. |
description |
string | No | Description. |
location |
string | No | Location. |
start_at |
string | No | Start (UTC), e.g. 2026-09-01 18:00:00. Required when creating. |
end_at |
string | No | End (UTC), must be after start_at. Required when creating. |
all_day |
boolean | No | All-day event. |
status |
string | No | confirmed | tentative | cancelled (default confirmed). |
Delete an event.
| Field | Type | Required | Description |
|---|---|---|---|
event_id |
integer | ✓ Yes | ID of the event to delete. |
Events that overlap the window [from, to), optionally per calendar.
| Field | Type | Required | Description |
|---|---|---|---|
from |
string | ✓ Yes | Window start (UTC). |
to |
string | ✓ Yes | Window end (UTC), after from. |
calendar_id |
integer | No | Limit to one calendar. |
Create or update a bookable resource (chair/table/room). Without resource_id = create (calendar_id, type, name required).
| Field | Type | Required | Description |
|---|---|---|---|
resource_id |
integer | No | ID of an existing resource (omit when creating). |
calendar_id |
integer | No | Calendar on which bookings land as events. Required when creating. |
type |
string | No | Resource type: chair | table | room (extensible, lowercase a-z/_). Required when creating. |
name |
string | No | Name, e.g. "Table 4" or "Room 12". Required when creating. |
capacity |
integer | No | Capacity (people), default 1. |
config |
array | No | Type-specific config. table: {min_party, max_party, seating_minutes, shifts}. room: {room_type, min_stay_nights, checkin_time, checkout_time}. chair: {service_ids}. |
active |
boolean | No | Inactive resources cannot be booked. |
All resources of this project, optionally filtered.
| Field | Type | Required | Description |
|---|---|---|---|
type |
string | No | Filter by type (chair/table/room/...). |
active_only |
boolean | No | Only active resources. |
Availability rules per resource.
| Field | Type | Required | Description |
|---|---|---|---|
resource_id |
integer | ✓ Yes | Resource the rules apply to. |
rules |
array | ✓ Yes | Rules object: {weekdays: {mon:[{from:"09:00",to:"17:00"}], ...}, slot_minutes: 30, exceptions: [{date:"2026-12-25", closed:true}], vacations: [{from:"2026-08-01", to:"2026-08-14"}]}. Times in the calendar timezone. Day keys: mon, tue, wed, thu, fri, sat, sun (full English day names are stored as these keys). Times as HH:MM, from before to. Rooms book per night: exceptions with closed:true and vacations (dates inclusive) close nights, where a night belongs to its check-in date; weekday windows do not apply to rooms. Invalid rules are rejected with the reason. |
Bookings of this project with filters and pagination.
| Field | Type | Required | Description |
|---|---|---|---|
status |
string | No | pending | confirmed | completed | cancelled | no_show. |
resource_id |
integer | No | Filter by resource. |
from |
string | No | Only bookings that end after this moment (UTC). |
to |
string | No | Only bookings that start before this moment (UTC). |
page |
integer | No | Page (default 1). |
per_page |
integer | No | Per page (default 25, max 100). |
Change the status of a booking (e.g. confirmed → completed or no_show).
| Field | Type | Required | Description |
|---|---|---|---|
booking_id |
integer | ✓ Yes | ID of the booking. |
status |
string | ✓ Yes | pending | confirmed | completed | cancelled | no_show. |
Delete a resource including its availability. Refused while future pending/confirmed bookings exist; past bookings are kept.
| Field | Type | Required | Description |
|---|---|---|---|
resource_id |
integer | ✓ Yes | ID of the resource to delete. |
Available slots (or nights for rooms) per resource. Give resource_id or type, plus date or from/to (max 31 days). Slots are returned in UTC and in local calendar time. Room nights closed by exceptions (closed:true) or vacations are returned with available:false. With block_on_events on the calendar, busy events are left out as well.
| Field | Type | Required | Description |
|---|---|---|---|
resource_id |
integer | No | One specific resource. |
type |
string | No | All active resources of this type (chair/table/room/...). |
date |
string | No | One day, YYYY-MM-DD (calendar timezone). |
from |
string | No | Start of the date range, YYYY-MM-DD. |
to |
string | No | End of the date range, YYYY-MM-DD (max 31 days). |
party_size |
integer | No | Filter resources by capacity and min/max party. |
Book a resource. Tables/chairs: start_at + end_at (UTC). Rooms: checkin + checkout (YYYY-MM-DD, night granularity); a stay that includes a night closed by exceptions or vacations is refused. The claim is transactional, so a double booking is impossible. The response contains the cancel_token.
| Field | Type | Required | Description |
|---|---|---|---|
resource_id |
integer | ✓ Yes | Resource to book. |
start_at |
string | No | Start (UTC), required for slot resources (chair/table). |
end_at |
string | No | End (UTC), required for slot resources. |
checkin |
string | No | Check-in date YYYY-MM-DD, required for rooms. |
checkout |
string | No | Check-out date YYYY-MM-DD, required for rooms, after checkin. |
party_size |
integer | No | Number of people; validated against capacity and min/max party. |
service_id |
integer | No | Optional service (appointments). |
visitor_name |
string | ✓ Yes | Name of the booker. |
visitor_email |
string | No | Booker email. A confirmation/cancellation email is sent only when the project has its own mail provider (Vault: SMTP credentials, or an API key such as resend_api_key plus a from_email via email_layout); the response field email reports the outcome. |
visitor_phone |
string | No | Phone number. |
notes |
string | No | Notes (allergies, preferences, ...). |
source |
string | No | web | mcp | admin | voice (default mcp). Ignored in the visitor lane and set to web server-side. |
ignore_availability |
boolean | No | Owner only: book outside the availability windows or on closed room nights (the claim check always stays active). Stripped in the visitor lane. |
Cancel a booking via cancel_token (visitor) or booking_id (owner only). Idempotent; completed/no_show cannot be cancelled. The linked event is cancelled as well.
| Field | Type | Required | Description |
|---|---|---|---|
cancel_token |
string | No | Token from the book response or the confirmation email. |
booking_id |
integer | No | Owner only: cancel directly by ID. Stripped in the visitor lane, where only cancel_token counts. |
Read-only status of one booking by its cancel_token, e.g. to show a visitor whether their booking still stands or was moved or cancelled. Returns status, granularity, resource_name, start_at/end_at (UTC) plus start_local/end_local and timezone (slots) or checkin/checkout (rooms). No personal data. Changes nothing.
| Field | Type | Required | Description |
|---|---|---|---|
cancel_token |
string | ✓ Yes | Token from the book response or the confirmation email. |
Public ICS feed URL of a calendar (the secret is generated on the first call). With rotate=true the secret is replaced and the old URL stops working immediately. Subscribe Apple/Google/Outlook to this URL.
| Field | Type | Required | Description |
|---|---|---|---|
calendar_id |
integer | ✓ Yes | Calendar the feed belongs to. |
rotate |
boolean | No | Replace the secret (the old feed URL stops working). |
Link an external ICS feed to this calendar (1 per calendar). Imported events get origin=ics and never change internal events or bookings. They only block booking times when the calendar has block_on_events with "ics" (upsert-calendar). url=null to unlink.
| Field | Type | Required | Description |
|---|---|---|---|
calendar_id |
integer | ✓ Yes | Target calendar. |
url |
string | No | http(s) feed URL (max 500 chars), or null/empty to clear. |
Run the ICS import for one calendar (calendar_id) or for all calendars of the project with an import feed. Upserts on UID, removes events that disappeared from the feed, skips RRULE in v1. Also suited to a scheduled task.
| Field | Type | Required | Description |
|---|---|---|---|
calendar_id |
integer | No | Limit to one calendar; omit for all calendars with an import feed. |
Project settings for the calendar (visitor booking caps, booking-email cap per recipient), which ones were changed, and the platform limits.
No input parameters required.
Change project settings; only the keys you send change, null resets a key to the platform default. Values must stay within the platform limits shown by get-config. Owner only, not available to visitors.
| Field | Type | Required | Description |
|---|---|---|---|
visitor_book_burst_max |
integer | No | Max visitor booking attempts per connection within visitor_book_burst_seconds. |
visitor_book_burst_seconds |
integer | No | Window in seconds for visitor_book_burst_max. |
visitor_book_hourly_max |
integer | No | Max visitor booking attempts per connection per hour. |
recipient_mail_max |
integer | No | Max booking emails to one address from visitor bookings within recipient_mail_window_hours. Above it the booking is saved but no email is sent. |
recipient_mail_window_hours |
integer | No | Window in hours for recipient_mail_max. |
MCP Tool Names
When using this integration through an AI assistant (Claude, ChatGPT, Cursor, etc.), the endpoints are available as MCP tools:
| Endpoint | MCP Tool Name |
|---|---|
| upsert-calendar | calendar_upsert_calendar |
| list-calendars | calendar_list_calendars |
| delete-calendar | calendar_delete_calendar |
| upsert-event | calendar_upsert_event |
| delete-event | calendar_delete_event |
| list-events | calendar_list_events |
| upsert-resource | calendar_upsert_resource |
| list-resources | calendar_list_resources |
| set-availability | calendar_set_availability |
| list-bookings | calendar_list_bookings |
| update-booking-status | calendar_update_booking_status |
| delete-resource | calendar_delete_resource |
| get-slots | calendar_get_slots |
| book | calendar_book |
| cancel-booking | calendar_cancel_booking |
| get-booking | calendar_get_booking |
| get-feed-url | calendar_get_feed_url |
| set-import-feed | calendar_set_import_feed |
| run-import | calendar_run_import |
| get-config | calendar_get_config |
| set-config | calendar_set_config |
Website