Solel//dev docs

Calendar

The core keeps everyone's calendars, so the Calendar app, phones, Mail and your app all see the same events. Your back end reaches them through the core's calendar API, acting for the person using the app.

Grants

  • calendar.read lets your app make GET requests.
  • calendar.write lets it make everything else.

Call with your token and the person in X-Solel-Person, as Acting for a person describes. An app installed for one person always acts for them, so it can leave the header out. Your app sees and changes only what that person could: their own calendars and those shared with them. See Calendars and who sees them.

An event

{
  "id": "…", "calendarId": "…", "uid": "…", "etag": "…",
  "title": "Swimming", "start": "2026-10-24T09:00:00+11:00", "end": "2026-10-24T10:00:00+11:00",
  "allDay": false, "timeZone": "Australia/Melbourne", "location": "Fitzroy pool", "notes": "",
  "repeat": { "freq": "weekly", "days": ["SA"], "until": "2026-12-19" },
  "reminders": [30],
  "occurrence": "2026-10-31T09:00:00+11:00", "moved": false
}
  • Times. start and end are RFC 3339 times. For an all-day event they're dates, and end is the day after it finishes. A timeZone keeps an event at the same local time across daylight saving changes; without one, it's stored in UTC.
  • Repeats. freq is daily, weekly, monthly or yearly, with an optional interval, days (MO to SU), and either until or count. A repeat another app wrote that says more than this comes back with its rule as written, and is kept unless you change it.
  • One time of a repeat. Listed events give each time a repeat happens as its own entry, with occurrence, when that time was due. Pass ?occurrence= with that value to change or remove just that time.
  • Reminders are minutes before the start, up to five.
  • Invitations carry an organizer and attendees, and are read-only here.
  • Conflicts. Send If-Match with the event's etag when you change or remove it. If someone changed it in the meantime, the answer is 412.

Each event is kept as the iCalendar object a phone sends, so nothing your app writes is lost.

Endpoints

Request What it does
GET /api/calendar/calendars The person's calendars, then those shared with them, each with its access: owner, change or see
POST /api/calendar/calendars Makes one: {"name", "colour"}, with colour flare, ink or umber
PATCH /api/calendar/calendars/{id} Renames it or changes its colour
DELETE /api/calendar/calendars/{id} Deletes one of theirs, or stops showing one shared with them
PUT /api/calendar/calendars/{id}/shares {"shares": [{"personId", "access": "see" or "change"}]}. Each new person gets a notification
GET /api/calendar/people Who a calendar can be shared with
GET /api/calendar/events?from=&to=&calendar= Every time something happens between from and to, up to 400 days at once
POST /api/calendar/calendars/{id}/events Adds an event. It needs a title and a start, and lasts an hour unless you say otherwise
GET /api/calendar/events/{id} One event
PATCH /api/calendar/events/{id}?occurrence= Changes any of its fields. Moving the start keeps the length
DELETE /api/calendar/events/{id}?occurrence= Removes it, or just that time of it
POST /api/calendar/events/{id}/move Moves it to another calendar: {"calendarId"}
POST /api/calendar/calendars/{id}/import Brings in an .ics file of up to 32 MiB, sent as text/calendar. Answers {"added", "had", "skipped"}
GET /api/calendar/calendars/{id}/export The whole calendar as an .ics file
POST /api/calendar/subscriptions Subscribes to a calendar on the internet: {"url", "name", "colour"}
POST /api/calendar/calendars/{id}/refresh Fetches a subscription again now. Send {}
GET /api/calendar/holidays, PUT /api/calendar/holidays Where the person's public holidays come from, and {"country", "region"} to choose