Why does Apple iCloud CalDAV always return 400/405 on PUT? Is iCloud CalDAV write-protected?
06:23 24 Nov 2025

I'm integrating with Apple iCloud Calendar using CalDAV. (php curl )

All read operations work correctly But all PUT requests fail

https://pXX-caldav.icloud.com/\/calendars//.ics (endpoint)

header Content-Type: text/calendar If-None-Match: *User-Agent: DAVKit/5.0

the ics BEGIN:VCALENDAR

VERSION:2.0

PRODID:-//Test//EN

BEGIN:VEVENT

UID:test123@example.com

DTSTAMP:20231121T120000Z

DTSTART:20231121T130000Z

DTEND:20231121T140000Z

SUMMARY:Test Event

END:VEVENT

END:VCALENDAR

I'm NOT using the “Published Calendar” URL — I know those are read-only.
I am using the private CalDAV calendar collection (the user's real iCloud calendar).

Does Apple block PUT/DELETE on private iCloud CalDAV calendars?
Is iCloud CalDAV officially read-only for third-party clients (except Apple’s own apps like Calendar.app and EventKit)?

If this is intentional behavior, is there any Apple documentation confirming the limitation

$ch = curl_init("https://pXX-caldav.icloud.com/$dsid/calendars/$calid/$uid.ics");

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "PUT",
    CURLOPT_USERPWD        => "$apple_id:$app_specific_password",
    CURLOPT_HTTPHEADER     => [
        "Content-Type: text/calendar",
        "User-Agent: DAVKit/5.0",
        "If-None-Match: *"
    ],
    CURLOPT_POSTFIELDS     => $ics,
    CURLOPT_HEADER         => true
]);

$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE);
echo $response;
php curl calendar caldav