Figment.so
Mac hostingWebsite hostingGuidesHow to usePricing

Read and Update iCloud Calendars with CalDAV

iCloud Calendar speaks CalDAV, the RFC 4791 extension of WebDAV built for calendar data. Any HTTP client that can send PROPFIND, REPORT, and PUT requests can read and write iCloud events. The minimum requirements are: an Apple Account with two-factor authentication enabled, a valid scoped credential (an app-specific password or an authorized app token through Apple's account-authorization flow), and an understanding of ETag-guarded conditional writes. This guide covers each step in that order.

What CalDAV means for iCloud Calendar

CalDAV wraps iCalendar objects—VCALENDAR files containing VEVENT or VTODO components—inside a WebDAV container. Each event lives at its own URL inside a calendar collection. The standard operations are:

  • PROPFIND — read properties of a collection or resource, including its ETag
  • REPORT — query a collection by filter (time range, component type)
  • PUT — create or update a calendar object resource
  • DELETE — remove a resource

Each calendar object resource holds exactly one VCALENDAR component (alongside any VTIMEZONE components), and every resource carries a mandatory strong ETag that the safe update flow depends on.

Authentication

Two credential paths are available for iCloud CalDAV clients.

App-specific passwords are the traditional route. Apple requires two-factor authentication on the account before you can generate one (support.apple.com/en-us/102654). Sign in to account.apple.com, go to Sign-In and Security → App-Specific Passwords, and generate a labeled password for your application. You can maintain up to 25 active app-specific passwords; resetting your main Apple Account password revokes all of them. Use your full iCloud email address as the HTTP Basic Auth username and the generated password as the credential.

Apple's account authorization flow (support.apple.com/en-us/121539) covers iCloud Mail, Calendar, and Contacts in supported third-party apps. Users approve access by clicking Allow inside the requesting application, without generating a separate credential. The grant can be revoked independently through Apple Account settings under Account Data Sharing, and that revocation takes effect immediately.

Neither path delivers the Apple Account password to the developer's application.

Discovering your calendar home with PROPFIND

iCloud distributes user data across sharded backend hosts, so a correct client always discovers its principal URL rather than hard-coding a final calendar path. The initial CalDAV gateway is caldav.icloud.com, documented across Apple Community discussions and widely adopted by third-party CalDAV clients.

Step 1 — resolve the current-user-principal:

PROPFIND / HTTP/1.1
Host: caldav.icloud.com
Depth: 0
Authorization: Basic <base64(email:app-specific-password)>
Content-Type: application/xml; charset=utf-8

<?xml version="1.0" encoding="UTF-8"?>
<D:propfind xmlns:D="DAV:">
  <D:prop>
    <D:current-user-principal />
  </D:prop>
</D:propfind>

The multistatus response contains a DAV:href pointing to your principal resource—typically on a shard-specific host such as p0N-caldav.icloud.com.

Step 2 — request the calendar-home-set from the principal URL:

PROPFIND /principal/ HTTP/1.1
Host: p0N-caldav.icloud.com
Depth: 0
Authorization: Basic <base64(email:app-specific-password)>
Content-Type: application/xml; charset=utf-8

<?xml version="1.0" encoding="UTF-8"?>
<D:propfind xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
  <D:prop>
    <C:calendar-home-set />
  </D:prop>
</D:propfind>

Per RFC 4791, the CALDAV:calendar-home-set property lets users easily find the calendar collections owned by the principal. The DAV:href in the response is the collection URL you query next.

Reading events with calendar-query REPORT

With a calendar collection URL in hand, the REPORT method with a calendar-query body retrieves events. Use a time-range filter to avoid pulling the entire history. Always request DAV:getetag in the same query—you need those values before any write.

REPORT /calendars/<account-id>/home/ HTTP/1.1
Host: p0N-caldav.icloud.com
Depth: 1
Authorization: Basic <base64(email:app-specific-password)>
Content-Type: application/xml; charset=utf-8

<?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 />
  </D:prop>
  <C:filter>
    <C:comp-filter name="VCALENDAR">
      <C:comp-filter name="VEVENT">
        <C:time-range start="20260101T000000Z" end="20270101T000000Z" />
      </C:comp-filter>
    </C:comp-filter>
  </C:filter>
</C:calendar-query>

The response is a DAV:multistatus document with one DAV:response block per matching event. Each block contains the VCALENDAR payload in CALDAV:calendar-data and the strong ETag in DAV:getetag.

The safe update flow: ETag and conditional PUT

This is the brief's core artifact and the foundation of any CalDAV client that shares calendar data with other apps or devices. RFC 4791 mandates strong ETags on every calendar object resource; the standard HTTP If-Match and If-None-Match headers enforce optimistic concurrency.

Creating a new event

Send a PUT to a URL that does not yet exist. Add If-None-Match: * so the server rejects the request with 412 Precondition Failed if the path is already taken:

PUT /calendars/<account-id>/home/<new-uid>.ics HTTP/1.1
Host: p0N-caldav.icloud.com
If-None-Match: *
Authorization: Basic <base64(email:app-specific-password)>
Content-Type: text/calendar; charset=utf-8

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example//EN
BEGIN:VEVENT
UID:<new-uid>@example.com
SUMMARY:Team sync
DTSTART:20261115T140000Z
DTEND:20261115T150000Z
DTSTAMP:20261112T000000Z
END:VEVENT
END:VCALENDAR

A 201 Created response confirms the write. Store the ETag from the response header if the server returns one.

Updating an existing event

The four-step sequence that makes concurrent writes safe:

  1. Capture the ETag. Your REPORT response included it. Store it alongside the resource URL—do not proceed without it.
  2. Modify the VCALENDAR locally. Increment the SEQUENCE counter and update LAST-MODIFIED.
  3. PUT with If-Match:
PUT /calendars/<account-id>/home/<uid>.ics HTTP/1.1
Host: p0N-caldav.icloud.com
If-Match: "abc123etag"
Authorization: Basic <base64(email:app-specific-password)>
Content-Type: text/calendar; charset=utf-8

<your modified VCALENDAR payload>
  1. On 412 Precondition Failed: the resource changed between your read and your write. Re-fetch the event with PROPFIND or a fresh REPORT, resolve the conflict, and retry with the updated ETag. Never retry with a stale ETag.

A 204 No Content response confirms success. Capture the new ETag from the response header for your next write.

This four-step loop—read ETag, modify locally, PUT with If-Match, handle 412—is the foundation of any robust CalDAV sync implementation. Skip any step and you trade correctness for speed; in a shared calendar environment that trade is rarely worth it.

Figment Apple Connect and iCloud Calendar

Figment Apple Connect currently provides a read-only synthetic sandbox for iCloud Calendar. Register your app at /apple-connect/developers, request the calendar:read scope, and explore the sandbox endpoint:

GET /api/apple-connect/v1/connections/{connection_id}/calendar
    ?start=2026-01-01T00:00:00Z&end=2026-12-31T23:59:59Z

The response returns synthetic event objects of the form {id, calendarId, title, start, end, allDay, location} and is labeled mode: "sandbox". Both start and end must be supplied together; end must follow start; the range may not exceed 366 days. This data is invented—it does not access a real iCloud library.

Live customer calendar access through Figment is not yet available. For read/write access to a live iCloud calendar today, CalDAV is the Apple-supported protocol described in this guide.

Connect Apple Account


Related reading


Subscribe for Figma design and website publishing guides.


Figment.so

Contact

Twitter

Website pricing

Compute index

About

Privacy

Terms