For developers and product teams building calendar-centric applications, integrating with Apple Calendar presents a unique challenge. Enter CalDAV, a versatile protocol that unlocks a world of possibilities for Apple Calendar integration and beyond.

CalDAV, WebDAV, and iCalendar

  1. CalDAV and WebDAV: CalDAV, or Calendar Distributed Authoring and Versioning, is an extension of WebDAV, a protocol for collaborative editing and management of files on web servers. CalDAV extends WebDAV to support calendar-specific operations, providing a standardized way for clients to access and manage calendar events.

    One unusual detail of WebDav is that this XML based protocol uses the HTTP methods PROPFIND and REPORT alot.

   REPORT /bernard/work/ HTTP/1.1
   Host: cal.example.com
   Depth: 1
   Content-Type: application/xml; charset="utf-8"
   Content-Length: xxxx

   <?xml version="1.0" encoding="utf-8" ?>
   <C:calendar-query xmlns:D="DAV:"
                 xmlns:C="urn:ietf:params:xml:ns:caldav">
     <D:prop>
       <D:getetag/>
       <C:calendar-data>
         <C:comp name="VCALENDAR">
           <C:prop name="VERSION"/>
           <C:comp name="VEVENT">
             <C:prop name="SUMMARY"/>
             <C:prop name="UID"/>
             <C:prop name="DTSTART"/>
             <C:prop name="DTEND"/>
             <C:prop name="DURATION"/>
             <C:prop name="RRULE"/>
             <C:prop name="RDATE"/>
             <C:prop name="EXRULE"/>
             <C:prop name="EXDATE"/>
             <C:prop name="RECURRENCE-ID"/>
           </C:comp>
           <C:comp name="VTIMEZONE"/>
         </C:comp>
       </C:calendar-data>
     </D:prop>
     <C:filter>
       <C:comp-filter name="VCALENDAR">
         <C:comp-filter name="VEVENT">
           <C:time-range start="20060104T000000Z"
                         end="20060105T000000Z"/>
         </C:comp-filter>
       </C:comp-filter>
     </C:filter>
   </C:calendar-query>
  1. iCalendar: iCalendar, or ICS, is a standard format for representing and exchanging calendaring and scheduling information. It is often used with CalDAV to facilitate the sharing of calendar events across different platforms and applications.

    In the example below you see iCalendar payload inside of the ‘calendar-data’ XML tag:

<?xml version="1.0" encoding="utf-8" ?>
   <D:multistatus xmlns:D="DAV:"
              xmlns:C="urn:ietf:params:xml:ns:caldav">
     <D:response>
       <D:href>http://cal.example.com/bernard/work/abcd2.ics</D:href>
       <D:propstat>
         <D:prop>
           <D:getetag>"fffff-abcd2"</D:getetag>
           <C:calendar-data>BEGIN:VCALENDAR
   VERSION:2.0
   BEGIN:VTIMEZONE
   LAST-MODIFIED:20040110T032845Z
   TZID:US/Eastern
   BEGIN:DAYLIGHT
   DTSTART:20000404T020000
   RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
   TZNAME:EDT
   TZOFFSETFROM:-0500
   TZOFFSETTO:-0400
   END:DAYLIGHT
   BEGIN:STANDARD
   DTSTART:20001026T020000
   RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
   TZNAME:EST
   TZOFFSETFROM:-0400
   TZOFFSETTO:-0500
   END:STANDARD
   END:VTIMEZONE
   BEGIN:VEVENT
   DTSTART;TZID=US/Eastern:20060102T120000
   DURATION:PT1H
   RRULE:FREQ=DAILY;COUNT=5
   SUMMARY:Event #2
   UID:00959BC664CA650E933C892C@example.com
   END:VEVENT
   BEGIN:VEVENT
   DTSTART;TZID=US/Eastern:20060104T140000
   DURATION:PT1H
   RECURRENCE-ID;TZID=US/Eastern:20060104T120000
   SUMMARY:Event #2 bis
   UID:00959BC664CA650E933C892C@example.com
   END:VEVENT
   BEGIN:VEVENT
   DTSTART;TZID=US/Eastern:20060106T140000
   DURATION:PT1H
   RECURRENCE-ID;TZID=US/Eastern:20060106T120000
   SUMMARY:Event #2 bis bis
   UID:00959BC664CA650E933C892C@example.com
   END:VEVENT
   END:VCALENDAR
   </C:calendar-data>
         </D:prop>
         <D:status>HTTP/1.1 200 OK</D:status>
       </D:propstat>
     </D:response>
...

Diverse Calendar Providers

Major players in the calendar space, such as Apple, Yahoo, Google, and Microsoft, support CalDAV. However, each provider has its own nuances and capabilities. For example, the CalDav protocol defines calendar components (like event, a to-do, a journal entry, time zone information, or free/busy time information, or an alarm) but not all servers will support all those components (most will support event, time zone info and to-do though).

  • Apple Calendar: Apple’s iCloud supports CalDAV, allowing seamless synchronization across Apple devices. Integrating Apple Calendars involves obtaining the CalDAV URL and using the CalDAV protocol for communication.

  • Google Calendar: Google provides both CalDAV and proprietary APIs. While CalDAV is widely supported, Google’s API might offer additional features and flexibility for integration.

  • Microsoft Exchange: Microsoft Exchange supports both CalDAV and proprietary APIs (like ActiveSync and EWS). Developers can choose the protocol based on their specific requirements.

Integrating Apple Calendars using CalDAV

To integrate Apple Calendars, developers need to authenticate with iCloud (using app-password), obtain the CalDAV URL, and use CalDAV requests for operations like event creation, deletion, or retrieval. Let’s walk through some of the key methods that will help you start integrating with Apple/iCloud.

Get user/principle information

PROPFIND / HTTP/1.1
Host: caldav.icloud.com
Content-Type: application/xml; charset=utf-8
Authorization: Basic basicValue

<d:propfind xmlns:d="DAV:">
  <d:prop>
    <d:current-user-principal/>
  </d:prop>
</d:propfind>

Response - properties are successfully retrieved when you see status HTTP/1.1 200 OK

HTTP/1.1 207 Multi-Status
Server: AppleHttpServer/78689afb4479
Content-Type: application/xml; charset=UTF-8

<multistatus xmlns="DAV:">
  <response xmlns="DAV:">
    <href>/</href>
    <propstat>
      <prop>
        <current-user-principal xmlns="DAV:">
          <href xmlns="DAV:">/200385701/principal/</href>
        </current-user-principal>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
</multistatus>

Discover the principal’s CalDav server

PROPFIND /200385701/principal/ HTTP/1.1
Host: caldav.icloud.com
Content-Type: application/xml; charset=utf-8
Authorization: Basic basicValue

<d:propfind xmlns:d="DAV:" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/">
  <d:prop>
    <cal:calendar-home-set/>
    <d:group-membership/>
  </d:prop>
</d:propfind>

Response - group-membership is not defined for this user (HTTP/1.1 404 Not Found) but calendar-home-set tells you the CalDav server (https://p34-caldav.icloud.com).

HTTP/1.1 207 Multi-Status
Server: AppleHttpServer/78689afb4479
Content-Type: application/xml; charset=UTF-8

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<multistatus xmlns="DAV:">
  <response xmlns="DAV:">
    <href>/200385701/principal/</href>
      <propstat>
         <prop>
            <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">
              <href xmlns="DAV:">https://p34-caldav.icloud.com:443/200385701/calendars/</href>
            </calendar-home-set>
        </prop>
        <status>HTTP/1.1 200 OK</status>
      </propstat>
      <propstat>
          <prop>
            <group-membership xmlns="DAV:"/>
          </prop>
          <status>HTTP/1.1 404 Not Found</status>
      </propstat>
  </response>
</multistatus>

Communicate with the principal’s CalDav instance (https://p34-caldav.icloud.com) from now on!

Get a list of calendars

Some properties, like calendar-color, are clearly provider specific.

PROPFIND /200385701/calendars/ HTTP/1.1
Host: p34-caldav.icloud.com
Content-Type: application/xml; charset=utf-8
Authorization: Basic basicValue

<d:propfind xmlns:d="DAV:" xmlns:apple="http://apple.com/ns/ical/" xmlns:cs="http://calendarserver.org/ns/" xmlns:cal="urn:ietf:params:xml:ns:caldav">
  <d:prop>
    <d:current-user-privilege-set/>
    <d:resourcetype />
    <d:displayname />
    <apple:calendar-color/>
    <cs:source/>
    <cal:supported-calendar-component-set/>
  </d:prop>
</d:propfind>

Response - calendar-component-set shows you what a calendar supports: events, to-dos, free/busy information.

HTTP/1.1 207 Multi-Status
Server: AppleHttpServer/78689afb4479
Content-Type: application/xml; charset=UTF-8

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<multistatus xmlns="DAV:">
  <response xmlns="DAV:">
    <href>/200385701/calendars/</href>
    <propstat>
      <prop>
        <current-user-privilege-set xmlns="DAV:">
          <privilege>
              <read/>
          </privilege>
          ...
        </current-user-privilege-set>
        <resourcetype xmlns="DAV:">
          <collection/>
        </resourcetype>
        <displayname xmlns="DAV:">User name</displayname>
        <supported-calendar-component-set xmlns="urn:ietf:params:xml:ns:caldav">
          <comp name='VEVENT' xmlns='urn:ietf:params:xml:ns:caldav'/>
          <comp name='VTODO' xmlns='urn:ietf:params:xml:ns:caldav'/>
          <comp name='VFREEBUSY' xmlns='urn:ietf:params:xml:ns:caldav'/>
        </supported-calendar-component-set>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
    <propstat>
      <prop>
        <calendar-color xmlns="http://apple.com/ns/ical/"/>
        <source xmlns="http://calendarserver.org/ns/"/>
      </prop>
      <status>HTTP/1.1 404 Not Found</status>
    </propstat>
</response>
<response xmlns="DAV:">
    <href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/</href>
    <propstat>
      <prop>
        <current-user-privilege-set xmlns="DAV:">
          <privilege>
              <read/>
          </privilege>
          ...
        </current-user-privilege-set>
        <resourcetype xmlns="DAV:">
          <collection/>
          <calendar xmlns="urn:ietf:params:xml:ns:caldav"/>
        </resourcetype>
        <displayname xmlns="DAV:">New calendars</displayname>
        <calendar-color xmlns="http://apple.com/ns/ical/">#FF2D55FF</calendar-color>
        <supported-calendar-component-set xmlns="urn:ietf:params:xml:ns:caldav">
          <comp name='VEVENT' xmlns='urn:ietf:params:xml:ns:caldav'/>
        </supported-calendar-component-set>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
    <propstat>
      <prop>
        <source xmlns="http://calendarserver.org/ns/"/>
      </prop>
      <status>HTTP/1.1 404 Not Found</status>
    </propstat>
  </response>
  ...
</multistatus>

Request a list of calendar events

REPORT /200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/
Host: p34-caldav.icloud.com
Content-Type: text/plain; charset=utf-8
Authorization: Basic basicValue
Depth: 1

<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">
  <d:prop>
    <d:getetag/>
  </d:prop>
 <c:filter>
   <c:comp-filter name="VCALENDAR">
     <c:comp-filter name="VEVENT">
     </c:comp-filter>
   </c:comp-filter>
 </c:filter>
</c:calendar-query>

Response - see href links. Some servers can return event details when calendar-data is requested (see examples below). Keep track of etags, they change when the records change.

HTTP/1.1 207 Multi-Status
Server: AppleHttpServer/78689afb4479
Content-Type: application/xml; charset=UTF-8

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<multistatus xmlns="DAV:">
	<response>
		<href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/</href>
		<propstat>
			<prop>
				<getetag xmlns="DAV:">"kiix2mif"</getetag>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
	</response>
	<response>
		<href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/1.ics</href>
		<propstat>
			<prop>
				<getetag xmlns="DAV:">"lrgcxs0m"</getetag>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
	</response>
	<response>
		<href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/2.ics</href>
		<propstat>
			<prop>
				<getetag xmlns="DAV:">"lrgcxs0m"</getetag>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
	</response>
	...
</multistatus>

Retrieve details of multiple events:

Simply specify the href links and request calendar-data.

REPORT /200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/
Host: p34-caldav.icloud.com
Authorization: Basic basicValue
Depth: 1
Content-Type: text/plain; charset=utf-8

<c:calendar-multiget xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">
	<d:prop>
		<d:getetag/>
		<c:calendar-data></c:calendar-data>
	</d:prop>
	<d:href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/1.ics</d:href>
	<d:href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/2.ics</d:href>
</c:calendar-multiget>

Response - always check response status (there is one per event) as some events may be gone (HTTP/1.1 404 Not Found). calendar-data is the event data in iCalendar format.

HTTP/1.1 207 Multi-Status
Server: AppleHttpServer/78689afb4479
Content-Type: application/xml; charset=UTF-8

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<multistatus xmlns="DAV:">
	<response xmlns="DAV:">
		<href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/2.ics</href>
		<status>HTTP/1.1 404 Not Found</status>
	</response>
	<response xmlns="DAV:">
		<href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/1.ics</href>
		<propstat>
			<prop>
				<getetag xmlns="DAV:">"lqghznnp"</getetag>
				<calendar-data xmlns="urn:ietf:params:xml:ns:caldav"><![CDATA[BEGIN:VCALENDAR
CALSCALE:GREGORIAN
PRODID:-//Apple Inc.//macOS 14.2.1//EN
VERSION:2.0
BEGIN:VEVENT
CREATED:20231222T103741Z
DTEND;TZID=Africa/Bamako:20240114T100000
DTSTAMP:20240109T073000Z
DTSTART;TZID=Africa/Bamako:20240114T090000
LAST-MODIFIED:20240109T070811Z
LOCATION:New York County\, NY\nUnited States
SEQUENCE:1
SUMMARY:Single event
UID:1
X-APPLE-CREATOR-IDENTITY:com.apple.calendar
X-APPLE-CREATOR-TEAM-IDENTITY:0000000000
...
END:VEVENT
BEGIN:VTIMEZONE
TZID:Africa/Bamako
X-LIC-LOCATION:Africa/Bamako
BEGIN:STANDARD
DTSTART:19120101T000000
RDATE:19120101T000000
TZNAME:GMT
TZOFFSETFROM:-001608
TZOFFSETTO:+0000
END:STANDARD
END:VTIMEZONE
END:VCALENDAR
]]></calendar-data>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
	</response>
</multistatus>

Report events in a time range

Here is an alternative way to get event details (calendar-data) for multiple events.

REPORT /200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/
Host: p34-caldav.icloud.com
Authorization: Basic basicValue
Depth: 1
Content-Type: text/plain; charset=utf-8

<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">
	<d:prop>
		<d:getetag/>
		<c:calendar-data>
			<c:comp name="VCALENDAR">
				<c:prop name="VERSION"/>
				<c:comp name="VEVENT">
					<c:prop name="UID"/>
					<c:prop name="CREATED"/>
					<c:prop name="LAST-MODIFIED"/>
					<c:prop name="SUMMARY"/>
					<c:prop name="DTSTART"/>
					<c:prop name="DTEND"/>
					<c:prop name="ORGANIZER"/>
					<c:prop name="STATUS"/>
					<c:prop name="RECURRENCE-ID"/>
					<c:prop name="RRULE"/>
					<c:prop name="LOCATION"/>
					<c:prop name="TRANSP"/>
					<c:prop name="CATEGORIES"/>
					<c:prop name="ATTACH"/>
					<c:prop name="ATTENDEE"/>
				</c:comp>
				<c:comp name="VTIMEZONE"/>
			</c:comp>
		</c:calendar-data>
	</d:prop>
	<c:filter>
		<c:comp-filter name="VCALENDAR">
			<c:comp-filter name="VEVENT">
				<c:time-range start="20240125T000000Z" end="20240126T000000Z"/>
			</c:comp-filter>
		</c:comp-filter>
	</c:filter>
</c:calendar-query>

Response - extract event id from the href links and keep track of etags.

HTTP/1.1 207 Multi-Status
Server: AppleHttpServer/78689afb4479
Content-Type: application/xml; charset=UTF-8

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<multistatus xmlns="DAV:">
	<response>
		<href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/603275E4-6A47-4EFA-BAEF-CCD33A314C30.ics</href>
		<propstat>
			<prop>
				<getetag xmlns="DAV:">"lreo54jn"</getetag>
				<calendar-data xmlns="urn:ietf:params:xml:ns:caldav"><![CDATA[BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
CREATED:20240115T083404Z
DTEND;VALUE=DATE:20240126
DTSTART;VALUE=DATE:20240125
LAST-MODIFIED:20240115T083404Z
RRULE:FREQ=DAILY;COUNT=3
SUMMARY:Bamako All
UID:603275E4-6A47-4EFA-BAEF-CCD33A314C30
TRANSP:TRANSPARENT
BEGIN:VALARM
ACTION:DISPLAY
DESCRIPTION:Reminder
TRIGGER:-PT15H
UID:E40DEE70-5AF7-43D6-93FC-3D2C755A29F6
X-APPLE-DEFAULT-ALARM:TRUE
X-WR-ALARMUID:E40DEE70-5AF7-43D6-93FC-3D2C755A29F6
END:VALARM
END:VEVENT
END:VCALENDAR
]]></calendar-data>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
	</response>
</multistatus>

Get an event by id

Append .ics after an event id (i.e. 603275E4-6A47-4EFA-BAEF-CCD33A314C30). Essentially, you’re requesting an .ics file.

GET /200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/603275E4-6A47-4EFA-BAEF-CCD33A314C30.ics HTTP/1.1
Authorization: Basic basicValue
Host: p34-caldav.icloud.com

Response - here, response is not XML but iCalendar.

HTTP/1.1 200 OK
Server: AppleHttpServer/78689afb4479
Content-Type: text/calendar; charset=UTF-8
ETag: "lreo54jn"
DAV: 1, access-control

BEGIN:VCALENDAR
CALSCALE:GREGORIAN
PRODID:-//Apple Inc.//macOS 14.2.1//EN
VERSION:2.0
BEGIN:VEVENT
CREATED:20240115T083404Z
DTEND;VALUE=DATE:20240126
DTSTAMP:20240115T083404Z
DTSTART;VALUE=DATE:20240125
LAST-MODIFIED:20240115T083404Z
RRULE:FREQ=DAILY;COUNT=3
SEQUENCE:0
SUMMARY:Bamako All
UID:603275E4-6A47-4EFA-BAEF-CCD33A314C30
X-APPLE-CREATOR-IDENTITY:com.apple.calendar
X-APPLE-CREATOR-TEAM-IDENTITY:0000000000
TRANSP:TRANSPARENT
BEGIN:VALARM
ACTION:DISPLAY
DESCRIPTION:Reminder
TRIGGER:-PT15H
UID:E40DEE70-5AF7-43D6-93FC-3D2C755A29F6
X-APPLE-DEFAULT-ALARM:TRUE
X-WR-ALARMUID:E40DEE70-5AF7-43D6-93FC-3D2C755A29F6
END:VALARM
END:VEVENT
END:VCALENDAR

Update an event

There is no patching! So, load an event, make changes and send its full payload back to the server. A new event is created using PUT too, simply generate a new UUID for your new event.

PUT /200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/603275E4-6A47-4EFA-BAEF-CCD33A314C30.ics HTTP/1.1
Authorization: Basic basicValue
Host: p34-caldav.icloud.com

BEGIN:VCALENDAR
CALSCALE:GREGORIAN
PRODID:-//Apple Inc.//macOS 14.2.1//EN
VERSION:2.0
BEGIN:VEVENT
CREATED:20240115T083404Z
DTEND;VALUE=DATE:20240126
DTSTAMP:20240115T083404Z
DTSTART;VALUE=DATE:20240125
LAST-MODIFIED:20240115T083404Z
RRULE:FREQ=DAILY;COUNT=3
SEQUENCE:0
SUMMARY:Bamako All 2
UID:603275E4-6A47-4EFA-BAEF-CCD33A314C30
X-APPLE-CREATOR-IDENTITY:com.apple.calendar
X-APPLE-CREATOR-TEAM-IDENTITY:0000000000
TRANSP:TRANSPARENT
BEGIN:VALARM
ACTION:DISPLAY
DESCRIPTION:Reminder
TRIGGER:-PT15H
UID:E40DEE70-5AF7-43D6-93FC-3D2C755A29F6
X-APPLE-DEFAULT-ALARM:TRUE
X-WR-ALARMUID:E40DEE70-5AF7-43D6-93FC-3D2C755A29F6
END:VALARM
END:VEVENT
END:VCALENDAR

Response - no content here, but capture the etag!

TTP/1.1 204 No Content
Server: AppleHttpServer/78689afb4479
X-Apple-API-Version: v1
Etag: "lrhk7ybi"

Syncing

Let’s assume that your CalDAV server supports the collection synchronization extension (most calendar providers do).

If the DAV:sync-collection report is implemented by a WebDAV server, then the server MUST list the report in the “DAV:supported-report-set” property on any collection that supports synchronization.

Initial Sync

No sync token is specified yet.

REPORT /200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/
Authorization: Basic basicValue
Content-Type: text/xml; charset=utf-8
Depth: 1
Host: p34-caldav.icloud.com

<d:sync-collection xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
	<d:sync-token/>
	<d:sync-level>1</d:sync-level>
    <d:limit>
      <d:nresults>10</d:nresults>
    </d:limit>
	<d:prop>
		<d:getcontenttype/>
		<d:getetag/>
	</d:prop>
</d:sync-collection>

Response - CalDAV server will start returning all events (10 records per page) and a sync token to receive the next page. 1st response record is about the calendar itself.

HTTP/1.1 207 Multi-Status
Server: AppleHttpServer/78689afb4479
Content-Type: application/xml; charset=UTF-8

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<multistatus xmlns="DAV:">
	<response xmlns="DAV:">
		<href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/</href>
		<propstat>
			<prop>
				<getcontenttype xmlns="DAV:">httpd/unix-directory</getcontenttype>
				<getetag xmlns="DAV:">"kiix2min"</getetag>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
	</response>
  <response xmlns="DAV:">
		<href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/8A4BFE75-91F3-4FF6-AF3D-9221B0587C6C.ics</href>
		<propstat>
			<prop>
				<getcontenttype xmlns="DAV:">text/calendar</getcontenttype>
				<getetag xmlns="DAV:">"lralxxtk"</getetag>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
	</response>
	...
	<sync-token>HwoQEgwAAGbI6heuOgAAAAEYARgAIhYIlZjF9sL437yDARDR3sXqpc+jt4UBKAA=</sync-token>
</multistatus>

Incremental Sync (or next page of the initial sync)

Request the ‘sync-collection’ with a sync token now.

REPORT /20038570152/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/ HTTP/1.1
Authorization: Basic basicValue
Content-Type: text/xml; charset=utf-8
Depth: 1
Host: p34-caldav.icloud.com

<d:sync-collection xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
	<d:sync-token>HwoQEgwAAGay9UzEEAAAAAEYARgAIhYIlZjF9sL437yDARDR3sXqpc+jt4UBKAA=</d:sync-token>
	<d:sync-level>1</d:sync-level>
    <d:limit>
      <d:nresults>10</d:nresults>
    </d:limit>
	<d:prop>
		<d:getcontenttype/>
		<d:getetag/>
	</d:prop>
</d:sync-collection>

Response - capture the new sync token and continue paging until you get 0 records. Deleted events show the status ‘HTTP/1.1 404 Not Found’.

HTTP/1.1 207 Multi-Status
Server: AppleHttpServer/78689afb4479
Content-Type: application/xml; charset=UTF-8

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<multistatus xmlns="DAV:">
	<response xmlns="DAV:">
		<href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/</href>
		<propstat>
			<prop>
				<getcontenttype xmlns="DAV:">httpd/unix-directory</getcontenttype>
				<getetag xmlns="DAV:">"kiix2min"</getetag>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
	</response>
	<response xmlns="DAV:">
		<href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/8A4BFE75-91F3-4FF6-AF3D-9221B0587C6C.ics</href>
		<propstat>
			<prop>
				<getcontenttype xmlns="DAV:">text/calendar</getcontenttype>
				<getetag xmlns="DAV:">"lralxxtk"</getetag>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
	</response>
	<response xmlns="DAV:">
		<href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/47474204-131F-4E09-B866-204C892781DE.ics</href>
		<status>HTTP/1.1 404 Not Found</status>
	</response>
	<sync-token>HwoQEgwAAGbI6heuOgAAAAEYARgAIhYIlZjF9sL437yDARDR3sXqpc+jt4UBKAA=</sync-token>
</multistatus>

Sync token property

You can get the latest sync token without doing the full initial sync.

PROPFIND /200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/
Authorization: Basic basicValue
Depth: 0
Content-Type: text/plain; charset=utf-8
Host: p34-caldav.icloud.com

<d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/">
  <d:prop>
     <d:displayname />
     <cs:getctag />
     <d:sync-token />
  </d:prop>
</d:propfind>

Response - capture the sync token and use it for receiving updates in the future.

HTTP/1.1 207 Multi-Status
Server: AppleHttpServer/78689afb4479
Content-Type: application/xml; charset=UTF-8

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<multistatus xmlns="DAV:">
	<response xmlns="DAV:">
		<href>/200385701/calendars/2b0158b9-9c73-49e8-92a9-9aefbbec3534/</href>
		<propstat>
			<prop>
				<displayname xmlns="DAV:">home</displayname>
				<getctag xmlns="http://calendarserver.org/ns/">HwoQEgwAAGay9UzEEAAAAAEYARgAIhYIlZjF9sL437yDARDR3sXqpc+jt4UBKAA=</getctag>
				<sync-token xmlns="DAV:">HwoQEgwAAGay9UzEEAAAAAEYARgAIhYIlZjF9sL437yDARDR3sXqpc+jt4UBKAA=</sync-token>
			</prop>
			<status>HTTP/1.1 200 OK</status>
		</propstat>
	</response>
</multistatus>

Harnessing the Power of Aurinko

CalDAV, while powerful, comes with complexities. Some challenges include dealing with different implementations across providers, handling recurring events, and managing time zones consistently. Developers should be prepared to address these intricacies during implementation.

Aurinko’s API gateway abstracts the intricacies of CalDAV, handling protocol-specific features behind the scenes (Appple/iCloud at the moment). This allows developers to focus on building features without getting bogged down by the complexities of CalDAV’s XML-based requests and responses.

By leveraging the Aurinko Calendar API, developers can enhance their applications with robust calendaring features while enjoying the benefits of a RESTful architecture.