Fork me on GitHub

JMAP Contacts

This document specifies a data model for synchronising contacts data with a server using JMAP.

Introduction

JMAP is a generic protocol for synchronising data, such as mail, calendars or contacts, between a client and a server. It is optimised for mobile and web environments, and aims to provide a consistent interface to different data types.

This specification defines a data model for synchronising contacts between a client and a server using JMAP.

Notational Conventions

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [@!RFC2119].

The underlying format used for this specification is JSON. Consequently, the terms “object” and “array” as well as the four primitive types (strings, numbers, booleans, and null) are to be interpreted as described in Section 1 of [@!RFC7159].

Some examples in this document contain “partial” JSON documents used for illustrative purposes. In these examples, three periods “…” are used to indicate a portion of the document that has been removed for compactness.

Types signatures are given for all JSON objects in this document. The following conventions are used:

Terminology

The same terminology is used in this document as in the core JMAP specification.

Addition to the capabilities object

The capabilities object is returned as part of the standard JMAP authentication response; see the JMAP spec. Servers supporting this specification MUST add a property called {TODO: URI for this spec} to the capabilities object. The value of this is an empty object.

Contact Groups

A Contact Group represents a named set of contacts. It has the following properties:

getContactGroups

Contact Groups can either be fetched explicitly by id, or all of them at once. To fetch contact groups, make a call to getContactGroups. It takes the following arguments:

The response to getContactGroups is called contactGroups. It has the following arguments:

The following errors may be returned instead of the contactGroups response:

accountNotFound: Returned if an accountId was explicitly included with the request, but it does not correspond to a valid account.

accountNotSupportedByMethod: Returned if the accountId given corresponds to a valid account, but the account does not support this data type.

requestTooLarge: Returned if the number of ids requested by the client exceeds the maximum number the server is willing to process in a single method call.

invalidArguments: Returned if one of the arguments is of the wrong type, or otherwise invalid. A description property MAY be present on the response object to help debug with an explanation of what the problem was.

getContactGroupUpdates

The getContactGroupUpdates call allows a client to efficiently update the state of its cached contacts to match the new state on the server. It takes the following arguments:

The response to getContactGroupUpdates is called contactGroupUpdates. It has the following arguments:

If a group has been modified AND deleted since the oldState, the server should just return the id in the removed array, but MAY return it in the changed array as well. If a group has been created AND deleted since the oldState, the server SHOULD remove the group id from the response entirely, but MAY include it in the removed array.

The following errors may be returned instead of the contactGroupUpdates response:

accountNotFound: Returned if an accountId was explicitly included with the request, but it does not correspond to a valid account.

accountNotSupportedByMethod: Returned if the accountId given corresponds to a valid account, but the account does not support this data type.

invalidArguments: Returned if the request does not include one of the required arguments, or one of the arguments is of the wrong type, or otherwise invalid. A description property MAY be present on the response object to help debug with an explanation of what the problem was.

cannotCalculateChanges: Returned if the server cannot calculate the changes from the state string given by the client. Usually due to the client’s state being too old. The client MUST invalidate its ContactGroup cache.

setContactGroups

Modifying the state of ContactGroup objects on the server is done via the setContactGroups method. This encompasses creating, updating and destroying ContactGroup records.

The setContactGroups method takes the following arguments:

Each create, update or destroy is considered an atomic unit. It is permissible for the server to commit some of the changes but not others, however it is not permissible to only commit part of an update to a single group (e.g. update the name property but not the contactIds property if both are supplied in the update object).

If a create, update or destroy is rejected, the appropriate error MUST be added to the notCreated/notUpdated/notDestroyed property of the response and the server MUST continue to the next create/update/destroy. It does not terminate the method.

If an id given cannot be found, the update or destroy MUST be rejected with a notFound set error.

If any of the properties in a create or update are invalid (immutable and different to the current server value, wrong type, non-existent contactId value in contactsIds list), the server MUST reject the create/update with a SetError of type invalidProperties. The SetError object SHOULD contain a property called properties of type String[] that lists all the properties that were invalid. The object MAY also contain a description property of type String with a user-friendly description of the problems.

Contacts Groups reference Contacts. When groups are created or modified, they may reference contacts being created in the same API request by using the creation id prefixed with a #. The order of the method calls in the request by the client MUST be such that the contact being referenced is created in an earlier call. The server thus never has to look ahead. Instead, while processing a request (a series of method calls), the server MUST keep a simple map for the duration of the request of creation id to Contact id for each newly created contact, so it can substitute in the correct value if necessary in later method calls. Creation ids sent by the client SHOULD be unique within the single API request for a particular data type. If a creation id is reused, the server MUST map the creation id to the most recently created item with that id.

The response to setContactGroups is called contactGroupsSet. It has the following arguments:

A SetError object has the following properties:

The following errors may be returned instead of the contactGroupsSet response:

accountNotFound: Returned if an accountId was explicitly included with the request, but it does not correspond to a valid account.

accountNotSupportedByMethod: Returned if the accountId given corresponds to a valid account, but the account does not support this data type.

accountReadOnly: Returned if the account has isReadOnly == true.

requestTooLarge: Returned if the total number of objects to create, update or destroy exceeds the maximum number the server is willing to process in a single method call.

invalidArguments: Returned if one of the arguments is of the wrong type, or otherwise invalid. A description property MAY be present on the response object to help debug with an explanation of what the problem was.

stateMismatch: Returned if an ifInState argument was supplied and it does not match the current state.

ContactLists

A ContactList is a query on the set of contacts in a user’s contacts. The client can optionally also fetch the contacts.

getContactList

To fetch a contact list, make a call to getContactList. It takes the following arguments:

Filtering

A FilterOperator object has the following properties:

A FilterCondition object has the following properties:

If zero properties are specified on the FilterCondition, the condition MUST always evaluate to true. If multiple properties are specified, ALL must apply for the condition to be true (it is equivalent to splitting the object into one-property conditions and making them all the child of an AND filter operator).

The exact semantics for matching String fields is deliberately not defined to allow for flexibility in indexing implementation, subject to the following:

Sorting

Results MUST be sorted in a stable order so the client can load the full list in sections. The exact ordering to use is server dependent.

Windowing

To paginate the results the client MAY supply a position argument: this is the 0-based index of the first result to return in the list of contacts after filtering and sorting. If the index is greater than or equal to the total number of contacts in the list, then there are no results to return, but this DOES NOT generate an error. If null, this defaults to 0.

Response

The response to a call to getContactList is called contactList. It has the following arguments:

The following errors may be returned instead of the contactList response:

accountNotFound: Returned if an accountId was explicitly included with the request, but it does not correspond to a valid account.

accountNotSupportedByMethod: Returned if the accountId given corresponds to a valid account, but the account does not support this data type.

invalidArguments: Returned if the request does not include one of the required arguments, or one of the arguments is of the wrong type, or otherwise invalid. A description property MAY be present on the response object to help debug with an explanation of what the problem was.

Contacts

A Contact object stores information about a person or company. It has the following properties:

Note, none of these properties have a nullable type. If the specific information is not known for a contact, the empty string or empty array should be used as appropriate, or in the case of birthday the string "0000-00-00".

A ContactInformation object has the following properties:

An Address object has the following properties:

A File Object has the following properties:

getContacts

Contacts can either be fetched explicitly by id, or all of them at once. To fetch contacts, make a call to getContacts. It takes the following arguments:

The response to getContacts is called contacts. It has the following arguments:

The following errors may be returned instead of the contacts response:

accountNotFound: Returned if an accountId was explicitly included with the request, but it does not correspond to a valid account.

accountNotSupportedByMethod: Returned if the accountId given corresponds to a valid account, but the account does not support this data type.

requestTooLarge: Returned if the number of ids requested by the client exceeds the maximum number the server is willing to process in a single method call.

invalidArguments: Returned if the request does not include one of the required arguments, or one of the arguments is of the wrong type, or otherwise invalid. A description property MAY be present on the response object to help debug with an explanation of what the problem was.

getContactUpdates

The getContactUpdates call allows a client to efficiently update the state of its cached contacts to match the new state on the server. It takes the following arguments:

The response to getContactUpdates is called contactUpdates. It has the following arguments:

If a maxChanges is supplied, or set automatically by the server, the server MUST ensure the number of ids returned across changed and removed does not exceed this limit. If there are more changes than this between the client’s state and the current server state, the update returned SHOULD generate an update to take the client to an intermediate state, from which the client can continue to call getContactUpdates until it is fully up to date. If it is unable to calculat an intermediate state, it MUST return a cannotCalculateChanges error response instead.

If a contact has been modified AND deleted since the oldState, the server should just return the id in the removed array, but MAY return it in the changed array as well. If a contact has been created AND deleted since the oldState, the server SHOULD remove the contact id from the response entirely, but MAY include it in the removed array.

The following errors may be returned instead of the contactUpdates response:

accountNotFound: Returned if an accountId was explicitly included with the request, but it does not correspond to a valid account.

accountNotSupportedByMethod: Returned if the accountId given corresponds to a valid account, but the account does not support this data type.

invalidArguments: Returned if the request does not include one of the required arguments, or one of the arguments is of the wrong type, or otherwise invalid. A description property MAY be present on the response object to help debug with an explanation of what the problem was.

cannotCalculateChanges: Returned if the server cannot calculate the changes from the state string given by the client. Usually due to the client’s state being too old, or the server being unable to produce an update to an intermediate state when there are too many updates. The client MUST invalidate its Contact cache.

setContacts

Modifying the state of Contact objects on the server is done via the setContacts method. This encompasses creating, updating and destroying Contact records.

The setContacts method takes the following arguments:

Each create, update or destroy is considered an atomic unit. It is permissible for the server to commit some of the changes but not others, however it is not permissible to only commit part of an update to a single contact (e.g. update the firstName property but not the lastName property if both are supplied in the update object).

If a create, update or destroy is rejected, the appropriate error MUST be added to the notCreated/notUpdated/notDestroyed property of the response and the server MUST continue to the next create/update/destroy. It does not terminate the method.

If an id given cannot be found, the update or destroy MUST be rejected with a notFound set error.

If any of the properties in a create or update are invalid, the server MUST reject the create/update with a SetError of type invalidProperties. The SetError object SHOULD contain a property called properties of type String[] that lists all the properties that were invalid. The object MAY also contain a description property of type String with a user-friendly description of the problems.

To set a new avatar, the file must first be uploaded using the standard upload mechanism (see the File Uploads section of this spec). This will give the client a valid blobId/size/type to use. The server SHOULD reject attempts to set a file that is not a recognised image type as the avatar for a contact.

The response to setContacts is called contactsSet. It has the following arguments:

A SetError object has the following properties:

Other properties may also be present on the object, as described in the relevant methods.

The following errors may be returned instead of the contactsSet response:

accountNotFound: Returned if an accountId was explicitly included with the request, but it does not correspond to a valid account.

accountNotSupportedByMethod: Returned if the accountId given corresponds to a valid account, but the account does not support this data type.

accountReadOnly: Returned if the account has isReadOnly == true.

requestTooLarge: Returned if the total number of objects to create, update or destroy exceeds the maximum number the server is willing to process in a single method call.

invalidArguments: Returned if one of the arguments is of the wrong type, or otherwise invalid. A description property MAY be present on the response object to help debug with an explanation of what the problem was.

stateMismatch: Returned if an ifInState argument was supplied and it does not match the current state.