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:defaultorprivate(people who can only see "busy" never see the details of a private event).- A repeating event is one event with a
recurrencerule. Changed or cancelled single occurrences are stored as exceptions linked byseries_idandoriginal_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,idreturns busy periods.POST /calendar/suggesttakesusers,calendars,from,to,duration(minutes),timezone,day_start,day_endandlimitand returnsslotswhen everyone is free, plusunknownfor people whose calendars you cannot see.
Subscription link
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 |
Related
- Public endpoints
- Functions SDK:
axis.calendar.* - In the product: Calendar