The Nylas Contacts API, part of Nylas Connect, provides a secure and reliable connection to your users’ contacts. This enables you to perform bi-directional sync with full CRUD (Create, Read, Update, Delete) capabilities for users’ accounts. The API provides a REST interface that lets you…
- Read contact information, including names, email addresses, phone numbers, and more.
- Create, update, and delete native iCloud and Yahoo contacts through CardDAV.
- Organize contacts using contact groups.
- Store private application data on Contact objects with Nylas-managed metadata.
Contact sources
Section titled “Contact sources”By default, Nylas fetches address_book contacts when you make a Get all Contacts request. Use source=domain or source=inbox only when the provider supports that source.
| Grant type | address_book behavior | Other sources |
|---|---|---|
| Google or Microsoft | Uses the provider contacts API. | inbox and domain availability depends on provider scopes. |
| EWS | Uses the provider contacts API. | inbox is unsupported. |
| Native iCloud | Uses iCloud CardDAV and supports list, create, update, and delete without the inbox feature gate. | inbox is separately gated and read-only. domain and compound filters fail. |
| Native Yahoo | Uses Yahoo CardDAV and supports list, create, update, and delete without the inbox feature gate. | inbox is separately gated and read-only. domain and compound filters fail. |
| Generic hosted IMAP | API-created contacts use address_book. Updating an inbox contact changes it to address_book. | Contacts are gated. inbox is parsed from message metadata. Compound address_book,inbox is supported. |
The Contacts feature for generic hosted IMAP is gated. When enabled, Nylas builds inbox contacts automatically from the name and email pairs in message from, to, cc, and bcc metadata. Creating a contact through the API always creates an address_book contact. Updating an inbox contact saves the updated contact with source=address_book.
Native iCloud and Yahoo behave differently. Their address_book contacts come from the provider’s CardDAV server, not from email messages, and don’t depend on the gated inbox feature. When enabled, their mailbox-derived inbox contacts are read-only. See the generic hosted IMAP provider guide, iCloud provider guide, and Yahoo authentication guide for setup details.
To get contact information from a user’s inbox, you need the following scopes:
- Google:
contacts.other.readonly - Microsoft:
People.Read
Native iCloud and Yahoo CardDAV contacts don’t use Google or Microsoft Contacts scopes. Configure the native provider connector and authenticate the grant as described in the iCloud provider guide or Yahoo authentication guide.
Before you begin
Section titled “Before you begin”To follow along with the samples on this page, you first need to sign up for a Nylas developer account, which gets you a free Nylas application and API key.
For a guided introduction, you can follow the Getting started guide to set up a Nylas account and Sandbox application. When you have those, you can connect an account from a calendar provider (such as Google, Microsoft, or iCloud) and use your API key with the sample API calls on this page to access that account’s data.
Return all contacts
Section titled “Return all contacts”To get a list of your user’s contacts, make a Get all Contacts request. By default, Nylas returns up to 30 results. The examples below use the limit parameter to set the maximum number of objects to 5. For more information about limits and offsets, see the pagination references.
curl --compressed --request GET \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --header 'Content-Type: application/json'{ "request_id": "1", "data": [ { "birthday": "1960-12-31", "company_name": "Nylas", "emails": [ { "type": "work", }, { "type": "home", } ], "given_name": "Leyah", "grant_id": "<NYLAS_GRANT_ID>", "groups": [{ "id": "starred" }, { "id": "friends" }], "id": "<CONTACT_ID>", "im_addresses": [ { "type": "jabber", "im_address": "jabber_at_leyah" }, { "type": "msn", "im_address": "leyah.miller" } ], "job_title": "Software Engineer", "manager_name": "Nyla", "middle_name": "Allison", "metadata": { "key1": "customer-123", "crm_record": "crm-456" }, "nickname": "Allie", "notes": "Loves ramen", "object": "contact", "office_location": "123 Main Street", "phone_numbers": [ { "type": "work", "number": "+1-555-555-5555" }, { "type": "home", "number": "+1-555-555-5556" } ], "physical_addresses": [ { "type": "work", "street_address": "123 Main Street", "postal_code": "94107", "state": "CA", "country": "US", "city": "San Francisco" }, { "type": "home", "street_address": "123 Main Street", "postal_code": "94107", "state": "CA", "country": "US", "city": "San Francisco" } ], "picture_url": "https://example.com/picture.jpg", "source": "address_book", "surname": "Miller", "web_pages": [ { "type": "work", "url": "<WEBPAGE_URL>" }, { "type": "home", "url": "<WEBPAGE_URL>" } ] } ], "next_cursor": "2"}import Nylas from "nylas";
const nylas = new Nylas({ apiKey: "<NYLAS_API_KEY>", apiUri: "<NYLAS_API_URI>",});
async function fetchContacts() { try { const identifier = "<NYLAS_GRANT_ID>"; const contacts = await nylas.contacts.list({ identifier, queryParams: {}, });
console.log("Recent Contacts:", contacts); } catch (error) { console.error("Error fetching drafts:", error); }}
fetchContacts();from nylas import Client
nylas = Client( "<NYLAS_API_KEY>", "<NYLAS_API_URI>")
grant_id = "<NYLAS_GRANT_ID>"
contacts = nylas.contacts.list( grant_id,)
print(contacts)require 'nylas'
nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")contacts, _ = nylas.contacts.list(identifier: "<NYLAS_GRANT_ID>")
contacts.each {|contact| puts "Name: #{contact[:given_name]} #{contact[:surname]} | " \ "Email: #{contact[:emails][0][:email]} | ID: #{contact[:id]}"}import com.nylas.NylasClient
fun main(args: Array<String>) { val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>") val contacts = nylas.contacts().list("<NYLAS_GRANT_ID>")
for(contact in contacts.data){ println(contact) }}import com.nylas.NylasClient;import com.nylas.models.*;
public class ReadAllContacts { public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError { NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build(); ListResponse<Contact> contacts = nylas.contacts().list("<NYLAS_GRANT_ID>");
for(Contact contact : contacts.getData()) { System.out.println(contact); System.out.println("\n"); } }}View a contact
Section titled “View a contact”To get information about a specific contact, make a Get Contact request with the contact’s ID.
curl --compressed --request GET \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts/<CONTACT_ID>' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --header 'Content-Type: application/json'{ "request_id": "1", "data": { "birthday": "1960-12-31", "company_name": "Nylas", "emails": [ { "type": "work", }, { "type": "home", } ], "given_name": "Leyah", "grant_id": "<NYLAS_GRANT_ID>", "groups": [{ "id": "starred" }, { "id": "friends" }], "id": "<CONTACT_ID>", "im_addresses": [ { "type": "jabber", "im_address": "leyah_jabber" }, { "type": "msn", "im_address": "leyah_msn" } ], "job_title": "Software Engineer", "manager_name": "Bill", "middle_name": "Allison", "metadata": { "key1": "customer-123", "crm_record": "crm-456" }, "nickname": "Allie", "notes": "Loves ramen", "object": "contact", "office_location": "123 Main Street", "phone_numbers": [ { "type": "work", "number": "+1-555-555-5555" }, { "type": "home", "number": "+1-555-555-5556" } ], "physical_addresses": [ { "type": "work", "street_address": "123 Main Street", "postal_code": "94107", "state": "CA", "country": "US", "city": "San Francisco" }, { "type": "home", "street_address": "123 Main Street", "postal_code": "94107", "state": "CA", "country": "US", "city": "San Francisco" } ], "picture_url": "https://example.com/picture.jpg", "source": "address_book", "surname": "Miller", "web_pages": [ { "type": "work", "url": "<WEBPAGE_URL>" }, { "type": "home", "url": "<WEBPAGE_URL>" } ] }}import Nylas from "nylas";
const nylas = new Nylas({ apiKey: "<NYLAS_API_KEY>", apiUri: "<NYLAS_API_URI>",});
async function fetchContactById() { try { const contact = await nylas.contacts.find({ identifier: "<NYLAS_GRANT_ID>", contactId: "<CONTACT_ID>", queryParams: {}, });
console.log("contact:", contact); } catch (error) { console.error("Error fetching contact:", error); }}
fetchContactById();from nylas import Client
nylas = Client( "<NYLAS_API_KEY>", "<NYLAS_API_URI>")
grant_id = "<NYLAS_GRANT_ID>"contact_id = "<CONTACT_ID>"
contact = nylas.contacts.find( grant_id, contact_id,)
print(contact)require 'nylas'
nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")contact, _ = nylas.contacts.find(identifier: "<NYLAS_GRANT_ID>", contact_id: "<CONTACT_ID>")
puts contactimport com.nylas.NylasClient
fun main(args: Array<String>) { val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>") var contact = nylas.contacts().find("<NYLAS_GRANT_ID>", "<CONTACT_ID>")
print(contact)}import com.nylas.NylasClient;import com.nylas.models.*;
public class ReturnAContact { public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError { NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build(); Response<Contact> contact = nylas.contacts().find("<NYLAS_GRANT_ID>", "<CONTACT_ID>");
System.out.println(contact); }}Store CardDAV contact IDs safely
Section titled “Store CardDAV contact IDs safely”Native iCloud and Yahoo contact IDs start with carddav_v1_. The encoded value contains the contact’s canonical provider href. It doesn’t contain an ETag and doesn’t rely on a Nylas ID mapping.
Treat the ID as opaque, untrusted, and grant-bound. URL-encode it in request paths and never decode it to construct your own CardDAV request. Nylas validates the underlying href against the address books discovered for that grant.
An ordinary update keeps the same ID while the provider href stays stable:
Before update: carddav_v1_<CONTACT_HREF_A>After update: carddav_v1_<CONTACT_HREF_A>The Contacts API doesn’t expose an address-book move operation. If the user or provider moves the resource, its href and ID can change. You might observe a deletion for the old ID and an update for the new ID:
Before move: carddav_v1_<CONTACT_HREF_A>After move: carddav_v1_<CONTACT_HREF_B>Always persist the latest data.id from an API response or notification. A CardDAV ID is a current locator, not a permanent tombstone: if the provider later reuses the same href, Nylas can return the same derived ID for the new resource.
Download contact profile image
Section titled “Download contact profile image”Many providers let users assign a photo to a contact’s profile. You can access contact profile images by including the ?profile_picture=true query parameter in a Get Contact request.
Nylas returns a Base64-encoded data blob that represents the profile image. To save or display the image, redirect the response to an appropriate file.
Native iCloud and Yahoo CardDAV contacts don’t support profile_picture=true.
curl --request GET \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts/<CONTACT_ID>?profile_picture=true' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --header 'Content-Type: application/json'{ "request_id": "1", "data": { "birthday": "1960-12-31", "emails": [ { "type": "home", } ], "given_name": "Leyah", "grant_id": "<NYLAS_GRANT_ID>", "groups": [{ "id": "starred" }, { "id": "friends" }], "id": "<CONTACT_ID>", "middle_name": "Allison", "nickname": "Allie", "object": "contact", "phone_numbers": [ { "type": "home", "number": "+1-555-555-5556" } ], "physical_addresses": [ { "type": "home", "street_address": "123 Main Street", "postal_code": "94107", "state": "CA", "country": "US", "city": "San Francisco" } ], "picture_url": "https://example.com/picture.jpg", "picture": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4QAqRXhpZgAASUkqAAgAAAABADEB...", "source": "address_book", "surname": "Miller" }}Create a contact
Section titled “Create a contact”To create a contact, make a Create Contact request that includes the contact’s profile information.
curl --compressed --request POST \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --header 'Content-Type: application/json' \ --data '{ "birthday": "1960-12-31", "company_name": "Nylas", "emails": [ { "email": "[email protected]", "type": "work" }, { "email": "[email protected]", "type": "home" } ], "given_name": "Leyah", "groups": [ { "id": "starred" }, { "id": "friends" } ], "im_addresses": [ { "type": "jabber", "im_address": "leyah_jabber" }, { "type": "msn", "im_address": "leyah_msn" } ], "job_title": "Software Engineer", "manager_name": "Bill", "middle_name": "Allison", "metadata": { "key1": "customer-123", "crm_record": "crm-456" }, "nickname": "Allie", "notes": "Loves Ramen", "office_location": "123 Main Street", "phone_numbers": [ { "number": "+1-555-555-5555", "type": "work" }, { "number": "+1-555-555-5556", "type": "home" } ], "physical_addresses": [ { "type": "work", "street_address": "123 Main Street", "postal_code": "94107", "state": "CA", "country": "USA", "city": "San Francisco" }, { "type": "home", "street_address": "456 Main Street", "postal_code": "94107", "state": "CA", "country": "USA", "city": "San Francisco" } ], "source": "address_book", "surname": "Miller", "web_pages": [ { "type": "work", "url": "<WEBPAGE_URL>" }, { "type": "home", "url": "<WEBPAGE_URL>" } ] }'{ "request_id": "1", "data": { "birthday": "1960-12-31", "company_name": "Nylas", "emails": [ { "type": "work", }, { "type": "home", } ], "given_name": "Leyah", "grant_id": "<NYLAS_GRANT_ID>", "groups": [{ "id": "starred" }, { "id": "friends" }], "id": "<CONTACT_ID>", "im_addresses": [ { "type": "jabber", "im_address": "leyah_jabber" }, { "type": "msn", "im_address": "leyah_msn" } ], "job_title": "Software Engineer", "manager_name": "Bill", "middle_name": "Allison", "metadata": { "key1": "customer-123", "crm_record": "crm-456" }, "nickname": "Allie", "notes": "Loves ramen", "object": "contact", "office_location": "123 Main Street", "phone_numbers": [ { "type": "work", "number": "+1-555-555-5555" }, { "type": "home", "number": "+1-555-555-5556" } ], "physical_addresses": [ { "type": "work", "street_address": "123 Main Street", "postal_code": "94107", "state": "CA", "country": "US", "city": "San Francisco" }, { "type": "home", "street_address": "321 Pleasant Drive", "postal_code": "94107", "state": "CA", "country": "US", "city": "San Francisco" } ], "picture_url": "https://example.com/picture.jpg", "source": "address_book", "surname": "Miller", "web_pages": [ { "type": "work", "url": "<WEBPAGE_URL>" }, { "type": "home", "url": "<WEBPAGE_URL>" } ] }}import Nylas from "nylas";
const nylas = new Nylas({ apiKey: "<NYLAS_API_KEY>", apiUri: "<NYLAS_API_URI>",});
async function createContact() { try { const contact = await nylas.contacts.create({ identifier: "<NYLAS_GRANT_ID>", requestBody: { givenName: "My", middleName: "Nylas", surname: "Friend", notes: "Make sure to keep in touch!", phoneNumbers: [{ type: "work", number: "(555) 555-5555" }], webPages: [{ type: "other", url: "nylas.com" }], }, });
console.log("Contact:", JSON.stringify(contact)); } catch (error) { console.error("Error to create contact:", error); }}
createContact();from nylas import Client
nylas = Client( "<NYLAS_API_KEY>", "<NYLAS_API_URI>")
grant_id = "<NYLAS_GRANT_ID>"
contact = nylas.contacts.create( grant_id, request_body={ "middle_name": "Nylas", "surname": "Friend", "notes": "Make sure to keep in touch!", "phone_numbers": [{"type": "work", "number": "(555) 555-5555"}], "web_pages": [{"type": "other", "url": "nylas.com"}] })
print(contact)require 'nylas'
nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")
request_body = { given_name: "My", middle_name: "Nylas", surname: "Friend", notes: "Make sure to keep in touch!", phone_numbers: [{number: "555 555-5555", type: "business"}], web_pages: [{url: "https://www.nylas.com", type: "homepage"}]}
contact, _ = nylas.contacts.create(identifier: "<NYLAS_GRANT_ID>", request_body: request_body)
puts contactimport com.nylas.NylasClientimport com.nylas.models.ContactEmailimport com.nylas.models.CreateContactRequestimport com.nylas.models.WebPage
fun main(args: Array<String>) { val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>") val webpage : List<WebPage> = listOf(WebPage("https://www.nylas.com", "work"))
val contactRequest = CreateContactRequest.Builder(). emails(emails). companyName("Nylas"). givenName("Nylas' Swag"). notes("This is good swag"). webPages(webpage). build()
val contact = nylas.contacts().create("<NYLAS_GRANT_ID>", contactRequest)
print(contact.data)}import com.nylas.NylasClient;import com.nylas.models.*;import java.util.ArrayList;import java.util.List;
public class CreateAContact { public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
List<ContactEmail> contactEmails = new ArrayList<>();
List<WebPage> contactWebpages = new ArrayList<>(); contactWebpages.add(new WebPage("https://www.nylas.com", "work"));
CreateContactRequest requestBody = new CreateContactRequest.Builder(). emails(contactEmails). companyName("Nylas"). givenName("Nylas' Swag"). notes("This is good swag"). webPages(contactWebpages). build();
Response<Contact> contact = nylas.contacts().create("<NYLAS_GRANT_ID>", requestBody);
System.out.println(contact); }}Modify a contact
Section titled “Modify a contact”Make an Update Contact request with the contact id to change a contact’s details.
curl --request PUT \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts/<CONTACT_ID>' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --header 'Content-Type: application/json' \ --data '{ "job_title": "Senior Software Engineer" }'{ "request_id": "1", "data": { "birthday": "1960-12-31", "company_name": "Nylas", "emails": [ { "type": "work", }, { "type": "home", } ], "given_name": "Leyah", "grant_id": "<NYLAS_GRANT_ID>", "groups": [{ "id": "starred" }, { "id": "friends" }], "id": "<CONTACT_ID>", "im_addresses": [ { "type": "jabber", "im_address": "leyah_jabber" }, { "type": "msn", "im_address": "leyah_msn" } ], "job_title": "Senior Software Engineer", "manager_name": "Bill", "middle_name": "Allison", "nickname": "Allie", "notes": "Loves ramen", "object": "contact", "office_location": "123 Main Street", "phone_numbers": [ { "type": "work", "number": "+1-555-555-5555" }, { "type": "home", "number": "+1-555-555-5556" } ], "physical_addresses": [ { "type": "work", "street_address": "123 Main Street", "postal_code": "94107", "state": "CA", "country": "US", "city": "San Francisco" }, { "type": "home", "street_address": "321 Pleasant Drive", "postal_code": "94107", "state": "CA", "country": "US", "city": "San Francisco" } ], "picture_url": "https://example.com/picture.jpg", "source": "address_book", "surname": "Miller", "web_pages": [ { "type": "work", "url": "<WEBPAGE_URL>" }, { "type": "home", "url": "<WEBPAGE_URL>" } ] }}import Nylas from "nylas";
const nylas = new Nylas({ apiKey: "<NYLAS_API_KEY>", apiUri: "<NYLAS_API_URI>",});
async function updateContact() { try { const contact = await nylas.contacts.update({ identifier: "<NYLAS_GRANT_ID>", contactId: "<CONTACT_ID>", requestBody: { givenName: "Nyla", }, });
console.log("Contact:", JSON.stringify(contact)); } catch (error) { console.error("Error to create contact:", error); }}
updateContact();from nylas import Client
nylas = Client( "<NYLAS_API_KEY>", "<NYLAS_API_URI>")
grant_id = "<NYLAS_GRANT_ID>"contact_id = "<CONTACT_ID>"
contact = nylas.contacts.update( grant_id, contact_id, request_body={ "given_name": "Nyla", })
print(contact)require 'nylas'
nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")
request_body = { notes: "This is *the best* swag",}
contact, _ = nylas.contacts.update(identifier: "<NYLAS_GRANT_ID>", contact_id: "<CONTACT_ID>", request_body: request_body)
puts contactimport com.nylas.NylasClientimport com.nylas.models.*
fun main(args: Array<String>) { val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>")
val updateRequest = UpdateContactRequest.Builder(). notes("This is *the best* swag"). build()
val contact = nylas.contacts().update("<NYLAS_GRANT_ID>", "<CONTACT_ID>", updateRequest)
print(contact.data)}import com.nylas.NylasClient;import com.nylas.models.*;
public class UpdateContact { public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError { NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
UpdateContactRequest requestBody = new UpdateContactRequest. Builder(). notes("This is *the best* swag"). build();
Response<Contact> contact = nylas.contacts().update("<NYLAS_GRANT_ID>", "<CONTACT_ID>", requestBody);
System.out.println(contact); }}Add metadata to a contact
Section titled “Add metadata to a contact”Contact metadata stores application data without writing it to the provider contact or vCard. It works for Google, Microsoft Graph, EWS, hosted IMAP, native iCloud, and native Yahoo grants. The metadata belongs to the Contact object only; Contact Group objects and endpoints don’t support it.
You can supply metadata when you create a contact, as shown in the Create a contact sample. Create, get, list, and update responses hydrate the metadata field from Nylas storage.
Send only metadata to update it without changing provider fields:
curl --request PUT \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts/<CONTACT_ID>' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --header 'Content-Type: application/json' \ --data '{ "metadata": { "key1": "customer-123", "crm_record": "crm-789" } }'curl --request PUT \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts/<CONTACT_ID>' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --header 'Content-Type: application/json' \ --data '{ "metadata": {} }'Metadata updates follow these rules:
- Omitting
metadatapreserves the existing object. - Supplying an object replaces the whole existing object.
- Supplying
"metadata": {}clears the metadata. - Deleting the contact also cleans up its Nylas-managed metadata.
- Deleting the grant removes metadata stored for its Contacts.
Use one of the indexed keys key1 through key5 with metadata_pair to filter contacts:
curl --request GET \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts?metadata_pair=key1:customer-123&limit=50' \ --header 'Authorization: Bearer <NYLAS_API_KEY>'You can paginate a metadata query with limit and page_token. You can’t combine metadata_pair with email, phone_number, group, recurse, or a non-default source. If a filtered metadata record points to a provider contact that no longer exists, Nylas removes the stale record while resolving the query.
Delete a contact
Section titled “Delete a contact”To delete a contact, make a Delete Contact request with the contact’s id.
curl --compressed --request DELETE \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts/<CONTACT_ID>' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --header 'Content-Type: application/json'import Nylas from "nylas";
const nylas = new Nylas({ apiKey: "<NYLAS_API_KEY>", apiUri: "<NYLAS_API_URI>",});const identifier = "<NYLAS_GRANT_ID>";const contactId = "<CONTACT_ID>";
const deleteContact = async () => { try { await nylas.contacts.destroy({ identifier, contactId }); console.log(`Contact with ID ${contactId} deleted successfully.`); } catch (error) { console.error(`Error deleting contact with ID ${contactId}:`, error); }};
deleteContact();from nylas import Client
nylas = Client( "<NYLAS_API_KEY>", "<NYLAS_API_URI>")
grant_id = "<NYLAS_GRANT_ID>"contact_id = "<CONTACT_ID>"
request = nylas.contacts.destroy( grant_id, contact_id,)
print(request)require 'nylas'
nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")status, _ = nylas.contacts.destroy(identifier: "<NYLAS_GRANT_ID>", contact_id: "<CONTACT_ID>")
puts statusimport com.nylas.NylasClient
fun main(args: Array<String>) { val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>") var contact = nylas.contacts().destroy("<NYLAS_GRANT_ID>", "<CONTACT_ID>")
print(contact)}import com.nylas.NylasClient;import com.nylas.models.*;
public class DeleteAContact { public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError { NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build(); DeleteResponse contact = nylas.contacts().destroy("<NYLAS_GRANT_ID>", "<CONTACT_ID>");
System.out.println(contact); }}Organize contacts with contact groups
Section titled “Organize contacts with contact groups”Contact groups let your users organize their contacts. You can get a full list of a user’s contact groups by making a Get Contact Groups request.
For native iCloud and Yahoo grants, Nylas returns explicit provider-backed group vCard records only. Address-book collections are containers, not groups, and combined views such as iCloud All Contacts don’t appear. CardDAV group IDs start with carddav_group_v1_; treat them as opaque and grant-bound, and expect the ID to change if the provider moves the group resource.
curl --compressed --request GET \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/contacts/groups' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --header 'Content-Type: application/json'{ "request_id": "1", "data": [ { "grant_id": "<NYLAS_GRANT_ID>", "group_type": "system", "id": "starred", "name": "starred", "object": "contact_group", "path": "parentId/starred" }, { "grant_id": "<NYLAS_GRANT_ID>", "group_type": "user", "id": "friends", "name": "friends", "object": "contact_group", "path": "parentId/friends" } ], "next_cursor": "2"}import Nylas from "nylas";
const nylas = new Nylas({ apiKey: "<NYLAS_API_KEY>", apiUri: "<NYLAS_API_URI>",});
async function listContactGroups() { try { const groups = await nylas.contacts.groups({ identifier: "<NYLAS_GRANT_ID>", });
console.log("Contact groups:", groups); } catch (error) { console.error("Error listing contact groups:", error); }}
listContactGroups();from nylas import Client
nylas = Client( "<NYLAS_API_KEY>", "<NYLAS_API_URI>")
grant_id = "<NYLAS_GRANT_ID>"
contact_groups = nylas.contacts.list_groups( grant_id,)
print(contact_groups)require 'nylas'
nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")groups = nylas.contacts.list_groups(identifier: "<NYLAS_GRANT_ID>")
puts groupsimport com.nylas.NylasClient
fun main(args: Array<String>) {
val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>") var groups = nylas.contacts().listGroups("<NYLAS_GRANT_ID>")
print(groups)}import com.nylas.NylasClient;import com.nylas.models.*;
public class ReadContactGroups { public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError { NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build(); ListResponse<ContactGroup> groups = nylas.contacts().listGroups("<NYLAS_GRANT_ID>");
System.out.println(groups); }}The Contacts API manages group membership through the groups field on Contact create and update requests, and removes contact membership when you delete a contact. It doesn’t expose endpoints to create, rename, or delete Contact Group resources. Concurrent provider edits can cause a conflict or partial failure during a membership update. Fetch the latest Contact and Contact Groups before retrying. See Work with Contact Groups for provider-specific examples.
Contacts limitations
Section titled “Contacts limitations”Keep the following limitations in mind as you work with the Contacts API.
Native CardDAV safety limits and errors
Section titled “Native CardDAV safety limits and errors”Native iCloud and Yahoo list responses contain at most 200 Contacts per API page. Nylas rejects an individual provider vCard larger than 1 MB and a CardDAV inventory response larger than 8 MB instead of parsing unbounded provider data.
Native group operations are bounded to 1,000 groups, 9,000 member references per group, 100,000 member references across the result, 10,000 scanned provider resources, 1 MB per group vCard, and 8 MB of group-card data. If provider data exceeds a bound, Nylas returns a provider error.
CardDAV requests can also fail because an ID is invalid or belongs to another grant, authentication, or permissions changed, the provider has no unambiguous writable address book, an ETag conflict occurred, or the provider rate-limited or timed out. Group membership operations can partially change provider resources before an error. Fetch current Contact and Contact Group state before retrying a failed write.
Google limitations
Section titled “Google limitations”Google doesn’t have a modern push notification API to handle real-time changes to contacts, so Nylas polls for changes every 5 minutes.
Microsoft Graph limitations
Section titled “Microsoft Graph limitations”- Microsoft doesn’t support the
othertype for phone numbers. - Contacts can have at most two
homephone numbers, twoworkphone numbers, and onemobilephone number. - Contacts can have at most one
homephysical address, oneworkphysical address, and oneotherphysical address. - Contacts can have up to three email addresses.
- Email addresses have their
typeset tonullby default.
- Email addresses have their
- Contacts can have a maximum of three instant messenger (IM) addresses.
- Contacts can have only one
workwebpage.
Microsoft Exchange (EWS) limitations
Section titled “Microsoft Exchange (EWS) limitations”Because of the way the Microsoft Exchange protocol works, Nylas applies the following limitations to Exchange contacts:
- Contacts can have at most two
homephone numbers, twoworkphone numbers, onemobilephone number, and oneotherphone number. - Contacts can have at most one
homephysical address, oneworkphysical address, and oneotherphysical address. - Contacts can have a maximum of three instant messenger (IM) addresses.
- IM addresses have their
typeset tonullby default.
- IM addresses have their
- Microsoft Exchange doesn’t support adding contacts on Microsoft Exchange accounts to contact groups.
- Microsoft Exchange doesn’t support the
suffixproperty on Exchange contacts. - Contacts can have up to three email addresses.
- Email addresses have their
typeset tonullby default.
- Email addresses have their
- Contacts can have a maximum of three instant messenger (IM) addresses.
- IM addresses have their
typeset tonullby default.
- IM addresses have their
- Contacts can have only one
workwebpage.
iCloud limitations
Section titled “iCloud limitations”source=address_bookuses native CardDAV.inboxis a separately gated, read-only source;domainand compound sources are unsupported.- iCloud contacts support multiple email addresses, phone numbers, physical addresses, IM addresses, and web pages.
manager_name,office_location, and profile pictures are unsupported. - The first successful CardDAV notification scan establishes a baseline and doesn’t publish historical contacts. Later polling can emit
contact.updatedandcontact.deleted. - Provider-originated changes aren’t real-time. Duplicate notifications are possible, and the sync cursor can advance before publication, so the notification feed isn’t an exactly-once or lossless change log.
- Contact IDs and Contact Group IDs are href-derived locators. A provider-side move can change an ID.
Yahoo limitations
Section titled “Yahoo limitations”- Native Yahoo grants use CardDAV for
source=address_book. Generic hosted IMAP grants don’t gain Yahoo CardDAV support. - A Yahoo contact supports at most one email address and multiple phone numbers, physical addresses, IM addresses, and web pages. Some fields, including
manager_name,office_location, and profile pictures, aren’t writable. - Yahoo doesn’t emit
contact.updatedorcontact.deletednotifications, including for Contacts API writes. - Yahoo rejects the filtered CardDAV group query, so Nylas uses a bounded inventory and
addressbook-multigetfallback. Large or conflicting group updates can return provider errors.