Skip to content
Skip to main content

How to list iCloud contacts

Last updated:

Apple doesn’t ship a REST contacts API. iCloud exposes its address book over CardDAV, the same WebDAV-based protocol it uses for calendars, and it gates access behind an app-specific password rather than OAuth. So instead of an events.insert-style endpoint, you’re writing CardDAV PROPFIND and REPORT requests against contacts.icloud.com and parsing vCard payloads by hand.

This recipe reads an iCloud address book through one call to the Nylas Contacts API. You get the same contact schema returned for Gmail, Outlook, and Exchange accounts, so a single parser handles every provider and you never touch CardDAV or vCard directly.

Why use Nylas instead of iCloud CardDAV directly?

Section titled “Why use Nylas instead of iCloud CardDAV directly?”

CardDAV is a sync protocol, not a query API, so reading contacts the native way means more plumbing than a contact picker should need. One Nylas request replaces a CardDAV handshake plus vCard parsing across all 6 supported providers. These 3 differences from a typical REST integration are where the work piles up:

  • No OAuth, no scopes. iCloud authenticates with an app-specific password the user generates at appleid.apple.com. There’s no consent screen and no scope list, so you store and rotate that credential yourself unless a grant holds it for you.
  • vCard parsing. CardDAV REPORT requests return vCard 3.0 text, not JSON. You parse FN, EMAIL, TEL, and ORG lines and reconcile them into objects. The API does this and hands back JSON fields like emails, phone_numbers, and company_name.
  • One schema across providers. The same GET /v3/grants/{grant_id}/contacts request reads an iCloud, Gmail, Outlook, or Exchange address book, so your picker code stays provider-agnostic.

To list iCloud contacts you need a connected iCloud account, and that connection depends on 2 things Apple requires: an iCloud connector in your project and an app-specific password from the user. iCloud doesn’t use OAuth scopes, so there’s no permission list to request.

  • A Nylas application with a valid API key
  • An iCloud connector added to that application
  • A grant for an iCloud account authorized with an app-specific password

Apple requires an app-specific password to connect any third-party app, and it must be generated by the user because Apple offers no API for it. Direct the user to appleid.apple.com, have them sign in, and walk them through Apple’s app-specific password steps. They enter that 16-character password during auth instead of their main Apple ID password. The full connector and Bring Your Own Authentication flow lives in the iCloud provider guide.

Send a GET request to /v3/grants/{grant_id}/contacts with the grant ID for the connected iCloud account. The response is a data array of contact objects plus a request_id, and a single page returns 30 contacts by default and up to 200 with the limit parameter. Each object carries emails, phone_numbers, job_title, company_name, and groups populated from the iCloud address book.

The samples below list contacts for one grant and print the unified response.

For create, update, and delete operations plus the complete field list, see Manage contacts with the Contacts API.

iCloud exposes contacts over CardDAV, and each user must create a 16-character app-specific password before any client connects. The Nylas CLI reads them once that grant exists: nylas contacts list returns the account’s contacts straight from your terminal, with no CardDAV client to build or sync logic to maintain.

The Nylas CLI reads contacts from your terminal with the same source model as the Contacts API. After nylas init and nylas auth login, contacts list returns 50 contacts by default and pages through everything automatically once --limit goes over 200:

# List 50 contacts (default)
nylas contacts list
# Only the saved address book, skipping auto-collected senders
nylas contacts list --source address_book --limit 100

Every contact carries a source: address_book (saved by the user), inbox (auto-collected from sent mail), or domain (the organization directory). Filter deliberately, because a busy account can hold thousands of inbox contacts the user never saved. To find a specific person rather than list everyone, contacts search matches on company, email, or phone:

# Find contacts at a company who have an email on file
nylas contacts search --company "Acme" --has-email

See the contacts list and contacts search command reference for every flag.

Like other IMAP-style providers, an iCloud contact holds at most one email and one phone number, so don’t expect the multi-value fields a Google contact carries. Listing returns 50 contacts by default. Filter to the saved set with nylas contacts list --source address_book, which skips auto-collected senders.

Three query parameters narrow an iCloud contact list: email, phone_number, and source. iCloud supports the phone_number filter, which Microsoft doesn’t, so you can match a contact by digits as well as by address. The source parameter picks between saved contacts (address_book) and the auto-generated entries Nylas derives from message participants (inbox). The recurse parameter is Microsoft-only, so it has no effect on an iCloud grant.

This curl request returns contacts whose email contains jane from the user’s saved iCloud address book. Swap email for phone_number to match a number instead.

iCloud is one of only 2 providers that accept a compound source filter, so you can pass source=address_book,inbox to merge saved and auto-generated contacts in a single request.

iCloud contacts arrive as vCard 3.0 over CardDAV, and that single fact shapes the 4 details below: the protocol underneath, the app-password auth model, compound source filtering, and the 90-day cache that governs sync timing. Read these before you wire the address book into a picker or a sync job.

Nylas reads iCloud contacts over CardDAV, the address-book extension to WebDAV defined in RFC 6352, rather than a JSON REST API. CardDAV speaks PROPFIND and REPORT requests and returns vCard 3.0 payloads, which the API normalizes into the unified contact object. Two effects fall out of this. First, iCloud contacts have no concept of system labels like Gmail’s starred, so the groups array reflects only CardDAV address-book collections. Second, contact IDs are stable CardDAV resource URLs, so they survive across syncs and are safe to store as foreign keys.

Auth uses an app-specific password, not OAuth scopes

Section titled “Auth uses an app-specific password, not OAuth scopes”

Every other major contacts provider uses OAuth, but iCloud uses an app-specific password the user generates manually. There’s no scope list and no admin consent step, which removes a verification hurdle that Google’s sensitive contacts scopes and Microsoft’s Contacts.Read admin consent both impose. The tradeoff is credential management: a user must regenerate the 16-character password if they reset their Apple ID password or revoke the app, and the grant moves to an error state until they re-authenticate. Surface a reconnect prompt so a stale password doesn’t silently stop contact reads.

Compound source filters are an iCloud advantage

Section titled “Compound source filters are an iCloud advantage”

The source parameter accepts a comma-separated list on iCloud and IMAP only, the 2 providers where Nylas reads contacts from both the CardDAV address book and message participants. Pass source=address_book,inbox to return saved contacts and auto-generated ones in a single call, which Google and Microsoft can’t do in one request. This is useful for recipient autocomplete, where you want both the user’s saved contacts and the people they’ve recently emailed ranked together. Filtering on source=address_book alone returns only the entries the user explicitly saved in the Contacts app.

Nylas caches iCloud data for 90 days and reads new contact changes from CardDAV on its sync schedule rather than in real time, so a contact added on an iPhone may take a short interval to surface through the list call. iCloud also doesn’t emit auto-generated “other contacts” the way Gmail builds a separate collection, so the inbox source is derived from message participants instead of an Apple-managed list. Apple enforces account-level limits documented in its iCloud system limits, so if you sync many accounts on a schedule, stagger the jobs rather than firing them at once.

The list endpoint returns 30 contacts per page by default, up to a maximum of 200, and uses cursor pagination through the page_token query parameter. Each response includes a next_cursor value when more contacts exist; pass it as page_token on the next request to fetch the following page. Loop until a response omits next_cursor, which signals the last page.