Calendar API

Calendars, events with repeats and guests, availability, import and export.

Calendar covers personal, team and resource calendars, events with repeats and guests, booking pages and calendars built from the dates on your records. This API reads and manages calendars and events and checks availability. The public booking, invitation and subscription links visitors use are in Public endpoints.

If the Calendar app is switched off in Settings › Apps, these routes answer 404 NOT_FOUND.

Note: Personal calendars belong to people. An access key can work with team (organisation) calendars and record calendars, which are controlled by the calendar:* permissions on the calendar's key, but it has no personal calendar of its own.

Endpoints

Method Path What it does
GET /orgs/{orgId}/calendar/calendars List calendars you can see (?all=1 also includes other members' personal calendars that you can only see through their visibility setting)
POST /orgs/{orgId}/calendar/calendars Create a calendar
GET /orgs/{orgId}/calendar/calendars/{calId} Get a calendar
PATCH /orgs/{orgId}/calendar/calendars/{calId} Change a calendar
DELETE /orgs/{orgId}/calendar/calendars/{calId} Delete a calendar
POST /orgs/{orgId}/calendar/calendars/{calId}/feed Turn the subscription link on or off
GET /orgs/{orgId}/calendar/calendars/{calId}/export Download .ics
POST /orgs/{orgId}/calendar/calendars/{calId}/import Import .ics
GET · POST · DELETE /orgs/{orgId}/calendar/calendars/{calId}/shares[/{shareId}] List, add, remove shares
PATCH /orgs/{orgId}/calendar/calendars/{calId}/records/{recordId} Reschedule a record shown on a record calendar
GET /orgs/{orgId}/calendar/events List events in a time window
POST /orgs/{orgId}/calendar/events Create an event
GET /orgs/{orgId}/calendar/events/{eventId} Get an event
PATCH /orgs/{orgId}/calendar/events/{eventId} Change an event
DELETE /orgs/{orgId}/calendar/events/{eventId} Delete an event
POST /orgs/{orgId}/calendar/events/{eventId}/rsvp Answer an invitation
GET /orgs/{orgId}/calendar/freebusy Busy periods
POST /orgs/{orgId}/calendar/suggest Suggest meeting times
GET /orgs/{orgId}/calendar/records/{typeKey}/{recordId}/events Events linked to a record

What you may do on a team or record calendar depends on its key: calendar:read to see events, calendar:write to add, move and delete them, calendar:manage for the calendar itself (settings, booking page, subscription link, deleting it). A calendar's visibility setting can give every member a floor of "busy" or "read" access, but never write access. See Permissions reference.

Calendars

{
  "id": "0190f600-…",
  "key": "meeting-room-1",
  "name": "Meeting room 1",
  "description": "",
  "color": "teal",
  "kind": "org",
  "primary": false,
  "visibility": "busy",
  "timezone": "Asia/Kolkata",
  "access": "write",
  "settings": { "no_overlap": true, "default_reminders": [10] },
  "booking_url": "",
  "created_at": "2026-10-01T08:00:00Z",
  "updated_at": "2026-10-01T08:00:00Z"
}

kind is personal, org or records. access is what you may do here: none, busy, read, write, manage or owner.

POST and PATCH take: key and kind (set at creation only; key is 2 to 64 lowercase letters, digits, - or _, and keys starting u- are reserved), name, description (up to 1,000 characters), color, visibility (none, busy or read), timezone (an IANA zone such as Asia/Kolkata) and settings.

settings can hold:

Key Meaning
no_overlap Refuse an event that overlaps another on this calendar. Makes it a bookable resource (room, vehicle). A clash answers 409 SLOT_TAKEN
default_reminders Minutes before the start, for events that state none
booking The public booking page: enabled, title, description, durations (minutes, the first is the default), slot_step, buffer, min_notice, horizon_days, hours (for example {"mon": [["09:00","17:00"]]}), location
source For a record calendar: type_key, start_field, end_field, title_field. The calendar reads those records live under each viewer's permissions

Shares: POST …/shares takes { "email": "asha@example.com", "level": "read" } (level busy, read, write or manage) and answers 201; DELETE …/shares/{shareId} answers 200 with { "deleted": true }. Rescheduling a record: PATCH …/records/{recordId} takes { "start": …, "end": … } (RFC 3339 or YYYY-MM-DD; end optional) and answers { "moved": true }. Deleting a calendar answers 200 with { "deleted": true }.

Events

{
  "id": "0190f601-…",
  "calendar_id": "0190f600-…",
  "calendar_name": "Meeting room 1",
  "title": "Weekly stand-up",
  "description": "",
  "location": "Room 1",
  "start": "2026-10-05T04:30:00Z",
  "end": "2026-10-05T05:00:00Z",
  "all_day": false,
  "timezone": "Asia/Kolkata",
  "recurrence": "FREQ=WEEKLY;BYDAY=MO",
  "status": "confirmed",
  "visibility": "default",
  "reminders": [10],
  "source": "manual",
  "attendees": [ { "id": "…", "email": "asha@example.com", "name": "Asha", "status": "needs_action" } ],
  "can_edit": true,
  "created_at": "2026-10-01T08:00:00Z",
  "updated_at": "2026-10-01T08:00:00Z"
}
  • status: confirmed, tentative, cancelled. visibility: default or private (people who can only see "busy" never see the details of a private event).
  • A repeating event is one event with a recurrence rule. Changed or cancelled single occurrences are stored as exceptions linked by series_id and original_start.

POST /orgs/{orgId}/calendar/events

Field Type Required Notes
title string Yes
start string Yes RFC 3339, or YYYY-MM-DD for an all-day event
end string No Same formats. Timed events default to one hour after start
calendar_id string No The calendar to put it on. People's events go on their own calendar if omitted; an access key should always set it
all_day boolean No
timezone string No IANA zone the event lives in. Repeats follow this zone's clock
recurrence string No A repeat rule such as FREQ=WEEKLY;BYDAY=MO
description, location, color string No Title up to 300, location up to 500, description up to 20,000 characters
status, visibility string No See above
reminders array of numbers No Minutes before. Up to 5, each up to 7 days (10,080 minutes)
attendees array No Up to 100. Each is { "user_id": … } or { "email": …, "name": … }. Guests are emailed an invitation
record_type, record_id string No Link the event to a record
notify boolean No Set false to skip invitation emails. Default true
curl -s -X POST https://axisiq.co/api/v1/orgs/$ORG/calendar/events \
  -H "Authorization: Bearer $AXIS_KEY" -H "Content-Type: application/json" \
  -d '{"calendar_id": "0190f600-…", "title": "Site visit", "start": "2026-10-07T05:00:00Z", "end": "2026-10-07T06:00:00Z", "attendees": [{"email": "asha@example.com"}]}'

Response 201 with the event.

GET /orgs/{orgId}/calendar/events

Parameter Notes
from, to Required. RFC 3339 or YYYY-MM-DD. A window is at most 400 days
calendars Comma-separated calendar ids. Default: all you can see
invites 0 to leave out events you were only invited to

Returns { "events": [ … ] } with repeating events expanded into occurrences (at most 2,000). Each occurrence has event_id, series_id, calendar_id, start, end, all_day, title, status, recurring, and details: false when you can only see that the time is busy.

PATCH and DELETE on repeating events

Both take scope and occurrence as query parameters:

scope Effect
all (default) The whole series
this Only the occurrence starting at occurrence (an RFC 3339 time)
following That occurrence and all later ones

PATCH takes any of the creation fields. DELETE answers 200 with { "deleted": true }; add notify=0 to skip cancellation emails.

POST /orgs/{orgId}/calendar/events/{eventId}/rsvp

{ "status": "accepted" } where status is accepted, declined, tentative or needs_action. Returns the event.

Availability

  • GET /calendar/freebusy?from=&to=&users=id,id&calendars=id,id returns busy periods.
  • POST /calendar/suggest takes users, calendars, from, to, duration (minutes), timezone, day_start, day_end and limit and returns slots when everyone is free, plus unknown for people whose calendars you cannot see.

POST …/calendars/{calId}/feed with { "enabled": true } creates a secret .ics subscription link and returns the calendar with feed_url. { "enabled": false } switches it off. Turning it on again makes a new link and the old one stops working. Needs calendar:manage. Records calendars have no feed.

Import and export

GET …/export returns an .ics file. POST …/import takes an .ics as a multipart upload with a file field or as the raw body. Up to 2,000 events per import; events with a UID that already exists are updated instead of duplicated. Response: { "created": 12, "updated": 3, "skipped": 0, "warnings": [] }.

Errors

Status Code When
400 VALIDATION_ERROR Missing title or start, bad date, window over 400 days, too many attendees
403 FORBIDDEN The calendar permission is missing
404 NOT_FOUND No such calendar or event, or you may not see it
409 KEY_TAKEN Calendar key already used
409 SLOT_TAKEN The calendar does not allow overlaps and that time is taken