Calendar Sync & API Reference
Connect Apple Calendar with iOS Shortcuts or Google Calendar with Apps Script. Each member can sync their own events into the same Shalendar calendar.
iOS Shortcut Setup
Step-by-step Apple Calendar sync workflow
Before you sync
- Each member can run a copy of the Shortcut on their own iPhone.
- Set
partner_nameto your exact member name, or set it to"BOTH"to sync joint events to all members on standard calendars. Privacy-capable calendars sync one member at a time. - Set
sourceto"apple"or"google". Each source has its own sync window and won’t remove the other source’s events. - For privacy-capable calendars, use your own member name and access password. Other members only receive Busy for your event titles.
- Format dates as ISO 8601 with a timezone offset or
Z. - A stable unique event ID is needed to update the same event on later runs. A title or Name value may repeat.
- Without
sync_startandsync_end, a run with no events will not remove previously synced events. - With a sync window, missing events from the selected source are removed inside that window. Manually created events and events from the other provider are kept.
Step 1Set up your calendar and Shortcut
Create a calendar in Shalendar first. On your iPhone, create a Shortcut named Sync Shalendar. Add three Text actions for the calendar name, shared password, and your exact member name; save each with Set Variable. If editing a shared Shortcut, replace any example credentials in both Text actions and request body fields. Keep the password private when sharing or exporting a Shortcut.
Step 2Find Calendar Events
Add Find Calendar Events and filter Start Date to the next 7 days. Add a Calendar filter if you only want to sync one Apple Calendar.
Step 3Loop Events & Extract Details
Add Repeat with Each for the found events. Inside the loop, get each event's Title, Start Date, and End Date. Format both dates as ISO 8601 with time. Also get a stable unique event identifier for external_shortcut_id. Using the event's Name or title as the ID can merge distinct events with the same name.
Step 4Format Items into JSON Dictionaries
Inside the loop, add a Dictionary with these keys:
• title → Title
• start_time → Start Date (Formatted as ISO 8601)
• end_time → End Date (Formatted as ISO 8601)
• external_shortcut_id → stable unique event ID
Add each dictionary to an EventList variable. Pass that list as the events array, including when it contains just one event.
Step 5Send POST Request to /api/sync
After the loop, add Get Contents of URL:
• URL: https://shalendar.aaryandehade.com/api/sync
• Method: POST
• Header: Content-Type: application/json
• Request Body: JSON containing calendar_name, password, partner_name, timezone, and events (the EventList variable). You can use the JSON body editor, or send a Text action containing valid JSON as a File body with the same header. Run it once and check for success: true before adding automation.
Step 6Automate Background Sync
In the Automation tab, add a Time of Day personal automation, set it to run daily, and select Sync Shalendar. Choose Run Immediately if available on your iOS version, or turn off Ask Before Running.
Get Contents of URL configuration
URL
https://shalendar.aaryandehade.com/api/sync
Method
POST
Header: Content-Type
application/json
Body Type
JSON, or File with JSON Text
Google Calendar Sync
Import one member’s Google Calendar events into Shalendar.
- Open Google Apps Script and create a standalone project.
- Download shalendar-google-sync.gs, then paste its contents into the script editor and save.
- Under Project Settings → Script properties, add
SHALENDAR_NAME,SHALENDAR_PASSWORD, andSHALENDAR_MEMBER. The password is your member access password on privacy-capable calendars, or the shared password on standard calendars. - Optionally add
GOOGLE_CALENDAR_IDto sync a specific calendar. Leave it unset to use your default Google Calendar. - Run
syncGoogleCalendarToShalendaronce and approve Google Calendar and external request access. - Run
installShalendarGoogleSyncTriggeronce to install the 6-hour refresh. Shalendar tracks Google and Apple events separately, even when the same member uses both.
google events within its date range. Events outside that window and all Apple-synced events remain unchanged. Review the selected calendar and member properties before enabling the trigger.Privacy & Display
Choose title privacy when you create a calendar.
Privacy-capable calendars
Turn on Privacy capable in the create-calendar form. This choice is saved with the calendar and cannot be changed later. Each member signs in with their own name and access password. Give each person only their password; event titles are replaced with Busy for other members. The signed-in member can add, edit, and delete only their own events. Calendar owners can manage member settings.
The first member uses the password entered for Person 1. Enter a different password for every additional member, then share it directly with that person. Privacy calendars sync one member at a time using that member’s password.
Long events
Events lasting 23 hours or more are hidden from Day, Week, Month, and Agenda by default. Use Show 23+ hr in the calendar toolbar to display them. Hidden events still count as busy when Shalendar finds mutual free time.
API Reference
REST endpoint documentation for /api/sync
/api/syncWithin each member and source sync window, matches events by external_shortcut_id and removes stored events absent from that source’s payload. Set source to apple or google. Supply both sync_start and sync_end to cover a full window, including a run with zero events.
calendar_name + password in JSON body
application/json
success and sync stats
Payload Schema
Fields accepted by /api/sync.
Request Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
| calendar_name | string | required | The unique slug name of your Shalendar calendar (e.g. shalendar-demo). |
| password | string | required | The calendar password for standard calendars; the selected member’s access password for privacy-capable calendars. |
| partner_name | string | optional | Member display name (e.g. "Aaru"). Standard calendars can use "BOTH"; privacy-capable calendars require one existing member name. |
| timezone | string | optional | Timezone for a newly created member (e.g. America/Los_Angeles). Defaults to UTC; event timestamps still need an offset or Z. |
| source | string | optional | "apple" or "google". Defaults to "apple". Sync cleanup only removes missing events from the same source. |
| events | array | optional | Array of event objects. Defaults to an empty array; an empty array changes nothing unless a sync window is supplied. |
| sync_start | ISO 8601 | optional | Start of sync window. With sync_end, missing events fully inside the window are removed. Defaults to the earliest supplied event start when events are present. |
| sync_end | ISO 8601 | optional | End of sync window. Defaults to the latest supplied event end when events are present. |
Event Object Fields (inside events[])
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | optional | Event title (supports text and emojis). Defaults to Untitled Event. |
| start_time | ISO 8601 | required | ISO 8601 start time with an offset or Z (e.g. 2026-09-14T08:00:00-07:00). |
| end_time | ISO 8601 | required | ISO 8601 end time with an offset or Z. |
| external_shortcut_id | string | optional | Stable unique ID for this event within its source. Strongly recommended: without one, repeated syncs can create duplicates. |
cURL Test
Copy-paste ready payload samples and cURL commands
Full Request Payload
{
"calendar_name": "shalendar-demo",
"password": "your-shared-password",
"partner_name": "demo-name",
"source": "apple",
"timezone": "America/Los_Angeles",
"sync_start": "2026-09-14T00:00:00-07:00",
"sync_end": "2026-09-21T23:59:59-07:00",
"events": [
{
"title": "Morning Run 🏃",
"start_time": "2026-09-14T08:00:00-07:00",
"end_time": "2026-09-14T09:00:00-07:00",
"external_shortcut_id": "apple-cal-uuid-abc123"
},
{
"title": "Dinner Date 🍷",
"start_time": "2026-09-14T19:00:00-07:00",
"end_time": "2026-09-14T21:00:00-07:00",
"external_shortcut_id": "apple-cal-uuid-def456"
}
]
}cURL Test Command
curl -X POST https://shalendar.aaryandehade.com/api/sync \
-H "Content-Type: application/json" \
-d '{
"calendar_name": "shalendar-demo",
"password": "your-shared-password",
"partner_name": "BOTH",
"source": "apple",
"timezone": "America/Los_Angeles",
"events": [
{
"title": "Weekend Trip 🚗",
"start_time": "2026-09-19T09:00:00-07:00",
"end_time": "2026-09-20T18:00:00-07:00",
"external_shortcut_id": "trip-event-1001"
}
]
}'Common Questions
Frequently asked questions
Q1.Can one Shalendar member sync Apple and Google calendars?
Yes. Run separate Apple Shortcuts and Google Apps Script syncs with the same partner_name, using source set to "apple" or "google". Each source cleans up only its own events.
Q2.How does a privacy-capable calendar work?
Privacy is chosen when the calendar is created and cannot be changed later. Each member signs in with their own name and password. Other members receive only Busy in place of event titles.
Q3.Can privacy calendars sync events for BOTH members?
No. A privacy calendar sync must authenticate one member at a time so event titles stay private.
Q4.Why are my event times shifted?
Use ISO 8601 timestamps with an explicit offset, such as 2026-09-14T08:00:00-07:00, or UTC with Z. Check the selected calendar timezone view as well.
Q5.What is external_shortcut_id used for?
It identifies the same event across runs. Use a stable unique value; an event title or Name alone may collide with another event.
Q6.Why did an empty sync leave old events?
With no events, the API needs both sync_start and sync_end to know which stored events to remove.