Calendar API
The Calendar API is available under /apis/v1/calendar and requires a Ration bearer token. Calendar, event, and scheduling data is tenant-scoped to the authenticated user.
Authorization: Bearer <ration_access_token>
Content-Type: application/json
Ration also supports CalDAV interoperability for compatible calendar clients. This REST reference covers only the public /apis/v1 API.
Calendars
List calendars
GET /apis/v1/calendar
| Query parameter | Type | Required | Description |
|---|---|---|---|
limit | Integer | No | Page size; defaults to 50. |
cursor | String | No | Cursor returned by a prior page. |
Response: a paginated calendar result returned by Ration, including calendar records and its cursor metadata.
Create a calendar
POST /apis/v1/calendar
Send calendar attributes at the top level.
{ "name": "Product", "color": "#006699" }
Response: { "calendar": { ... } }.
Update or delete a calendar
PUT /apis/v1/calendar/:calendar_id
Calendar attributes may be supplied either directly or nested under calendar:
{ "calendar": { "name": "Product delivery", "color": "#006699" } }
Response: { "calendar": { ... } }. The returned object is re-read after the update, so it is suitable for refreshing the client view.
DELETE /apis/v1/calendar/:calendar_id
| Body/query field | Type | Required | Description |
|---|---|---|---|
move_to_calendar_id | String | No | Destination calendar for existing events before deletion. |
Successful deletion returns 204 No Content.
Events
List events or expanded instances
GET /apis/v1/calendar/:calendar_id/events
| Query parameter | Type | Required | Description |
|---|---|---|---|
start, end | ISO 8601 date-time | No | Event window. Omitted bounds default from the Unix epoch through five years ahead. |
limit | Integer | No | Page size; defaults to 50. |
cursor | String | No | Event list cursor. |
GET /apis/v1/calendar/:calendar_id/instances
This expands recurring events into occurrences. Both start and end are required ISO 8601 date-times; it also accepts limit and cursor.
Create or update an event
POST /apis/v1/calendar/:calendar_id/events
PUT /apis/v1/calendar/:calendar_id/events/:event_id
Place event attributes under event:
{
"event": {
"summary": "Design review",
"dtstart": "2026-08-10T09:00:00+01:00",
"dtend": "2026-08-10T10:00:00+01:00",
"description": "Review the proposed experience.",
"location": "Video meeting",
"attendees": [{ "email": "sam@example.com", "name": "Sam" }]
}
}
The event model supports standard calendar fields such as title/summary, date and time, description, location, attendees, recurrence, alarms, and scheduling metadata. Responses are { "event": { ... } }.
GET /apis/v1/calendar/:calendar_id/events/:event_id returns the same envelope. DELETE on that path returns 204 No Content.
Batch event changes
POST /apis/v1/calendar/:calendar_id/events/batch
{
"operations": {
"create": [{ "summary": "Kickoff", "dtstart": "…", "dtend": "…" }],
"update": [{ "event_id": "event-id", "summary": "Updated kickoff" }],
"delete": ["event-id"]
}
}
The create, update, and delete arrays may be placed directly at the top level instead. Response:
| Field | Type | Description |
|---|---|---|
created, updated, deleted | Array | One result per requested operation. |
*.status | String | ok or error. |
*.event, *.event_id | Object or String | Created/updated event or the affected event ID. |
*.error | String | Error detail for an individual failed operation. |
RSVP and propose a time
PUT /apis/v1/calendar/:calendar_id/events/:event_id/rsvp
{ "response": "accepted" }
The response generates and dispatches a scheduling reply: { "status": "ok", "schedule_statuses": [...] }.
POST /apis/v1/calendar/:calendar_id/events/:event_id/proposals accepts the proposal fields required for an alternative meeting time and returns { "status": "proposal_sent", "schedule_statuses": [...] }.
Synchronization and scheduling
Incremental sync
POST /apis/v1/calendar/:calendar_id/sync
{ "sync_token": "token-from-a-prior-sync" }
Returns the changes since that token. An invalid token produces an error that includes valid_sync_token when Ration can supply a usable replacement.
iTIP scheduling messages
| Method | Path | Required body | Response |
|---|---|---|---|
POST | /:calendar_id/scheduling/outbox | ics | { "status": "sent", "schedule_statuses": [...] } |
POST | /:calendar_id/scheduling/inbox | ics | { "status": "processed" } |
GET | /:calendar_id/scheduling/messages | — | Paginated scheduling-message result. |
GET | /:calendar_id/scheduling/messages/:message_id | — | { "message": { ... } } |
Paths in this table are relative to /apis/v1/calendar. Supply a complete iCalendar (.ics) payload in ics. The outbox dispatches it to recipients; the inbox validates and applies it to the calendar.
Free/busy lookup
POST /apis/v1/calendar/scheduling/free_busy
{
"start_date": "2026-08-10T09:00:00+01:00",
"end_date": "2026-08-10T18:00:00+01:00",
"attendees": ["sam@example.com", { "email": "lee@example.com" }]
}
dtstart and dtend are accepted aliases for start_date and end_date. The response returns merged busy windows for the caller and each resolved attendee. Off-tenant addresses can be represented as unresolved because Ration cannot inspect their calendars.
Time polls and holiday availability
Time polls
| Method | Path | Request | Response |
|---|---|---|---|
POST | /polls | title, calendar_id, attendees, and at least two options (dtstart, dtend); optional draft. | Created poll (201). |
GET | /polls/:id | — | Poll, tally, and my_vote. |
POST | /polls/:id/vote | option_ids array. | Updated poll and my_vote. |
POST | /polls/:id/finalize | — | { "poll": {...}, "event": {...} }. |
Paths in this table are relative to /apis/v1/calendar. Only the organizer can finalize a poll. A poll needs at least two options and cannot be finalized without a winning vote.
Holidays and subscriptions
| Method | Path | Description |
|---|---|---|
GET | /holidays | Holiday catalogue/lookup data. |
GET | /holidays/effective?year=2026 | Effective countries and holidays for the caller. |
GET | /holiday-subscriptions | Tenant default, caller additions, effective countries, and can_manage. |
PUT | /holiday-subscriptions | Set the caller's countries array (or comma-separated string). |
PUT | /holiday-subscriptions/tenant | Tenant administrators set countries, custom_days, and speedy_meetings. |
The tenant update requires the organization-management permission; otherwise it returns 403 { "error": "forbidden" }.
Errors
| Status | Meaning |
|---|---|
401 | Missing or invalid bearer authentication. |
403 | Tenant context is required, or the caller lacks calendar/tenant permission. |
404 | Calendar, event, poll, or scheduling message was not found. |
400 | Invalid date range, invalid ICS payload, incomplete poll, or other invalid request. |
422 | Calendar/event operation cannot be applied. |