Skip to Content
Developer APICalendar & Contacts

Calendar & Contacts

EUnifyer supports both standards-based protocols (CalDAV, CardDAV) and a REST API for calendar and contacts access. For external integrations, the standards-based path is recommended — it works with any compatible client out of the box.


Which path to use

Use caseRecommended
Connect Apple Calendar, Thunderbird, GNOME CalendarCalDAV
Connect Apple Contacts, Thunderbird, GNOME ContactsCardDAV
Build a server-side integration or sync jobCalDAV / CardDAV or REST
Mobile app syncing calendars/contactsCalDAV / CardDAV
REST programmatic access (events, contacts)REST API

CalDAV (Calendar)

  • Short client URL: https://cal.eunifyer.com
  • Canonical endpoint: https://cal.eunifyer.com/api/v1/caldav/
  • Standard: RFC 4791 (CalDAV) + RFC 6638 (scheduling extensions)
  • Auth: HTTP Basic (full-email:app-password) or Authorization: Bearer <token>
  • Service discovery: https://cal.eunifyer.com/.well-known/caldav (RFC 6764)

Connect a calendar client

Give users this URL for calendar client setup:

https://cal.eunifyer.com

Most clients (Apple Calendar, Thunderbird, GNOME Calendar) auto-configure from the well-known URL. The short URL handles root discovery and returns canonical resource paths. After discovery, the client reads user calendars via PROPFIND and syncs events via REPORT.

For Basic Auth, generate an App Password in Settings > App Passwords. The normal EUnifyer account password is not accepted.

Programmatic CalDAV access

Read events in a date range:

curl -X REPORT "https://cal.eunifyer.com/api/v1/caldav/{username}/{calendar-uid}/" \ -u "user@example.com:app-password" \ -H "Content-Type: application/xml; charset=utf-8" \ -H "Depth: 1" \ -d '<?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="20260401T000000Z" end="20260430T235959Z"/> </C:comp-filter> </C:comp-filter> </C:filter> </C:calendar-query>'

Create or update an event:

curl -X PUT "https://cal.eunifyer.com/api/v1/caldav/{username}/{calendar-uid}/{event-uid}.ics" \ -u "user@example.com:app-password" \ -H "Content-Type: text/calendar; charset=utf-8" \ -d 'BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Example//EN BEGIN:VEVENT UID:event-uid@example.com DTSTART:20260420T100000Z DTEND:20260420T110000Z SUMMARY:Team standup END:VEVENT END:VCALENDAR'

Delete an event:

curl -X DELETE "https://cal.eunifyer.com/api/v1/caldav/{username}/{calendar-uid}/{event-uid}.ics" \ -u "user@example.com:app-password"

REST Calendar API

Base path: /api/v1/calendar/
Auth: Bearer token (PAT, Keycloak JWT)
Scopes: calendar:read (read), calendar:write (create/update/delete)

Endpoints

GET /api/v1/calendar/calendars → list of CalendarInfo GET /api/v1/calendar/events?start=…&end=… → events across all calendars GET /api/v1/calendar/calendars/{cal_id}/events → events in one calendar GET /api/v1/calendar/calendars/{cal_id}/events/{uid} → single event POST /api/v1/calendar/calendars/{cal_id}/events → create event PUT /api/v1/calendar/calendars/{cal_id}/events/{uid} → replace event DELETE /api/v1/calendar/calendars/{cal_id}/events/{uid} → delete event POST /api/v1/calendar/freebusy → free/busy query POST /api/v1/calendar/calendars/{cal_id}/import → import ICS file GET /api/v1/calendar/calendars/{cal_id}/export.ics → export calendar as ICS

Example — list upcoming events

curl "https://api.eunifyer.com/api/v1/calendar/events?start=2026-04-01T00:00:00Z&end=2026-04-30T23:59:59Z" \ -H "Authorization: Bearer $TOKEN"

Example — create an event

curl -X POST https://api.eunifyer.com/api/v1/calendar/calendars/$CAL_ID/events \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Quarterly review", "start": "2026-04-20T09:00:00Z", "end": "2026-04-20T10:00:00Z", "description": "Q1 results discussion", "attendees": ["alice@example.com", "bob@example.com"] }'

Import and export

# Import ICS file curl -X POST https://api.eunifyer.com/api/v1/calendar/calendars/$CAL_ID/import \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: text/calendar" \ --data-binary @events.ics # Export as ICS curl https://api.eunifyer.com/api/v1/calendar/calendars/$CAL_ID/export.ics \ -H "Authorization: Bearer $TOKEN" \ -o calendar.ics

CardDAV (Contacts)

  • Short client URL: https://car.eunifyer.com (or https://contacts.eunifyer.com)
  • Canonical endpoint: https://car.eunifyer.com/api/v1/carddav/
  • Standard: RFC 6352 (CardDAV)
  • Auth: HTTP Basic (full-email:app-password) or Authorization: Bearer <token>
  • Service discovery: https://car.eunifyer.com/.well-known/carddav
  • ETag support: Active — use If-Match for safe updates

Connect a contacts client

Give users this URL for contacts client setup:

https://car.eunifyer.com

car. pairs with cal. for CalDAV, so users setting up both only have to remember one pattern. contacts.eunifyer.com is the older name for the same endpoint and keeps working — already-configured clients need no change.

Clients (Apple Contacts, Thunderbird, GNOME Contacts) auto-configure from the well-known URL. The full endpoint remains available for clients that require an explicit path.

Programmatic CardDAV access

List contacts in an address book:

curl -X REPORT "https://contacts.eunifyer.com/api/v1/carddav/{username}/{book-uid}/" \ -u "user@example.com:app-password" \ -H "Content-Type: application/xml; charset=utf-8" \ -H "Depth: 1" \ -d '<?xml version="1.0" encoding="utf-8"?> <C:addressbook-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav"> <D:prop><D:getetag/><C:address-data/></D:prop> </C:addressbook-query>'

Create or update a contact (VCard):

curl -X PUT "https://contacts.eunifyer.com/api/v1/carddav/{username}/{book-uid}/{contact-uid}.vcf" \ -u "user@example.com:app-password" \ -H "Content-Type: text/vcard; charset=utf-8" \ -d 'BEGIN:VCARD VERSION:3.0 UID:contact-uid@example.com FN:Alice Chen N:Chen;Alice;;; EMAIL:alice@example.com TEL:+1-555-0100 END:VCARD'

REST Contacts API

Base path: /api/v1/contacts/
Auth: Bearer token
Scopes: contacts:read / contacts:write

Endpoints

GET /api/v1/contacts/books → list of AddressBook GET /api/v1/contacts/books/{book_id} → list of ContactSummary GET /api/v1/contacts/books/{book_id}/{contact_id} → ContactDetail POST /api/v1/contacts/books/{book_id} → create contact PUT /api/v1/contacts/books/{book_id}/{contact_id} → replace contact DELETE /api/v1/contacts/books/{book_id}/{contact_id} → delete contact GET /api/v1/contacts/search?q=… → search contacts GET /api/v1/contacts/directory → organisation directory

Example — search contacts

curl "https://api.eunifyer.com/api/v1/contacts/search?q=alice" \ -H "Authorization: Bearer $TOKEN"

Webhook events

EventFires when
calendar.event.createdA calendar event is created
calendar.event.updatedA calendar event (or single occurrence) is updated

Subscribe via the Webhooks API to receive real-time notifications.