The calendar bridge lists the device’s calendars and their events in a date range, and creates, updates and deletes events.
dotnet add package Shiny.AppDeviceBridge.Calendar
builder.UseAppDeviceBridge(
bridge => bridge.AddCalendarBridge(),
| Client |
C# |
TypeScript |
ICalendarBridge |
AddCalendarBridgeClient() |
CalendarBridge |
| Topic |
Details |
| Platforms |
Android, iOS, Mac Catalyst, macOS and Windows. |
| Access |
POST calendar/access takes ReadWrite (the default), ReadOnly or WriteOnly. Write-only access (iOS 17+) is reported as Restricted. |
| Listing |
GET calendar/events requires start and end, at most 366 days apart. Paging works like contacts. |
| Reminders |
reminderMinutes counts minutes before the start. |
| Read-only fields |
attendees, the organizer and recurrence can be read but not written. |
| Read-only calendars |
writing to one returns 403 read_only, and so does writing to a system calendar on Windows, which only allows writes to app-owned calendars. |
| Deleting |
DELETE calendar/events/{id}?series=true removes the rest of a recurring series rather than one occurrence. |
| Mac Catalyst, sandboxed macOS |
also need the com.apple.security.personal-information.calendars entitlement. Without it, access is denied without a prompt. |
Every route answers 403 access_denied until access has been granted.
import { CalendarBridge } from "@shinyorg/appdevicebridge";
const calendar = new CalendarBridge();
await calendar.requestAccess({ access: "ReadWrite" });
const week = await calendar.getEvents(new Date(), new Date(Date.now() + 7 * 864e5), { limit: 50 });
for (const e of week.items) console.log(e.start, e.title);
const created = await calendar.createEvent({
start: "2026-10-12T15:00:00-04:00",
end: "2026-10-12T16:00:00-04:00",
await calendar.updateEvent(created.id!, { location: "123 Main St" });
Event lists page with offset and limit; hasMore says whether to ask again.
Where calendar access stands, without asking.
C#ICalendarBridge.GetAccessAsyncTSCalendarBridge.getAccess
- Response
- 200 CalendarAccessResult
CalendarAccessResult · 1 field
POST/_bridge/calendar/access#Asks for access, prompting if the OS has not asked before.
C#ICalendarBridge.RequestAccessAsyncTSCalendarBridge.requestAccess
- Body
application/json · CalendarAccessRequestCalendarAccessRequest · 1 field
- Response
- 200 CalendarAccessResult
CalendarAccessResult · 1 field
GET/_bridge/calendar/calendars#C#ICalendarBridge.GetCalendarsAsyncTSCalendarBridge.getCalendars
- Response
- 200 CalendarList
CalendarList · 1 field
GET/_bridge/calendar/events#Events overlapping a range of at most 366 days, a page at a time, in start order.
C#ICalendarBridge.GetEventsAsyncTSCalendarBridge.getEvents
| Parameter | In | Type | |
|---|
start | query | Date | string | required |
end | query | Date | string | required |
calendarId | query | string | null | optional |
search | query | string | null | optional |
offset | query | number | optional |
limit | query | number | optional |
- Response
- 200 CalendarEventPage
CalendarEventPage · 4 fields
POST/_bridge/calendar/events#Creates an event. A read-only calendar fails with read_only.
C#ICalendarBridge.CreateEventAsyncTSCalendarBridge.createEvent
- Body
application/json · NewCalendarEventNewCalendarEvent · 10 fields
title | string | At most 1,000 characters. |
start | Date | string | |
end | Date | string | Not before start. |
calendarId | string | null | The calendar to create it in; the device's default calendar when null. |
description | string | null | At most 10,000 characters. |
location | string | null | |
isAllDay | boolean | |
availability | EventAvailability | |
url | string | null | An absolute http or https URL. |
reminderMinutes | number[] | null | Whole minutes before the start; at most 10, each up to four weeks. |
- Response
- 200 CalendarEvent
CalendarEvent · 15 fields
id | string | null | |
calendarId | string | null | |
title | string | |
description | string | null | |
location | string | null | |
start | string | |
end | string | |
isAllDay | boolean | |
availability | EventAvailability | |
url | string | null | |
isRecurring | boolean | |
recurrenceRule | string | null | |
reminderMinutes | number[] | |
attendees | CalendarAttendee[] | |
organizer | CalendarAttendee | null | |
GET/_bridge/calendar/events/{id}#C#ICalendarBridge.GetEventAsyncTSCalendarBridge.getEvent
| Parameter | In | Type | |
|---|
id | path | string | required |
- Response
- 200 CalendarEvent
CalendarEvent · 15 fields
id | string | null | |
calendarId | string | null | |
title | string | |
description | string | null | |
location | string | null | |
start | string | |
end | string | |
isAllDay | boolean | |
availability | EventAvailability | |
url | string | null | |
isRecurring | boolean | |
recurrenceRule | string | null | |
reminderMinutes | number[] | |
attendees | CalendarAttendee[] | |
organizer | CalendarAttendee | null | |
PUT/_bridge/calendar/events/{id}#Changes only what changes sets. An event cannot move between calendars.
C#ICalendarBridge.UpdateEventAsyncTSCalendarBridge.updateEvent
| Parameter | In | Type | |
|---|
id | path | string | required |
- Body
application/json · CalendarEventChangesCalendarEventChanges · 9 fields
title | string | null | |
start | Date | string | null | |
end | Date | string | null | |
description | string | null | |
location | string | null | |
isAllDay | boolean | null | |
availability | EventAvailability | null | |
url | string | null | |
reminderMinutes | number[] | null | |
- Response
- 200 CalendarEvent
CalendarEvent · 15 fields
id | string | null | |
calendarId | string | null | |
title | string | |
description | string | null | |
location | string | null | |
start | string | |
end | string | |
isAllDay | boolean | |
availability | EventAvailability | |
url | string | null | |
isRecurring | boolean | |
recurrenceRule | string | null | |
reminderMinutes | number[] | |
attendees | CalendarAttendee[] | |
organizer | CalendarAttendee | null | |
DELETE/_bridge/calendar/events/{id}#Deletes an event — or, with series, the rest of the recurring series it belongs to.
C#ICalendarBridge.DeleteEventAsyncTSCalendarBridge.deleteEvent
| Parameter | In | Type | |
|---|
id | path | string | required |
series | query | boolean | optional |
- Response
- 204 No content
This bridge raises no events — everything it does is a request and its response.
JSON property names are camelCase and enums travel as their names. A ? marks a property the payload may omit;| null one that may be null.
CalendarAccessResultobject#Where a permission stands. Reported by every bridge that needs one; the names match Shiny's own.
"Unknown""NotSupported""NotSetup""Disabled""Restricted""Denied""Available"
CalendarAccessRequestobject#The access to ask for. Write-only is iOS 17 and later; elsewhere it is treated as read-write.
"ReadOnly""WriteOnly""ReadWrite"
id | string | null | |
name | string | |
color | string | null | |
isReadOnly | boolean | |
account | string | null | |
An event as the device holds it. Attendees, the organizer and recurrence can be read but not written.
id | string | null | |
calendarId | string | null | |
title | string | |
description | string | null | |
location | string | null | |
start | string | |
end | string | |
isAllDay | boolean | |
availability | EventAvailability | |
url | string | null | |
isRecurring | boolean | |
recurrenceRule | string | null | |
reminderMinutes | number[] | |
attendees | CalendarAttendee[] | |
organizer | CalendarAttendee | null | |
"Busy""Free""Tentative""Unavailable"
"Required""Optional""Resource""Unknown"
"Unknown""Pending""Accepted""Declined""Tentative"
An event to create. title, start and end are required.
title | string | At most 1,000 characters. |
start | Date | string | |
end | Date | string | Not before start. |
calendarId? | string | null | The calendar to create it in; the device's default calendar when null. |
description? | string | null | At most 10,000 characters. |
location? | string | null | |
isAllDay? | boolean | |
availability? | EventAvailability | |
url? | string | null | An absolute http or https URL. |
reminderMinutes? | number[] | null | Whole minutes before the start; at most 10, each up to four weeks. |
CalendarEventChangesobject#Changes to an event. Anything left null stays as it is; an empty reminderMinutes clears them, and an empty url removes it.
title? | string | null | |
start? | Date | string | null | |
end? | Date | string | null | |
description? | string | null | |
location? | string | null | |
isAllDay? | boolean | null | |
availability? | EventAvailability | null | |
url? | string | null | |
reminderMinutes? | number[] | null | |
These routes sit under AppDeviceBridgePolicies.Bridges like every other bridge: callers on this device by default.
See Security.