Oracle® Communications Contacts Server

RESTful Protocol Guide

Release 8.0

E60307-03

November 2016


The Oracle Communications Contacts Server RESTful protocol builds on the CardDAV protocol's key concepts to describe a web development friendly API with additional capabilities. For more information on CardDAV, see the Internet Engineering Task Force (IETF) proposed standard at:

http://tools.ietf.org/html/rfc6352

Topics:

RESTful Protocol Overview

The Contacts Server RESTful protocol enables HTTP clients to fetch, add, and edit address book related data that is stored by Contacts Server.

At the account level, the starting point is the address book home collection. By using standard HTTP methods on the address book home collection, you can:

In addition, logged-in users can list all their address books, even starting from the deployment's root URI.

Each address book is itself exposed as a collection that contains the set of entries (contact cards) belonging to that address book. In this way you can list, create, modify, and delete contact cards.

This model can be directly mapped to the CardDAV data model where an address book home collection is the container for one or multiple address book collections and where each address book collection itself contains address book entries (contact cards), represented by individual HTTP resources.

The canonical format for address book entries is the JavaScript Object Notation (JSON) format, which is described later in this document.

Authentication

Contacts Server supports Basic Authentication as the HTTP Authentication method.

Proxy Authentication

The Contacts Server configuration process creates an administrative user (for example, nabmaster). You can use this user's credentials to log in and proxy as any other user in the deployment. When providing the user name and credentials for HTTP basic authentication, give the user name as "admin;user" instead of just "user". For the password, use the administrator password. The resulting string used in the Authorization header is the base64 encoding of the string "admin;user:admin_passwd."

Address Book Discovery

To start the interaction, a client needs to discover the capabilities and location of the address book home collection for a given account. The standard way for a client to make this discovery is by using the wellknown URI and a service document. A simpler way is to configure clients to directly query a configured base URI as an authenticated user and find the address book collections. Clients could be pre-configured with the host, port and root URI for rest (for example, /nabserver/rest/ or /rest/). Then the clients could perform a GET command for address book collection URIs from that location for any further interaction.

Accessing the Corporate Directory

In corporate environments, users need access to the corporate directory in addition to their personal address books and other address books to which they have subscribed. Such directories are usually hosted in a Directory Server that is seamlessly available to users over HTTP. To this end, Contacts Server provides a configurable interface to access the corporate directory. The LDAP data is converted to the access protocol specific format by the server. For details on how to configure corporate directories and how the data is translated, see the topic on corporate directory integration in Calendar Server Concepts.

In the RESTful protocol, corporate directories are identified by a booktype value of public. Users' public address books are configured at the deployment level and are made available to users when they list their public booktype address books. Such public address books are always read-only address books. (The ACL gives only "r" rights.) Each public address book has a display name of "Corporate Directory" unless overridden in the LDAPURL specification. For more information, see the topic on configuring a domain-specific corporate directory in Contacts Server System Administrator's Guide.

Depending on the size of the Corporate Directory, you can query it by using regular LDAP searches (non-VLV mode) or by using the LDAPVirtualListControl where VLV browsing indexes are defined in the LDAP server (VLV mode). See the topic on VLV browsing in Oracle Communications Contacts Server Installation and Configuration Guide for information on creating VLV indexes. You can use the following extra parameters to effectively query such address books:

Protocol Operations

The following sections describe the operations on the address book home collection and operations on individual address books.

General Considerations

URI format

By virtue of being RESTful, this protocol exposes and allows for the discovery of URIs associated with resources.

Unless specified otherwise, clients should treat those URIs as opaque. Do not create client applications that use a certain hardwired syntax associated with a resource type. For example, do not assume that all address book collections have a URI such as http://server/rest/home/userid and http://server/rest/home/mail. While such a syntax might exist for a particular version of the server, it might change in future versions. This document in most parts uses the format http://server/rest/home/userid/. But http://server/rest/home/mail/ would be equally correct based for the default server configuration.

HTTP Methods

The RESTful protocol makes use of the following HTTP methods:

In the cases where you cannot PUT, PATCH, or DELETE due to client API limitation or firewall restrictions, the client can use an HTTP request with a POST method along with an X-HTTP-Method-Override HTTP header containing the intended method. This HTTP header is ignored if the method is not POST. For example:

>> Use of HTTP POST to delete a resource. <<

POST /rest/home/arnoldj/addressbook/xxx HTTP/1.1
Host: example.com
Content-Length: 0
X-HTTP-Method-Override: DELETE
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Use of ETag

ETag HTTP headers are returned in response to GET operations targeted at both collections and resources, that return entire contents of the collection or resource.

On address book collections, ETag values enable the use of conditional GET when trying to "refresh" the content of that address book. After retrieving the initial feed, clients can keep a copy of the returned ETag value, and use that value on subsequent GET requests by passing it in an If-None-Match HTTP request header. If the content has not changed since the last request, an HTTP status of 304 (Not Modified) and an empty body are returned. If the content has been modified, the entire new content is returned, along with a new ETag header value. The RESTful protocol also defines a "synctoken" parameter that enables clients to fetch only the changed contents based on the ETag value passed as token, which is even more efficient.

Similarly, an ETag value can be used to detect if the content of a resource has changed. For resources, in addition to GET, a PUT or PATCH with fetch parameter also returns an ETag header.

In addition to conditional GET, ETag values enable the use of conditional PUT, PATCH, or DELETE. There are cases where a client wants to modify a resource, but only if it has not changed since it was last retrieved. To achieve this, clients can add an If-Match HTTP header to their request with a value matching the last known ETag. If the resource ETag, as stored on the server, does not match the value from the If-Match header, the server must reject the request with an HTTP status of 412 (Precondition Failed).

Alternative Representations in Responses

By default, collections and resources are returned in JSON format. Clients can nevertheless ask for alternative representations to be returned in responses. This can be achieved by adding a format query parameter to the request URI. Currently only the JSON format is supported. The format parameter is present for future extension possibility.

The following value is supported:

Passing an unknown content-type must result in the default format ("json") being returned.

Response Prefix

To prevent JSON hijacking, all RESTful responses are prefixed with {}&&. You can configure this setting by using the davcore.serverdefaults.jsonprefix configuration parameter, which has the default value {}&&.

Supported Contact Properties and Handling Unknown Properties

Contacts Server uses the vCard3.0 format to store contact properties. For more information about vCard 3.0 format, see https://tools.ietf.org/html/rfc2426. In addition, Contacts Server accepts new vCard4 properties. For more information about vCard 4.0 format, see https://tools.ietf.org/html/rfc6350. Contact clients tend to add non-standard properties without explicitly marking them as X-props. Also vCard is still not stable and new properties are added often. Thus, to not lose any data, Contacts Server tries to store all properties that are provided. For a subset of the list of properties, see Property Definitions. vCard properties are stored as received by Contacts Server.

Contacts Server converts properties that are entered in JSON format to vCard. For more information on the JSON-to-vcard mapping, see vCard to JSON Contacts Mapping Rules. This mapping might result in renaming of the properties, including adding an x- prefix to unknown properties.

Status Code and Error Conditions

Successful responses use HTTP status codes in the range 2xx to 3xx. For example, in response to the successful creation of a resource using a POST method, the server returns a 201 code. On further update using PUT, the server returns a 204 code, if no fetch back is requested; and a 200 code, if a fetch back of data is requested. For a GET operation, the server generally returns 200 OK code, unless it is a conditional GET, in which case 304 Not Modified code can be returned. Creation of a subscribed address book returns a 200 code and not 201, because no new collection or resource is actually created.

Error conditions are exposed as HTTP responses with error status codes (4xx and 5xx). Common examples include using a 404 (Not Found) code when receiving requests against a URI not defined by the server; a 400 code for a general error in the request; and a 500 code for a server-side error while processing the request. In addition to the status code, servers must include a response body for error responses that includes more information about the error condition. The statuscode and statusmessage text fields are returned in the response.

In environments where handling of HTTP status code is difficult (for example, running in browsers that intercept all non 2xx responses), the httpError query parameter controls what is returned to the client. When set to 1 (default value), the whole range of HTTP status code is returned. When set to 0, a 200 OK status code is always returned, regardless of the success or failure of the operation. A status element is also returned. In case of failure, the status element contains the code and reason text elements.The client must then parse the response body to check whether the operation succeeded.

In the following example, a GET on a nonexisting collection leads to a 404 Not Found response.

>> Request <<

GET /rest/home/bogus/ HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 404 Not Found
Content-Type:application/json
Content-Length: zz

{
    "statuscode" : "404",
    "statusmessage" : "found 0 corresponding to: (uri=/rest/home/bogus)"
}

The same request with httpError=0 leads to a 200 OK response.

>> Request <<

GET /rest/home/bogus/?httpError=0 HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type:application/json
Content-Length: zz

{
    "statuscode" : "404",
    "statusmessage" : "found 0 corresponding to: (uri=/rest/home/bogus)"
}

Response in create and modify Operations

The fetch query parameter controls if a newly created or modified entry is returned on a PUT, POST, or PATCH. When set to 0, the entry is not returned. When set to 1 (default), the entry is returned.

Total Results

All GET operations return a totalresults element with a count of the actual number of entries returned.

Summary of Supported Query Parameters

Parameters Affecting All Methods
Additional Special Query Parameters

Few additional query parameters are defined to execute certain actions:

Root Collection Operations

The root collection URI for the RESTful protocol is derived by adding rest to the deployment base URI, for example, /rest/ or /nabserver/rest/.

Listing Address Books

Authenticated users can do a GET on the root collection to get their home URI and the RESTful protocol version. The response also includes the details of the user's address books, subscriptions, and public address books.

Supported parameters are: format (default: json), httpError (default: 1), and booktype (default: personal). Adding the searchstring parameter results in a different command as listed in next section.

The following example shows a listing performed by the authenticated user arnoldj.

>> Request <<

GET /rest/ HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

 {
    "restversion": "1.0",
    "baseuri": "https://example.com",
    "homeuri": "/rest/home/arnoldj/",
    "addressbook": [
        {
            "displayname": "Main Address Book",
            "description": "Arnold's Main Address Book",
            "uri": "/rest/home/arnoldj/addressbook/",
            "lastmodified": "20130321T174833Z",
            "type": "personal",
            "minsearchcharacters": "3",
            "acl": [
                "@:r",
                "admin@example.com:a"
            ]
        },
        {
            "displayname": "Personal Address Book",
            "description": "Personal Address Book",
            "uri": "/rest/home/arnoldj/personaladdressbook/",
            "lastmodified": "20130321T174833Z",
            "type": "personal",
            "minsearchcharacters": "3",
            "acl": [
                "@:n",
                "admin@example.com:r",
                "myteam@example.com:r"
            ]
        }
    ],
    "totalresults": 2
}

The following example lists subscribed address books. Notice that the "friends" address book is no longer available, because either access rights have been removed or the address book has been deleted, so myrights is displayed as 'n' (no access).

>> Request <<

GET /rest/?booktype=subscribed HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

 {
    "restversion": "1.0",
    "baseuri": "https://example.com",
    "homeuri": "/rest/home/arnoldj/",
    "addressbook": [
        {
            "displayname": "Main Address Book",
            "description": "Arnold's Main Address Book",
            "uri": "/rest/home/arnoldj/addressbook/",
            "lastmodified": "20130321T174833Z",
            "type": "personal",
            "minsearchcharacters": "3",
            "acl": [
                "@:r",
                "admin@example.com:a"
            ]
        },
        {
            "displayname": "Personal Address Book",
            "description": "Personal Address Book",
            "uri": "/rest/home/arnoldj/personaladdressbook/",
            "lastmodified": "20130321T174833Z",
            "type": "personal",
            "minsearchcharacters": "3",
            "acl": [
                "@:n",
                "admin@example.com:r",
                "myteam@example.com:r"
            ]
        },
        {
            "displayname": "Cindy's Address Book",
            "uri": "/rest/home/cindy/addressbook/",
            "lastmodified": "20130321T174833Z",
            "type": "subscribed",
            "myrights": "r"
        },
        {
            "displayname": "Address book of friends",
            "uri": "/rest/home/cindy/friends/",
            "lastmodified": "20130321T174833Z",
            "type": "subscribed",
            "myrights": "n"
        }
    ],
    "totalresults": 4
}

The following example lists all the public address books aka Corporate Directory in the deployment using the default English language.

>> Request <<

GET /rest/?booktype=public HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

 {
    "restversion": "1.0",
    "baseuri": "https://example.com",
    "homeuri": "/rest/home/arnoldj/",
    "addressbook": [
        {
            "uri": "/rest/directory/default/",
            "displayname": "Corporate Directory",
            "type": "public",
            "default": "true",
            "vlv": {
                "enabled": "true",
                "indexes": [
                    "cn",
                    "mail",
                    "sn",
                    "givenname"
                ]
            },
            "myrights": "r",
            "minsearchcharacters": "3",
        }
    ],
    "totalresults": 1
}

Adding the lang parameter returns the displayname of the public address books in that language.

>> Request <<

GET /rest/?booktype=public&lang=ja HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

 {
    "restversion": "1.0",
    "baseuri": "https://example.com",
    "homeuri": "/rest/home/arnoldj/",
    "addressbook": [
        {
            "uri": "/rest/directory/default/",
            "displayname": "企業ディレクトリ",
            "type": "public",
            "default": "true",
            "vlv": {
                "enabled": "true",
                "indexes": [
                    "cn",
                    "mail",
                    "sn",
                    "givenname"
                ]
            },
            "myrights": "r",
            "minsearchcharacters": "3",
        }
    ],
    "totalresults": 1
}

The following example shows the result when you define multiple corporate directories (using corpDirectoryUrl) for the user's domain. Each URI has the displayname customized in the corpDirectoryUrl specification, and the last segment of the URI is a hash of the corpDirectoryUrl value. Only one corpDirectoryUrl is designated as the default with the "default" property in the response set to true. The corpDirectoryUrl that has the default keyword used in the LDAPURL specification is the default.

GET /rest/?booktype=public HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

 {
    "restversion": "1.0",
    "baseuri": "https://example.com",
    "homeuri": "/rest/home/arnoldj/",
    "addressbook": [
        {
            "uri": "/rest/directory/27D4EA7E2917569DE34ECA503677DFDF/",
            "displayname": "USA HQ Directory",
            "type": "public",
            "default": "true",
            "vlv": {
                "enabled": "true",
                "indexes": [
                    "cn",
                    "mail",
                    "sn",
                    "givenname"
                ]
            },
            "myrights": "r",
            "minsearchcharacters": "3",
        },
        {
            "uri": "/rest/directory/F6464D976561B9A90EB8848266B6C693/",
            "displayname": "Europe Directory",
            "type": "public",
            "default": "false",
            "vlv": {
                "enabled": "false"
            },
            "myrights": "r",
            "minsearchcharacters": "3",
        },
        {
            "uri": "/rest/directory/BF230X6464D9908KLJW92K32L23DS4K76/",
            "displayname": "APAC Directory",
            "type": "public",
            "default": "false",
            "vlv": {
                "enabled": "false"
            },
            "myrights": "r",
            "minsearchcharacters": "3",
        }
    ],
    "totalresults": 3
}
Searching for Address Books

Perform a GET with a searchstring query parameter at the root URI to find address books belonging to users specified by the search string. The searchstring value is substituted in the server search filter defined by the server configuration parameter davcore.uriinfo.subjectsearchfilter and a query is made to Directory Server. By default it is the following:

(|(uid=%s*)(cn=%s)(mail=%s))

The search string can be either first part of the account's uid attribute or any part of its cn or mail attributes. The query is governed by the LDAP ACIs. It returns the list of users, groups, or resources matching the search string, for which the authenticated user has access. The results of the LDAP search are then checked to make sure that active address books exist for each and that the requesting user has both domain and address book ACL access to these. The information about the address books that survived the filtering is outputted.

The following parameters are supported: format (default: json), httpError (default: 1), and searchstring (default:none).

>> Request <<

GET /rest/?searchstring=cindy HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

{
    "baseuri": "https://example.com",
    "addressbook": [
        {
            "displayname": "Main Address Book",
            "description": "Cindy's Main Address Book",
            "uri": "/rest/home/cindy/addressbook/",
            "lastmodified": "20130321T174833Z",
            "type": "personal",
            "minsearchcharacters": "3",
            "myrights": "r"
        }
    ],
    "totalresults": 1
}

Address Book Home Collection Operations

Each address book home collection is represented as a collection where each entry corresponds to a particular address book collection.

Listing Address Books

To obtain the list of address books under a particular home collection, a client issues an HTTP GET on that home collection URI. The supported parameters are: format (default: json), httpError (default: 1), and booktype (default:personal). The booktype parameter with a value of personal lists only personal or owned address books, subscribed lists all subscribed including owned, and public lists corporate address book URIs.

>> Request <<

GET /rest/home/arnoldj/ HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

{
    "baseuri": "https://example.com",
    "addressbook": [
        {
            "displayname": "Main Address Book",
            "description": "Arnold's Main Address Book",
            "uri": "/rest/home/arnoldj/addressbook/",
            "lastmodified": "20130321T174833Z",
            "type": "personal",
            "minsearchcharacters": "3",
            "acl": [
                "@:r",
                "admin@example.com:a"
            ]
        },
        {
            "displayname": "Personal Address Book",
            "description": "Personal Address Book",
            "uri": "/rest/home/arnoldj/personaladdressbook/",
            "lastmodified": "20130321T174833Z",
            "type": "personal",
            "minsearchcharacters": "3",
            "acl": [
                "@:n",
                "admin@example.com:r",
                "myteam@example.com:r"
            ]
        }
    ],
    "totalresults": 2
}
Creating a Personal Address Book

To create an address book, a client makes an HTTP request with method POST on the targeted home collection.

The supported parameters are: format (default: json), httpError (default: 1), and fetch (default: 1). Adding the action parameter results in a different command as described in the following section.

Some important properties and the related rules of an address book collection include:

If the client does not follow the preceding rules, the result is a 403 "Forbidden" response.

All other properties must be ignored by the server.

On successful creation, the newly created address book is returned unless the fetch parameter is set to 0.

In the following example, an address book with a displayname of Basketball League is created. The response code (201) indicates that the address book was successfully created. The response body contains the newly created entry. The Location header contains the new URI for this collection. The last segment of that URI is based on the displayname provided with any changes required to make it part of a URI.

>> Request <<

POST /rest/home/arnoldj/?format=json HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "displayname": "Basketball League",
            "type": "personal",
            "acl": [
                "admin@example.com:a"
            ]
        }
    ]
}

>> Response <<

HTTP/1.1 201 Created
Content-Type: application/json
Location: https://example.com/rest/home/arnoldj/Basketball League/
Content-Length: xxxx

{
    "addressbook": [
        {
            "displayname": "Basketball League",
            "uri": "/rest/home/arnoldj/Basketball League/",
            "lastmodified": "20130321T174833Z",
            "acl": [
                "admin@example.com:a"
            ],
            "type": "personal",
            "minsearchcharacters": "3",
        }
    ]
}

Creating a Subscribed Address Book

To subscribe to a shared address book, POST the shared address book URI to the user's home collection with action parameter set to subscribe. You can add your own displayname to the subscription. Any other properties provided by the client are ignored by the server. A response of 200 OK is returned in most cases, with any failure information provided in the response body. If subscribing to multiple URIs, each one is returned in the response. If there are any failures, a failure status message is returned for the same. If the subscribe action is requested on an address book that is owned by the user or one that is already subscribed to, a response of 200 OK is still returned though no additional work is done on the server.

The supported parameters are: format (default: json), httpError (default: 1), fetch (default: 1), action (default: none; must be set to subscribe).

In the following example, user Arnold is subscribing to one of the address books for user Cindy that was retrieved from the search command.

>> Request <<

POST /rest/home/arnoldj/?format=json&action=subscribe HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "displayname": "Cindy's Address Book",
            "uri": "/rest/home/cindy/addressbook/"
        }
    ]
}

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

{
    "addressbook": [
        {
            "displayname": "Cindy's Address Book",
            "uri": "/rest/home/cindy/addressbook/",
            "lastmodified": "20130321T174833Z",
            "type": "subscribed",
            "myrights": "r"
        }
    ]
}

In the following example, user Arnold is subscribing to one of the address books for user Cindy and another address book for which he has no access. The latter results in a failure status.

>> Request <<

POST /rest/home/arnoldj/?format=json&action=subscribe HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "displayname": "Cindy's Address Book",
            "uri": "/rest/home/cindy/addressbook/"
        },
        {
            "displayname": "Chuck's Address Book",
            "uri": "/rest/home/chuck/addressbook/"
        }
    ]
}

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

{
    "addressbook": [
        {
            "displayname": "Cindy's Address Book",
            "uri": "/rest/home/cindy/addressbook/",
            "lastmodified": "20130321T174833Z",
            "type": "subscribed",
            "myrights": "r"
        },
        {
            "uri": "/rest/home/chuck/addressbook/",
            "statuscode": "404",
            "statusmessage": "found 0 corresponding to: (uri=/rest/home/chuck/addressbook/)"
        }
    ]
}
Deleting a Subscribed Address Book

To delete or unsubscribe to a subscribed address book, POST the subscribed address book URI to the user's home collection with the action parameter set to unsubscribe. A response of 204 (No Content) is returned if the unsubscribe action was successful. If httpError is set to 0, a response of 200 is returned with the success or failure status in the body. Multiple subscriptions can be unsubscribed in one command. In that case, if there is a partial failure, a 200 response is returned with the failed entry status message. You cannot unsubscribe to personal address books. A 405 status code is returned if an unsubscribe action is requested on a personal address book.

The supported parameters are: format (default: json), httpError (default: 1), action (default: none; the value unsubscribe must be given).

In the following example, user Arnold is unsubscribing to the address book for user Cindy.

>> Request <<

POST /rest/home/arnoldj/?format=json&action=unsubscribe HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "uri": "/rest/home/cindy/addressbook/"
        }
    ]
}

>> Response <<

HTTP/1.1 204 No Content

The following example is similar to the preceding one but with the httpError parameter set to 0.

>> Request <<

POST /rest/home/arnoldj/?format=json&action=unsubscribe&httpError=0 HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "uri": "/rest/home/cindy/addressbook/"
        }
    ]
}

>> Response <<

HTTP/1.1 200 OK
Content-Type:application/json
Content-Length: zz

{
    "statuscode" : "204"
}

In the following example, user Arnold is unsubscribing to an address book for user Cindy and unsubscribing from another address book for which the subscription does not exist.

>> Request <<

POST /rest/home/arnoldj/?format=json&action=unsubscribe HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "uri": "/rest/home/cindy/addressbook/"
        },
        {
            "uri": "/rest/home/erwin/addressbook/"
        }
    ]
}

>> Response <<

HTTP/1.1 200 OK
Content-Type:application/json
Content-Length: zz

{
    "entry": [
        {
            "uri": "/rest/home/erwin/addressbook/",
            "statuscode": "404",
            "statusmessage": "found 0 subscription corresponding to: (uri=/rest/home/erwin/addressbook/)"
        }
    ]
}

Fetching an Address Book

To fetch just a particular address book's properties including ACLs, do a GET on the address book URI with the booktype parameter set to personal, subscribed, or public, as the case may be. The default if no booktype is set is to return the contents (contact and contact group) of the address book. If the booktype value specified does not match the type of the collection, a "404 Not Found" error is returned. For example, this error is returned when specifying booktype=public on a personal (subscribed) address book URI, or booktype=personal on a corporate address book URI. Fetching with booktype set to personal fetches the address book properties as seen by the owner. That is, it shows displayname as set by the owner for other users' address books. Properties that are blocked by access control are not fetched. Fetching with booktype set to subscribed fetches the address book properties as seen by the owner for owned address books and as seen by subscriber for other users' address books. In either case, acl property is returned only for the address books you own. For other users the MyRights property is returned. Successful commands give a 200 OK status code and return the details of the address book.

The supported parameters are: format (default: json), httpError (default: 1), booktype (must be specified). Not specifying booktype explicitly results in a different command that fetches all address book entries.

>> Request <<

GET /rest/home/arnoldj/Basketball League/?format=json&booktype=personal HTTP/1.1
Host: example.com
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

{
    "addressbook": [
        {
            "displayname": "Basketball League",
            "uri": "/rest/home/arnoldj/Basketball League/",
            "lastmodified": "20130321T174833Z",
            "acl": [
                "admin@example.com:a"
            ],
            "type": "personal",
            "minsearchcharacters": "3"
        }
    ],
    "totalresults": 1
}

Modifying an Address Book

To modify the properties of an address book, a client can make an HTTP request with method PUT and all relevant properties of the address book. Not all address book properties can be modified. For other users' address books subscribed to, it is just the displayname. For public, the 403 response code should be returned because no properties can be modified. The PATCH method described later is more preferable than this method because it prevents clients from inadvertently removing properties unknown to it. Any attempt to modify an address book to which you do not have access, for example modifying a subscribed unowned address book, with booktype set to personal, should result in a 403 error.

The booktype parameter is used to indicate if an address book or a user's subscription link of it is being modified.

To delete a property, a client simply removes it from the entry. In other words, all remaining properties must be provided in the modification request. Values of server added properties like uri, type, or lastmodified are ignored even if provided.

The supported parameters are: format (default: json), httpError (default: 1), fetch (default: 1), and booktype (default: personal).

In the following example, a description property is added to the previously created Basketball League address book by using a conditional PUT. The 200 (OK) response code indicates that the address book was successfully modified. The response body contains the modified entry.

>> Request <<

PUT /rest/home/arnoldj/Basketball League/?format=json HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "displayname": "Basketball League",
            "description": "Arnold's basket ball contacts",
            "uri": "/rest/home/arnoldj/Basketball League/",
            "acl": [
                "admin@example.com:a"
            ],
            "type": "personal"
        }
    ]
}

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

{
    "addressbook": [
        {
            "displayname": "Basketball League",
            "description": "Arnold's basket ball contacts",
            "uri": "/rest/home/arnoldj/Basketball League/",
            "acl": [
                "admin@example.com:a"
            ],
            "lastmodified": "20130321T174833Z",
            "type": "personal",
            "minsearchcharacters": "3",
        }
    ]
}

To modify a subscription, do a PUT with the appropriate booktype. Not setting booktype results in attempt to modify the actual collection. The latter could fail or succeed based on the permissions the user has on the collection.

In the following example the subscription to address book owned by user Cindy is modified to change display name.

>> Request <<

PUT /rest/home/cindy/addressbook/?booktype=subscribed HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "displayname": "Cindy's Subscribed Address Book",
            "uri": "/rest/home/cindy/addressbook/"
        }
    ]
}

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

{
    "addressbook": [
        {
            "displayname": "Cindy's Subscribed Address Book",
            "uri": "/rest/home/cindy/addressbook/",
            "lastmodified": "20130321T174833Z",
            "type": "subscribed",
            "myrights": "r"
        }
    ]
}
Modifying an Address Book (Partial, "Preferred Method")

An address book's properties can also be modified by using the PATCH command. For this, a PATCH is executed against the address book's collection URI with just the properties that need to be added, modified, or deleted contained in two separate objects. The properties to be added or modified are provided as is within one object in an addressbook object and the properties to be deleted are specified within another object. The latter object must include the property x-orcl-patch-delete with its value set to true. Absence of the x-orcl-patch-delete or setting its value to false, marks the object and all the properties within it for add or modify.

In case of single valued properties, an addition replaces the existing property. In case of multi-valued properties, any addition is just added on. To replace a multi-valued property, specify it with its old value in the delete object and with the new value in the address book object. No partial updates of properties are possible. So to update a parameter of a property, the entire property with the new parameter should be given in the PATCH command. Special case for ACLs is described later.

Not all address book properties can be modified. For the subscribed address books, it is just the displayname. For public address books, the 403 response code should be returned because no properties can be modified.

The supported parameters are: format (default: json), httpError (default: 1), fetch (default: 1), booktype (default: personal). If fetch is set to 1, the entire modified entry is returned and a status code of 200 Ok is returned.

In the following example, the acl property is modified, displayname is changed, and description is removed.

>> Request <<

PATCH /rest/home/arnoldj/Basketball League/?format=json&fetch=0 HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "acl": [
                "admin@example.com:a",
                "cindy@example.com:r"
            ],
            "displayname": "Arnold's patched bball contacts"
        },
        {
            "x-orcl-patch-delete": "true",
            "description": "Arnold's basket ball contacts"
        }
    ]
}

>> Response <<

HTTP/1.1 204 No Content
Content-Length: 0

The following is the same request with fetch back. The status code changes to 200.

>> Request <<

PATCH /rest/home/arnoldj/Basketball League/?format=json HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "acl": [
                "admin@example.com:a",
                "cindy@example.com:r"
            ],
            "displayname": "Arnold's patched bball contacts"
        },
        {
            "x-orcl-patch-delete": "true",
            "description": "Arnold's basket ball contacts"
        }
    ]
}

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

{
    "addressbook": [
        {
            "displayname": "Arnold's patched bball contacts",
            "uri": "/rest/home/arnoldj/Basketball League/",
            "acl": [
                "admin@example.com:a",
                "cindy@example.com:r"
            ],
            "lastmodified": "20130321T174833Z",
            "type": "personal",
            "minsearchcharacters": "3",
        }
    ]
}

Deleting an Address Book

To delete an address book and all its content, a client sends a request with method DELETE on its collection URI. The deletion of an address book must result in the deletion of all the address book entries belonging to that address book. Only non-default personal address books can be deleted.

Upon success deletion, a 204 (No Content) status code is returned. If httpError is set to 0, a response of 200 is returned with the success or failure status in the body.

The supported parameters are: format (default: json) and httpError (default: 1)

>> Request <<

DELETE /rest/home/arnoldj/Basketball League/?format=json HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 204 No Content

Access Control Operations

An Access Control List (ACL) consists of one or more Access Control Entries (ACEs), which are strings that grant a particular level of access. Each entry in an ACL must contain 2 elements:

ACLs are denied unless explicitly granted. One can explicitly deny a user access granted through a group membership by using the 'n' setting. Some control access is "built-in" to the server. For example, owners and server administrators have full access to their address books. Granting a particular ACE means implicitly granting anything considered a "lower" ACE.

ACEs function in the following way:

The who Element

The who element defines the user or group of users to whom a set of privilege is granted.

Its text content can take the following values:

The privilege Element

The privilege element defines the set of privileges granted to the users.

Its text content can take the following values:

Listing ACEs

ACLs are returned as part of an address book listing.

Adding an ACE to a Personal Address Book

To add an ACE on an address book a client makes an HTTP request with method PUT on the collection URI associated with the address book with the entire new ACL and address book properties. Alternately, a client does a PATCH specifying the entire new ACL or just ACE to be added using the x-orcl-patch-setace property. As with other modifications, the PATCH method is the preferred method. Status code is 200 with fetch back and 204 with no fetch back. If httpError is set to 0, a response of 200 is returned with the success code in the body. When fetch back is requested, the entire adderss book entry is returned.

The following example uses the PUT approach to give joe@example.com read access to Arnold's Basketball League address book:

>> Request <<

PUT /rest/home/arnoldj/Basketball League/?format=json HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "displayname": "Basketball League",
            "uri": "/rest/home/arnoldj/Basketball League/",
            "acl": [
                "admin@example.com:a",
                "joe@example.com:r"
            ],
            "type": "personal"
        }
    ]
}

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

{
    "addressbook": [
        {
            "displayname": "Basketball League",
            "uri": "/rest/home/arnoldj/Basketball League/",
            "acl": [
                "admin@example.com:a",
                "joe@example.com:r"
            ],
            "lastmodified": "20130321T174833Z",
            "type": "personal",
            "minsearchcharacters": "3",
        }
    ]
}

The following example uses the PATCH command with the entire ACL property for doing the update to add the ACE:

>> Request <<

PATCH /rest/home/arnoldj/Basketball League/?format=json&fetch=0 HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "acl": [
                "admin@example.com:a",
                "joe@example.com:r"
            ]
        }
    ]
}

>> Response <<

HTTP/1.1 204 No Content
Content-Length: 0

The following example uses a partial ACL update or ACE update approach to add the same ACE

>> Request <<

PATCH /rest/home/arnoldj/Basketball League/?format=json HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "x-orcl-patch-setace": [
                "joe@example.com:r"
            ]
        }
    ]
}

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

{
    "addressbook": [
        {
            "displayname": "Basketball League",
            "uri": "/rest/home/arnoldj/Basketball League/",
            "acl": [
                "admin@example.com:a",
                "joe@example.com:r"
            ],
            "lastmodified": "20130321T174833Z",
            "type": "personal",
            "minsearchcharacters": "3",
        }
    ]
}
Modifying a Personal Address Book ACE

You modify an ACE just like an performing an add. To modify the privileges granted to a given user or group, the client issues an HTTP request with method PUT on the address book URI with the entire new ACL and address book properties. Alternately, you can do a PATCH specifying the entire new ACL or ACEs to be added, modified, or removed separately. In the last case, ACEs to be modified are specified by using the x-orcl-patch-setace property just like an add. The new value replaces the existing value. If successful, status code is 200 with fetch back and 204 with no fetch back. If httpError is set to 0, a response of 200 is returned with the success code in the body.

The following example shows a partial ACL or ACE level modification, changing rights for joe@example.com to "w" (write):

>> Request <<

PATCH /rest/home/arnoldj/Basketball League/?format=json&fetch=0 HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "x-orcl-patch-setace": [
                "joe@example.com:w"
            ]
        }
    ]
}

>> Response <<

HTTP/1.1 204 No Content
Content-Length: 0

Deleting an ACE of a Personal Address Book

To delete an ACE, a client sends a PUT request on the address book URI with the new ACL that has the ACE removed and all other address book properties. Alternately, you can do a PATCH replacing the whole ACL, or specifically removing that one ACE using the x-orcl-patch-removeace property. If doing the latter, you can give the entire ACE to be removed or just the principal to be removed from the ACL list. The privilege in the ACE is ignored because the ACL can only contain one entry for each principal. If successful, status code is 200 with fetch back and 204 with no fetch back. If httpError is set to 0, a response of 200 is returned with the success code in the body.

The following example shows a partial ACL or ACE level modification, removing rights for joe@example.com.

>> Request <<

PATCH /rest/home/arnoldj/Basketball League/?format=json&fetch=0 HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
        {
            "x-orcl-patch-removeace": [
                "joe@example.com"
            ]
        }
    ]
}

>> Response <<

HTTP/1.1 204 No Content
Content-Length: 0

Address Book Collection Operations

Each address book collection contains a collection of contact entries. Each entry has a uri property pointing to the URI of the entry itself. It has a vcard property that contains the actual contents of the contact. In addition it also has a type property.

Possible values for type property are:

There can be only one entry of type pcc (Personal Contact Card). It is auto-created on first access of the account and it cannot be deleted unless the account itself is being deleted.

Here is an example of such an entry object. Because most commands return more than one entry, the entry value is represented as an array of such entry objects in all the command responses.

Properties, parameters, or parts of structured values that are empty are omitted.

Any property or parameter that might have more than one value has its value represented as an array even if the entry has only one value. This is true for the entry value too. That is, entry value is always represented as an array of entry objects in RESTful command responses.

Any property value that can have parameters is represented as an object even if no parameters are present.

{
    "entry": [{
        "uri": "/rest/home/arnoldj/addressbook/one",
        "lastmodified": "20130321T174833Z",
        "type": "contact",
        "vcard": {
            "uid": { "text": "8135479335" },
            "fn": [{ "text": "JohnDoe" }],
            "email": [
                {
                    "parameters": [{
                        "type": {"text": ["work"]}
                    }],
                    "text": "john.doe@example.com"
                },{
                    "parameters": [{
                        "type": {"text": ["home"]}
                    }],
                    "text": "john.doe@home.com"
                }
            ],
            "n": [
                {
                    "surname": ["Doe"],
                    "given": ["John"],
                    "additional": ["Smith"],
                    "prefix": ["Dr."],
                    "suffix": ["Jr."]
                }
            ],
            "adr": [
                {
                    "parameters": [{
                        "type": {"text": ["work"]}
                    }],
                    "ext": ["Suite6"],
                    "street": ["282MonroeDrive"],
                    "locality": ["MountainView"],
                    "region": ["CA"],
                    "code": ["94040"],
                    "country": ["USA"]
                }
            ],
            "tel": [
                {
                    "parameters": [{
                        "type": {"text": ["work", "voice"]}
                    }],
                    "text": "tel: +1-650-656-9254;ext=102"
                }
            ]
        }
    }]
}
Listing Address Book Entries

To obtain the list of entries under a particular address book collection, a client issues an HTTP GET on that collection URI.

The supported parameters are: format (default: json), httpError (default: 1), fetchcomps (no default), fetchprops (default: fn,email,member,uid), sortprop (fn), sortorder (ascending), and searchstring (no default). sortorder and sortprop are currently only supported for public address books.

The default for fetchprops would be to return fn, email, uid, and member properties. Unknown properties are just ignored. A value of X-ORCL-ALLPROPS can be used to return all available properties. For "public" directories the valid fetchprops are uid, fn, n, email, kind, tel, adr, title, org, and url.

sortprop is supported for "public" address books only. The default for sortprop is fn.

For public directories a searchstring or count plus startindex to do pagination must be specified because retrieving everything in a public directory without pagination may result in too much data.

To get the full representation of a contact entry, clients must issue an HTTP GET on the entry's content URI.

In the following example, the queried address book contains two contact entries, one group entry, and the pcc. The first contact entry has two email addresses while the second entry does not have any. The return properties are set to default value.

>> Request <<

GET /rest/home/arnoldj/addressbook/?format=json HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx
ETag: "c180de84f991g8"

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/pcc",
            "type": "pcc",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique001"
                },
                "fn": [
                    {
                        "text": "Arnold Jones"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "type": {"text": ["work"]}
                        }],
                        "text": "arnold.jones@example.com"
                    },
                    {
                        "parameters": [{
                            "type": {"text": ["home"]}
                        }],
                        "text": "arnoldj@isp.net"
                    }
                ]
            }
        },
        {
            "uri": "/rest/home/arnoldj/addressbook/1",
            "type": "contact",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique002"
                },
                "fn": [
                    {
                        "text": "John Doe"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "type": {"text": ["work"]}
                        }],
                        "text": "john.doe@example.com"
                    },
                    {
                        "parameters": [{
                            "type": {"text": ["home"]}
                        }],
                        "text": "john.doe@isp.net"
                    }
                ]
            }
        },
        {
            "uri": "/rest/home/arnoldj/addressbook/2",
            "type": "contact",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique003"
                },
                "fn": [
                    {
                        "text": "Jane Smith"
                    }
                ]
            }
        },
        {
            "uri": "/rest/home/arnoldj/addressbook/grp1",
            "type": "contactgroup",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique004"
                },
                "fn": [
                    {
                        "text": "Work group"
                    }
                ],
                "member": [
                    {
                        "uri": "urn:uuid:unique002"
                    },
                    {
                        "uri": "urn:uuid:unique003"
                    },
                    {
                        "uri": "mailto:contractor@somewhere.com"
                    }
                ]
            }
        }
    ],
    "totalresults": 4
}

To limit the results to certain types, the fetchcomps parameter can be used. In this context pcc is also considered as a "contacts" component.

The following example shows how to fetch groups only.

>> Request <<

GET /rest/home/arnoldj/addressbook/?fetchcomps=contactgroup&fetchprops=fn,email,kind,member,uid HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx
ETag: "c180de84f991g8"

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/grp1",
            "type": "contactgroup",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique004"
                },
                "fn": [
                    {
                        "text": "Work group"
                    }
                ],
                "kind": {
                    "text": "group"
                },
                "member": [
                    {
                        "uri": "urn:uuid:unique002"
                    },
                    {
                        "uri": "urn:uuid:unique003"
                    },
                    {
                        "uri": "mailto:contractor@somewhere.com"
                    }
                ]
            }
        }
    ],
    "totalresults": 1
}

To limit the properties returned, the fetchprops parameter can be used. A value of X-ORCL-ALLPROPS can be used to return all available properties.

>> Request <<

GET /rest/home/arnoldj/addressbook/?fetchcomps=contactgroup&fetchprops=uid,fn HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx
ETag: "c180de84f991g8"

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/grp1",
            "type": "contactgroup",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique004"
                },
                "fn": [
                    {
                        "text": "Work group"
                    }
                ]
            }
        }
    ],
    "totalresults": 1
}

Specific contacts can be searched for by using the searchstring parameter, a string containing a filter that follows the XPath Syntax. The string must be enclosed within parenthesis.

The property names that can be used in the filter are:

The following property names are added for integration with Connector for Microsoft Outlook for corporate directory functions:

These three properties map to the LDAP attributes physicalDeliveryOfficeName, departmentNumber, and uid, respectively.

Value of all searches all properties. Only binary equality operator (=) is supported with all.

Filter Strings can be constructed using the following:

Enclose literal strings with single or double quotation marks and encode any special URL characters.

>> Request <<

GET /rest/home/arnoldj/addressbook/?format=json&searchstring=(contains(email,%20'john')) HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx
ETag: "c180de84f991g8"

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/1",
            "type": "contact",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique002"
                },
                "fn": [
                    {
                        "text": "John Doe"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "type": {"text": ["work"]}
                        }],
                        "text": "john.doe@example.com"
                    },
                    {
                        "parameters": [{
                            "type": {"text": ["home"]}
                        }],
                        "text": "john.doe@isp.net"
                    }
                ]
            }
        }
    ],
    "totalresults": 1
}

Example search strings:

Public Directory Listing

For "public" directories the valid fetchprops for users are uid, fn, n, email, kind, tel, adr, title, org, and url. For groups, the valid fetchprops are fn, email, kind, member, and org. For resource, the valid fetchprops are uid, fn, email, kind, tel, and adr. sortprop is supported for "public" address books only. The default for sortprop would be fn. The fetchcomps parameter can be set to contact, contactgroup, or resource to limit a given search to only users, groups, or resources in the directory respectively.

For public directories a searchstring or count plus startindex to do pagination must be specified because retrieving everything in a public directory without pagination might result in too much data.

The following example shows the output of a search of the default corporate directory by using various search and sort parameters:

GET /rest/directory/default/?format=json&searchstring=(starts-with(FN,%20'C'))&sortprop=fn&sortorder=descending HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx
ETag: "c180de84f991g8"

{
    "entry": [
        {
            "uri": "/rest/directory/default/uid%3Dcindy%2Cou%3DPeople%2Co%3Dexample.com%2Co%3Ddav",
            "lastmodified": "20131023T152910Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "cindy"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "pref": {"integer": "1"}
                        }],
                        "text": "cindy.smith@example.com"
                    }
                ],
                "uid": {
                    "text": "uid=cindy,ou=People,o=example.com,o=dav"
                }
            }
        },
        {
            "uri": "/rest/directory/default/uid%3Dchuck%2Cou%3DPeople%2Co%3Dexample.com%2Co%3Ddav",
            "lastmodified": "20131023T152910Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "chuck"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "pref": {"integer": "1"}
                        }],
                        "text": "chuck.miller@example.com"
                    }
                ],
                "uid": {
                    "text": "uid=chuck,ou=People,o=example.com,o=dav"
                }
            }
        }
    ],
    "totalResults": "2"
}

The following example shows the output of a search of the default corporate directory by using startindex and count parameters. Assume that the corporate directory contains users caluser1, caluser10, caluser11, and so on, through caluser19:

GET /rest/directory/default/?format=json&fetchcomps=contact&searchstring=(starts-with(FN,%20'caluser1'))&sortprop=fn&sortorder=descending&startindex=0&count=1 HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx
ETag: "c180de84f991g8"

{
    "entry": [
        {
            "uri": "/rest/directory/default/uid%3Dcaluser1%2Cou%3DPeople%2Co%3Dexample.com%2Co%3Ddav",
            "lastmodified": "20131023T152910Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "caluser1"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "pref": {"integer": "1"}
                        }],
                        "text": "caluser1@example.com"
                    }
                ],
                "uid": {
                    "text": "uid=caluser1,ou=People,o=example.com,o=dav"
                }
            }
        },
    ],
    "totalResults": "11"
}

The totalResults shows 11 matching entries (caluser1 through caluser19) even though only one entry is in the output because count is set to 1.

The following example uses a different startindex and count:

GET /rest/directory/default/?format=json&fetchcomps=contact&searchstring=(starts-with(FN,%20'caluser1'))&sortprop=fn&sortorder=descending&startindex=2&count=5 HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx
ETag: "c180de84f991g8"

{
    "entry": [
        {
            "uri": "/rest/directory/default/uid%3Dcaluser11%2Cou%3DPeople%2Co%3Dexample.com%2Co%3Ddav",
            "lastmodified": "20131023T152910Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "caluser11"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "pref": {"integer": "1"}
                        }],
                        "text": "caluser11@example.com"
                    }
                ],
                "uid": {
                    "text": "uid=caluser11,ou=People,o=example.com,o=dav"
                }
            }
        },
        {
            "uri": "/rest/directory/default/uid%3Dcaluser12%2Cou%3DPeople%2Co%3Dexample.com%2Co%3Ddav",
            "lastmodified": "20131023T152910Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "caluser12"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "pref": {"integer": "1"}
                        }],
                        "text": "caluser12@example.com"
                    }
                ],
                "uid": {
                    "text": "uid=caluser12,ou=People,o=example.com,o=dav"
                }
            }
        },
        {
            "uri": "/rest/directory/default/uid%3Dcaluser13%2Cou%3DPeople%2Co%3Dexmaple.com%2Co%3Ddav",
            "lastmodified": "20131023T152910Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "caluser13"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "pref": {"integer": "1"}
                        }],
                        "text": "caluser13@example.com"
                    }
                ],
                "uid": {
                    "text": "uid=caluser13,ou=People,o=example.com,o=dav"
                }
            }
        },
        {
            "uri": "/rest/directory/default/uid%3Dcaluser14%2Cou%3DPeople%2Co%3Dexample.com%2Co%3Ddav",
            "lastmodified": "20131023T152910Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "caluser14"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "pref": {"integer": "1"}
                        }],
                        "text": "caluser14@example.com"
                    }
                ],
                "uid": {
                    "text": "uid=caluser14,ou=People,o=example.com,o=dav"
                }
            }
        },
        {
            "uri": "/rest/directory/default/uid%3Dcaluser15%2Cou%3DPeople%2Co%3Dexample.com%2Co%3Ddav",
            "lastmodified": "20131023T152910Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "caluser15"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "pref": {"integer": "1"}
                        }],
                        "text": "caluser15@example.com"
                    }
                ],
                "uid": {
                    "text": "uid=caluser15,ou=People,o=example.com,o=dav"
                }
            }
        }
    ],
    "totalResults": "11"
}

This example starts at the third entry, which is caluser11, and ends at caluser15, for a total of 5 entries. Again, the totalResults is still 11. The following example shows what happens when the startindex is larger than the total number of matching entries:

GET /rest/directory/default/?format=json&fetchcomps=contact&searchstring=(starts-with(FN,%20'caluser1'))&sortprop=fn&sortorder=descending&startindex=100 HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx
ETag: "c180de84f991g8"

{
    "totalResults": "11"
}

There are no entries returned but the totalResults remains at 11.

The following examples use VLV browsing. The first request fetches the first five entries in the browsing index. totalResults shows the total number of entries in the browsing index, and vlvPos shows that the absolute index of the first entry in the browsing index.

GET /rest/directory/default/?format=json&fetchcomps=contact&startindex=0&count=5 HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

{
    "entry": [
        {
            "uri": "/davserver/rest/directory/default/uid%3Dtempuser%2C%20ou%3DPeople%2C%20o%3Dexample.com%2C%20o%3Ddav",
            "lastmodified": "20140507T125915Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "\"Temp User\""
                    }
                ],
                "email": [
                    {
                        "parameters": [
                            {
                                "pref": {
                                    "integer": "1"
                                }
                            }
                        ],
                        "text": "Temp.User@example.com"
                    }
                ],
                "uid": {
                    "text": "uid=tempuser, ou=People, o=example.com, o=dav"
                }
            }
        },
        {
            "uri": "/davserver/rest/directory/default/uid%3Dnabmaster%2C%20ou%3DPeople%2C%20o%3Dexample.com%2Co%3Ddav",
            "lastmodified": "20140507T125915Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "Address Book Administrator"
                    }
                ],
                "email": [
                    {
                        "parameters": [
                            {
                                "pref": {
                                    "integer": "1"
                                }
                            }
                        ],
                        "text": "nabmaster@example.com"
                    }
                ],
                "uid": {
                    "text": "uid=nabmaster, ou=People, o=example.com,o=dav"
                }
            }
        },
        {
            "uri": "/davserver/rest/directory/default/uid%3Dnab-admin.example.com-20111129212043Z%2Cou%3DPeople%2C%20o%3Dexample.com%2Co%3Ddav",
            "lastmodified": "20140507T125915Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "Address Book End User Administrator"
                    }
                ],
                "uid": {
                    "text": "uid=nab-admin.example.com-20111129212043Z,ou=People, o=example.com,o=dav"
                }
            }
        },
        {
            "uri": "/davserver/rest/directory/default/uid%3Dnab-admin.example.com-20111205200758Z%2Cou%3DPeople%2C%20o%3Dexample.com%2Co%3Ddav",
            "lastmodified": "20140507T125915Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "Address Book End User Administrator"
                    }
                ],
                "uid": {
                    "text": "uid=nab-admin.example.com-20111205200758Z,ou=People, o=example.com,o=dav"
                }
            }
        },
        {
            "uri": "/davserver/rest/directory/default/uid%3Dnab-admin.example.com-20111206194746Z%2Cou%3DPeople%2C%20o%3Dexample.com%2Co%3Ddav",
            "lastmodified": "20140507T125915Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "Address Book End User Administrator"
                    }
                ],
                "uid": {
                    "text": "uid=nab-admin.example.com-20111206194746Z,ou=People, o=example.com,o=dav"
                }
            }
        }
    ],
    "totalResults": "14052",
    "vlvPos": "0"
}

The next request is to fetch the entries that start with "an" in the browsing index. totalResults still shows the total number of entries in the browsing index, and vlvPos shows that the absolute index of the first "an" entry in the browsing index. Because five entries (count=5) were requested and there are only two entries in the result, this means all the entries that start with "an" in the entire browsing index were found.

GET /rest/directory/default/?format=json&fetchcomps=contact&startvalue=an&count=5 HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

{
    "entry": [
        {
            "uri": "/davserver/rest/directory/default/uid%3Diwc_ana%2Cou%3DPeople%2Co%3Dexample.com%2Co%3Ddav",
            "lastmodified": "20140507T125915Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "Ana Helena von Klopp"
                    }
                ],
                "email": [
                    {
                        "parameters": [
                            {
                                "pref": {
                                    "integer": "1"
                                }
                            }
                        ],
                        "text": "ana@example.com"
                    }
                ],
                "uid": {
                    "text": "uid=iwc_ana,ou=People,o=example.com,o=dav"
                }
            }
        },
        {
            "uri": "/davserver/rest/directory/default/uid%3Danilsri%2C%20ou%3DPeople%2C%20o%3Dexample.com%2C%20o%3Ddav",
            "lastmodified": "20140507T125915Z",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "anilsri"
                    }
                ],
                "email": [
                    {
                        "parameters": [
                            {
                                "pref": {
                                    "integer": "1"
                                }
                            }
                        ],
                        "text": "anil.srivastava@example.com"
                    }
                ],
                "uid": {
                    "text": "uid=anilsri, ou=People, o=example.com, o=dav"
                }
            }
        }
    ],
    "totalResults": "14052",
    "vlvPos": "60"
}

Suppose there are five entries in the previous result. That means there could be more entries that start with "an," and you could request the second page of five entries with the following request. The reason for startindex=65 is because the previous response shows vlvPos=60 plus a page size of 5. This means the next page of "an" starts at position 65. (This is just a hypothetical example because there are only two entries in the previous response.)

GET /rest/directory/default/?format=json&fetchcomps=contact&startindex=65&startvalue=an&count=5 HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Listing updated Address book Entries Only

By specifying the synctoken parameter with its value set to the last returned synctoken, clients can request servers for changed entries in a collection only. Newly added and modified entries are returned as a whole. For deleted entries, the entry URIs are returned with a statuscode property of 404.

Supported parameters: format (default: json), httpError (default: 1), fetchcomps (no default), fetchprops (default: fn, email, member, uid) and "synctoken" (must be set; if not entire contents are returned).

In the following example, a client performs a GET with a blank synctoken.

>> Request <<

GET /rest/home/arnoldj/addressbook/?synctoken= HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
{
    "syncToken":"1416523772000",
    "totalResults":"0"
}

After two new contacts have been added and one deleted subsequently, when the client does the GET with the synctoken obtained previously, it receives back a new entry and a deleted one. A new synctoken is also returned that can be used for subsequent refresh requests.

>> Request <<

GET /rest/home/arnoldj/addressbook/?synctoken=1416523772000 HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx
ETag: "c180de84f99235"

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/new",
            "type": "contact",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "uniquenew"
                },
                "fn": [
                    {
                        "text": "John Newman"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "type": {"text": ["work"]}
                        }],
                        "text": "john.newman@example.com"
                    },
                    {
                        "parameters": [{
                            "type": {"text": ["home"]}
                        }],
                        "text": "john.newman@isp.net"
                    }
                ]
            },
            "statusCode": "HTTP/1.1 200 OK"
        },
        {
            "uri": "/rest/home/arnoldj/addressbook/new2",
            "statuscode": "HTTP/1.1 404 Not Found"
        }
    ],
    "syncToken": "1416523774000"
    "totalresults": "2"
}
Exporting Address Book Entries

Export of address book entries is done the same way as listing. Additional parameters are specified to indicate the format and the language of the exported data. If multiple specific contacts where the URIs are known are to be exported, it should be done with the POST method with the multiexport action. See Exporting Multiple Contacts for more information.

The supported parameters are: format (default: json), httpError (default: 1), fetchcomps (no default), searchstring (no default), contentformat (default: vcard3), and lang (default: en). The format parameter value is used only if an error occurs. searchstring does not applies when the target URI is an individual or a group. The export functionality is not supported for use on the corporate directory.

Contacts can be exported in either vCard3 or CSV format, whereas contact groups can only be exported in vCard3 format when the target is a collection. When the target is a group, the internal members of the group are exported while the external group members are not.

>> Request <<

GET /rest/home/arnoldj/addressbook/?contentformat=csv&lang=en HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type:text/plain;charset=utf-8
Transfer-Encoding:chunked

Name,First Name,Middle Name,Last Name,Nick Name,Company,Department,Job Title,Business Street,Business City,Business State,Business Postal Code,Business Country/Region,Home Street,Home City,Home State,Home Postal Code,Home Country/Region,Business Fax,Business Phone,Home Phone,Mobile Phone,Pager,Other Phone,Anniversary,Birthday,E-mail Address,E-mail 2 Address,E-mail 3 Address,Notes,Office Location,Personal Web Page,Business Web Page,IM1,IM2,Calendar,FreeBuzy,Title,Suffix,Other Street,Other City,Other State,Other Postal Code,Other Country/Region
"Alice Thomas","","","","","","","","","","","","","","","","","","","","","","","","","","alice.thomas@example.com","","","","","","","","","","","","","","","","",""
"Cindy Smith","","","","","","","","","","","","","","","","","","","","","","","","","","cindy.smith@example.com","","","","","","","","","","","","","","","","",""
"Arnold Jones","","","","","","","","","","","","","","","","","","","","","","","","","","arnold.jones@example.com","","","","","","","","","","","","","","","","",""

Table 1 shows what is exported depending on if the request is done for an address book or an individual entry and what contentformat and fetchcomps values are used.

Table 1 Export Results

GET on ... fetchcomps contentformat Results
addressbook
Empty.
vcard3
Exports all contacts and groups.
"
"
csv
Exports all contacts. Ignores all groups.
"
contact
vcard3
Exports all contacts.
"
"
csv
Exports all contacts.
"
contactgroup
vcard3
Exports all groups.
"
"
csv
Status 400, "Export format csv is not supported for contact groups."
single contact
Empty. vcard3
Exports the contact.
"
"
csv
Exports the contact.
"
contact
vcard3
Exports the contact.
"
"
csv
Exports the contact.
"
contactgroup
vcard3
Status 400. "Resource is a contact but only contact groups were requested."
"
"
csv
Status 400, "Export format csv is not supported for contact groups."
single group
Empty. vcard3
Exports the vcard of the group.
"
"
csv
Status 400. "Resource is a contact group but fetchcomps is not set to contact as required for CSV export."
"
contact
vcard3
Exports the internal members of the group.
"
"
csv
Exports the internal members of the group.
"
contactgroup
vcard3
Exports the vcard of the group.
"
"
csv
Status 400, "Export format csv is not supported for contact groups."
Any
Any
unknown
Status 400, "Export format unknown is not supported."
Adding a Contact

To create a contact entry, a client makes an HTTP request with method POST on the targeted address book collection. The body of the HTTP POST request must contain one entry with a vcard object.

To create multiple contacts, use multiple POST commands or import. POST with multiple entries is not supported because the multiple locations cannot be returned in the location header.

If the contact contains a photo element containing inline data (that is, whose content is transmitted inline as a b64 encoded string), the photo is extracted and translated into an external link. As an alternative, the client can choose to not transmit the photo in the original POST request and instead upload the photo separately. The latter is the preferred method for adding a photo or logo and is explained later in this document.

The same command is also used to create a group. The vcard object provided in the request must be of KIND group in that case.

The supported parameters: format (default: json), httpError (default: 1), fetchprops (default: fn, email, member, uid) and fetch (default: 1).

The response code (201) indicates that the contact was successfully created. The response body contains the newly created entry unless fetch=0. The Location header contains the URI for this newly created resource.

In the following example, a contact with a name of Jacques Martin is created.

>> Request <<

POST /rest/home/arnoldj/addressbook/ HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "entry": [
        {
            "vcard": {
                "fn": [
                    {
                        "text": "Jacques Martin"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "type": {"text": ["work"]}
                        }],
                        "text": "jako@example.com"
                    }
                ]
            }
        }
    ]
}

>> Response <<

HTTP/1.1 201 Created
Location: https://example.com/rest/home/arnoldj/addressbook/3
Content-Type: application/json
Content-Length: xxxx

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/3",
            "type": "contact",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique005"
                },
                "fn": [
                    {
                        "text": "Jacques Martin"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "type": {"text": ["work"]}
                        }],
                        "text": "jako@example.com"
                    }
                ]
            }
        }
    ]
}


In the following example, a contact named Julia Martin is created and only the uid is fetched back.

>> Request <<

POST /rest/home/arnoldj/addressbook/?fetchprops=uid HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "entry": [
        {
            "vcard": {
                "fn": [
                    {
                        "text": "Julia Martin"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "type": {"text": ["work"]}
                        }],
                        "text": "julie@example.com"
                    }
                ]
            }
        }
    ]
}

>> Response <<

HTTP/1.1 201 Created
Location: https://example.com/rest/home/arnoldj/addressbook/19
Content-Type: application/json
Content-Length: xxxx

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/19",
            "type": "contact",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique019"
                }
            }
        }
    ]
}


Fetching a Contact

To fetch a particular contact, a client performs a GET on the entry URI.

The supported parameters are: format (default: json), httpError (default: 1), and fetchprops (default: fn,email, member, uid).

For the fetchprops parameter, unknown properties are just ignored. A value of X-ORCL-ALLPROPS can be used to return all available properties. For "public" directories, the valid fetchprops are uid, fn, n, email, kind, tel, adr, title, org, and url.

>> Request <<

GET /rest/home/arnoldj/addressbook/3 HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx
ETag: "c180de84f991g8"

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/3",
            "type": "contact",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique005"
                },
                "fn": [
                    {
                        "text": "Jacques Martin"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "type": {"text": ["work"]}
                        }],
                        "text": "jako@example.com"
                    }
                ]
            }
        }
    ],
    "totalresults":1
}


Modifying a Contact

To modify the properties of a contact, a client makes an HTTP request with method PUT to its entry URI. The PUT could be conditional. A conditional PUT or a PATCH is preferred to avoid clients from inadvertently overwriting changes on the server made through other clients.

The body of the HTTP PUT request must contain a valid vcard object. For adding and deleting group members, manipulate the group member properties using the same method.

For adding and modifying the photo property, see instructions in the photo/logo section.

The supported parameters are: format (default: json), httpError (default: 1), fetch (default: 1), and fetchprops (default: fn, email, member, uid). The fetchprops parameter is used only if the fetch parameter is set to 1.

In the following example, a contact with a name of Jacques Martin is modified (a phone number is added). The response code (200) indicates that the contact was successfully modified. If no fetch back is requested, the status code would be 204.

>> Request <<

PUT /rest/home/arnoldj/addressbook/3?fetch=0 HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "entry": [
        {
            "vcard": {
                "uid": {
                    "text": "unique005"
                },
                "fn": [
                    {
                        "text": "Jacques Martin"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "type": {"text": ["work"]}
                        }],
                        "text": "jako@example.com"
                    }
                ],
                "tel": [
                    {
                        "parameters": [{
                            "type": {"text": ["work", "voice"]}
                        }],
                        "text": "tel:+1-650-656-9254;ext=102"
                    }
                ]
            }
        }
    ]
}


>> Response <<

HTTP/1.1 204 No Content
Content-Length: 0

Modifying a Contact (Partial Modification, "Preferred Method")

When using HTTP PUT to modify a contact, all vCard properties must be part of the request. To modify only certain properties of a contact, a client makes an HTTP request with method PATCH to its entry URI.

The body of the HTTP PATCH request must contain at least one of two elements: one vCard object containing all the vCard properties to be added or modified and one vCard object containing all the vCard properties to be removed and an x-orcl-patch-delete property set to true. The absence of the x-orcl-patch-delete property or setting its value to false corresponds to an add or modify list. In case of single valued properties, an addition replaces the existing property. In the case of multi-valued properties, any addition is simply added on. To replace a multi-valued property, specify it with its old value in the delete object and with the new value in the add or modify object. No partial updates of properties are possible. Thus, to update a parameter of a property, give the entire property with the new parameter in the PATCH command.

The supported parameters are: format (default: json), httpError (default: 1), fetch (default: 1), fetchprops (default: fn, email, member, uid). If fetch is set to 1, the requested properties of the modified entry is returned.

The patch is applied in two steps:

  1. All properties from both the remove and add or modify lists are removed from the targetted vCard resource (assuming that they are present).
  2. Properties from the add or modify list are added back, as passed in.

Although described as a two-step process from a logical standpoint, the actual operation is atomic.

When deleting specific values of a multi-valued properties (for example, EMAIL property), the following set of rules apply when trying to find a match in the targetted vCard resource:

As a consequence, to modify the value or even a parameter value of a multi-valued property, one must add a property with the old value in the remove list and add a property with the new value (with all its parameters) in the add or modify list.

This method may be used to manipulate group entry memberships too.

In the following example, a contact with a name of Jacques Martin is first fetched, then modified (the home phone number changes, an email address type changes from work to home and a birthday is added). The response code (200 or 204) indicates that the contact was successfully modified.

>> Request <<

GET /rest/home/arnoldj/addressbook/3&fetchprops=fn,email,member,uid,tel HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx
ETag: "c180de84f991g8"

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/3",
            "type": "contact",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique005"
                },
                "fn": [
                    {
                        "text": "Jacques Martin"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                            "type": {"text": ["work"]}
                        }],
                        "text": "jako@example.com"
                    },
                    {
                        "type": [
                            "work"
                        ],
                        "text": "jacques.martin@example.com"
                    }
                ],
                "tel": [
                    {
                        "parameters": [{
                            "type": {"text": ["work", "voice"]}
                        }],
                        "text": "tel:+1-650-656-9254;ext=102"
                    }
                ]
            }
        }
    ],
    "totalresults":1
}

>> Request <<

PATCH /rest/home/arnoldj/addressbook/3?fetch=0 HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==


{
    "entry": [
        {
            "vcard": {
                "email": [
                    {
                        "parameters": [{
                            "type": {"text": ["work"]}
                        }],
                        "text": "jako@example.com"
                    }
                ],
                "tel": [
                    {
                        "parameters": [{
                            "type": {"text": ["work", "voice"]}
                        }],
                        "text": "tel:+1-510-656-9254"
                    }
                ],
                "bday": {
                    "text": "--0415"
                }
            }
        },
        {
            "vcard": {
                "x-orcl-patch-delete": "true",
                "email": [
                    {
                        "parameters": [{
                            "type": {"text": ["work"]}
                        }],
                        "text": "jako@example.com"
                    }
                ],
                "tel": [
                    {
                        "parameters": [{
                            "type": {"text": ["work", "voice"]}
                        }],
                        "text": "tel: +1-650-656-9254;ext: 102"
                    }
                ]
            }
        }
    ]
}

>> Response <<

HTTP/1.1 204 No Content
Content-Length: 0

In the following example, a group is fetched and two members are deleted from the group by using PATCH.

>> Request <<

GET /rest/home/arnoldj/addressbook/grp2&fetchprops=fn,email,member,uid,kind HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx
ETag: "c180de84f991g8"

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/grp2",
            "type": "contactgroup",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique006"
                },
                "fn": [
                    {
                        "text": "Project Group"
                    }
                ],
                "kind": {
                    "text": "group"
                },
                "member": [
                    {
                        "uri": "urn:uuid:unique000"
                    },
                    {
                        "uri": "urn:uuid:unique001"
                    },
                    {
                        "uri": "urn:uuid:unique002"
                    },
                    {
                        "uri": "urn:uuid:unique005"
                    },
                    {
                        "uri": "mailto:contractor@somewhere.com"
                    }
                ]
            }
        }
    ],
    "totalresults":1
}


>> Request <<

PATCH /rest/home/arnoldj/addressbook/grp2?fetch=0 HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "entry": [
        {
            "vcard": {
                "x-orcl-patch-delete": "true",
                "member": [
                    {
                        "uri": "urn:uuid:unique001"
                    },
                    {
                        "uri": "urn:uuid:unique002"
                    }
                ]
            }
        }
    ]
}

>> Response <<

HTTP/1.1 204 No Content
Content-Length: 0

Deleting a Contact

To delete a contact, a client sends a request with method DELETE on its entry URI. The deletion of a contact entry must result in the deletion of the associated photo resource, if it exists.

The supported parameters are: format (default: json) and httpError (default: 1). format is used in reporting any error.

Deleting a group results in deletion of group entry only and not its members.

The "pcc" entry cannot be deleted. Trying to delete the "pcc" entry should result in a "403 Forbidden" error.

Upon success, a 204 (No Content) Status code is returned. If httpError is set to 0, a response of 200 is returned with the success code in the body.

>> Request <<

DELETE /rest/home/arnoldj/Basketball League/3?format=json HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 204 No Content

Deleting Multiple Contacts

To delete multiple contacts, do a special POST on the container address book URL with action parameter value of multidelete. The entry URIs of all the contacts to be deleted are provided in the POST body. Upon successful completion, the server returns a 204, No Content status. If httpError is set to 0, a response of 200 is returned with the success code in the body. If there is a partial failure, a failure status is returned per failed entry with a HTTP overall response of 200, OK.

The supported parameters are: format (default: json) and httpError (default: 1). format is used in reporting any error.

>> Request <<

POST /rest/home/arnoldj/addressbook/?action=multidelete HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
     {
        "uri": "/rest/home/arnoldj/addressbook/grp2"
     },
     {
        "uri": "/rest/home/arnoldj/addressbook/3"
     }
 ]
}

>> Response <<

HTTP/1.1 204 No Content
Content-Length: 0

The following example shows a failure:

>> Request <<

POST /rest/home/arnoldj/addressbook/?action=multidelete HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
     {
        "uri": "/rest/home/arnoldj/addressbook/2"
     },
     {
        "uri": "/rest/home/arnoldj/addressbook/3"
     }
   ]
}

>> Response <<

HTTP/1.1 200 OK
Content-Type:application/json
Content-Length: zz

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/3",
            "statuscode": "404",
            "statusmessage": "found 0 corresponding to: (uri=/rest/home/arnoldj/addressbook/3)"
        }
    ]
}
Exporting Multiple Contacts

To export multiple contacts, do a special POST on the container address book URL with action parameter value of multiexport. The entry URIs of all the contacts to be exported are provided in the POST body. Upon successful completion, the server returns a 204, No Content status. If httpError is set to 0, a response of 200 is returned with the success code in the body. If there is a partial failure, a failure status is returned per failed entry with a HTTP overall response of 200, OK.

The supported parameters are: format (default: json), httpError (default: 1), contentformat (default: vcard3), and lang (default: en). format is used in reporting any error.

>> Request <<

POST /rest/home/arnoldj/addressbook/?format=json&action=multiexport&contentformat=vcard3 HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "addressbook": [
     {
        "uri": "/rest/home/arnoldj/addressbook/user1"
     },
     {
        "uri": "/rest/home/arnoldj/addressbook/user3"
     }
 ]
}

>> Response <<

X-Powered-By:Servlet/3.0 JSP/2.2 (Oracle GlassFish Server 3.1.2.4 Java/Oracle Corporation/1.7)
Server:Oracle GlassFish Server 3.1.2.4
Content-Disposition:attachment; filename=export.vcf
Content-Type:text/vcard;charset=UTF-8
Transfer-Encoding:chunked
Date:Fri, 29 Aug 2014 17:28:53 GMT

BEGIN:VCARD
VERSION:3.0
FN:User1 Doe
UID:user1
END:VCARD
BEGIN:VCARD
VERSION:3.0
FN:User3 Doe
UID:user3
END:VCARD

Photo/Logo Operations
Adding a Photo/Logo

To add a photo or logo property, do a POST to the contact entry URI it belongs to with the imgprop parameter value set to the property the value is intended for. Doing a POST again with a different value results in the original one being overwritten. Internally, the image at the old URI is deleted, the new one added, and the value of the PHOTO property modified to point to the new one.

The supported parameters are: format (default: json), httpError (default: 1), fetch (default: 1), and fetchprops (default: fn, email, member, uid). The fetchprops parameter is used only if the fetch parameter value is set to 1. A fetch returns the entire card entry filtered by the fetchprops setting.

The content-disposition name parameter, if you are using a file, must be name="file".

The response code (200) indicates that the contact was successfully updated. The response body contains the contact entry updated by adding the new property whose value points to where the uploaded image is stored.

An additional parameter x-orcl-uri is also emitted to provide the URI value in a relative format.

POST /rest/home/arnoldj/addressbook/3?imgprop=photo&fetchprops=fn,uid,photo HTTP/1.1
Host: example.com
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Content-Type: multipart/form-data;boundary="daboundary"
--daboundary
content-disposition: form-data; name="file"; filename="rubyHeart1.gif"
content-type: image/gif
Content-Transfer-Encoding: binary
Content-length:xxx
 /9j/4AAQSkZJRgABAQAAAQABAAD/4QBARXhpZgAATU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAA
 AAAqACAAQAAAABAAAAMKADAAQAAAABAAAAMAAAAAD/2wBDAAIBAQIBAQICAQICAgICAwUDAwMD
 AwYEBAMFBwYHBwcGBgYHCAsJBwgKCAYGCQ0JCgsLDAwMBwkNDg0MDgsMDAv/2wBDAQICAgMCAw
 UDAwULCAYICwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsL
 Cwv/wAARCAAwADADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8
--daboundary--

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/3",
            "type": "contact",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique005"
                },
                "fn": [
                    {
                        "text": "Jacques Martin"
                    }
                ],
                "photo": {
                    "x-orcl-uri": "/rest/home/arnoldj/dropbox/uniqu005/PHOTO-0123456789012-1",
                    "text": "https://example.com/dav/home/arnoldj/dropbox/unique005/PHOTO-0123456789012-1"
                }
            }
        }
    ]
}
Fetching a Photo/Logo

To fetch a photo or logo property, do a GET on the URI value specified in the corresponding property value of the contact. A fetch on the relative URL specified by the x-orcl-uri parameter also returns the photo or logo. Successful status code is 200.

Modifying a Photo/Logo

To modify, simply POST the new one to the URI value specified in the corresponding property value of the contact or to the relative URI value specified by the x-orcl-uri parameter. Doing a POST to the contact entry with the appropriate imgprop parameter also overwrites the existing one with the new one. Successful status code is 200 unless fetch is set to 0. For no fetch back it is 204. If httpError is set to 0, a response of 200 is returned with the success or failure status in the body.

The following example shows how to modify a photo by using the relative URI specified by the x-orcl-uri parameter.

>> Request <<

POST /rest/home/arnoldj/addressbook/dropbox/unique005/PHOTO-0123456789012-1?fetchprops=fn,uid,photo HTTP/1.1
Host: example.com
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Content-Type: multipart/form-data;boundary="daboundary"
--daboundary
content-disposition: form-data; name="file"; filename="rubyHeart2.tiff"
content-type: image/gif
Content-Transfer-Encoding: binary
Content-length:xxx
 /9j/4AAQSkZJRgABAQAAAQABAAD/4QBARXhpZgAATU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAA
 AAAqACAAQAAAABAAAAMKADAAQAAAABAAAAMAAAAAD/2wBDAAIBAQIBAQICAQICAgICAwUDAwMD
 AwYEBAMFBwYHBwcGBgYHCAsJBwgKCAYGCQ0JCgsLDAwMBwkNDg0MDgsMDAv/2wBDAQICAgMCAw
 UDAwULCAYICwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsL
 Cwv/wAARCAAwADADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8
--daboundary--

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/3",
            "type": "contact",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique005"
                },
                "fn": [
                    {
                        "text": "Jacques Martin"
                    }
                ],
                "photo": {
                    "x-orcl-uri": "/rest/home/arnoldj/dropbox/unique005/PHOTO-0123456789112-2",
                    "text": "https://example.com/dav/home/arnoldj/dropbox/unique005/PHOTO-0123456789112-2"
                }
            }
        }
    ]
}
Deleting a Photo/Logo

To delete a photo or logo property, modify the contact entry by removing the corresponding property from it. Doing a DELETE on the actual image URI is not supported. Trying to do so would result in a 403, Forbidden error. Successful deletion would result in status code of 200 with fetch back and 204 with no fetch back. If httpError is set to 0, a response of 200 is returned with the success or failure status in the body.

>> Request <<

PUT /rest/home/arnoldj/addressbook/3?format=json HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==


{
   "entry": [{
            "uri": "/rest/home/arnoldj/addressbook/3",
            "vcard": {
                "uid": {
                    "text": "unique005"
                },
                "fn": [
                    {
                        "text": "Jacques Martin"
                    }
                ],
            }
        }
    ]
}

>> Response <<

HTTP/1.1 204 No Content
Content-Length: 0

The following example shows a direct deletion on the image URI is not forbidden.

>> Request <<

DELETE /rest/home/arnoldj/addressbook/dropbox/unique005/PHOTO-0123456789112-2?format=json HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 403 Forbidden

Importing Contacts Into an Address Book

To import contacts into an address book, POST the contacts file contents to the address book URI.

The supported parameters are: format (default: json), httpError (default: 1), and lang (default: en). The format value is used only in case of an error. The HTTP response status is always 200 because the response body always contains the statusMessage of "\nImport succeeded for X contacts.\nImport failed for Y contacts.\n" plus statusImportCount and statusImportFailedCount. The word contacts is singular or plural depending on the X and Y values. The statusMessage can also contain information about any failures that occurred.

The server uses the first line, the header, of the content to determine the type of data being imported. The header is compared with a set of known headers and imports the data based on a match. If the type cannot be determines a status of 400 is returned.

Note
If the file being imported is in vCard format and it contains properties that Contacts Server does not understand, those properties will be imported, "as is."

The content-disposition name parameter, if you are using a file, must be name="file".

>> Request <<

POST /rest/home/arnoldj/addressbook/?format=json HTTP/1.1
Host: example.com
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Content-Type: multipart/form-data;boundary="daboundary"
--daboundary
content-disposition: form-data; name="file"; filename="file.vcf"
content-type: application/octet-stream
Content-Transfer-Encoding: binary
Content-length:xxx

First Name,Last Name,Display Name,Nickname,Primary Email,Secondary Email,Screen Name,Work Phone,Home Phone,Fax Number,Pager Number,Mobile Number,Home Address,Home Address 2,Home City,Home State,Home ZipCode,Home Country,Work Address,Work Address 2,Work City,Work State,Work ZipCode,Work Country,Job Title,Department,Organization,Web Page 1,Web Page 2,Birth Year,Birth Month,Birth Day,Custom 1,Custom 2,Custom 3,Custom 4,Notes,
Alice,Thomas,Alice Thomas,,Alice.Thomas@example.com,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
John,Silver,Long John Silver,Johnny,john.silver@gulf.com,john.silver@atlantic.com,John Silver,123-4567,123-4568,123-4569,123-1234,123-1235,101 Bay Harbor,#313,Tampa,FL,22222,USA,4000 Scaledale,#101,Tampa,FL,22222,USA,Head Fishmonger,Deep Fry,Fry'em,http://fryem.com,http://greasyfish.com,1901,01,01,,,,,,
--daboundary--

>> Response <<

HTTP/1.1 200 Ok
{
    "statusCode":"200",
    "statusMessage":"\nImport succeeded for 2 contacts.\nImport failed for 0 contacts.\n",
    "statusImportCount":"2",
    "statusImportFailedCount":"0"
}
Group Operations

A group is represented in vCard like a regular contact. The following example shows how to create a group named Project Group. The kind property must be set to the value group to create a group. Zero or more member property values can also be added.

>> Request <<

POST /rest/home/arnoldj/addressbook/?fetchprops=X-ORCL-ALLPROPS HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: xx
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

{
    "entry": [
        {
            "vcard": {
                "fn": [
                    {
                        "text": "Project Group"
                    }
                ],
                "kind": {
                    "text": "group"
                },
                "member": [
                    {
                        "uri": "urn:uuid:unique002"
                    },
                    {
                        "uri": "urn:uuid:unique005"
                    },
                    {
                        "uri": "urn:uuid:grp5"
                    },
                    {
                        "uri": "uid=johndoe,ou=People,o=example.com,o=isp"
                    },
                    {
                        "uri": "cn=staff,ou=Group,o=example.com,o=isp"
                    }
                    {
                        "uri": "mailto:contractor@somewhere.com"
                    }
                ]
            }
        }
    ]
}

>> Response <<

HTTP/1.1 201 Created
Location: https://example.com/rest/home/arnoldj/addressbook/grp2
Content-Type: application/json
Content-Length: xxxx

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/grp2",
            "type": "contactgroup",
            "lastmodified": "20130321T174833Z",
            "vcard": {
                "uid": {
                    "text": "unique006"
                },
                "fn": [
                    {
                        "text": "Project Group"
                    }
                ],
                "kind": {
                    "text": "group"
                },
                "member": [
                    {
                        "uri": "urn:uuid:unique002"
                    },
                    {
                        "uri": "urn:uuid:unique005"
                    },
                    {
                        "uri": "urn:uuid:grp5"
                    },
                    {
                        "uri": "uid=johndoe,ou=People,o=example.com,o=isp"
                    },
                    {
                        "uri": "cn=staff,ou=Group,o=example.com,o=isp"
                    }
                ]
            }
        }
    ]
}

The preceding example group shows six members with their different URIs. The first three are considered internal members where the members are actual contacts in one or more address books of the current user, just like the group itself. For Connector for Microsoft Outlook integration, having internal members from different address books is a requirement. Note that the last of the three members is a group itself, that is, a group as member of another group (nested group). This is also a requirement for Connector for Microsoft Outlook integration.

The next two members are LDAP entries that come from the corporate directory that is configured in the Contacts Server deployment. The first one is an individual, and the second one is a group. Again,this is a requirement for Connector for Microsoft Outlook integration.

To modify a group, use the PUT and PATCH method.

To get the details of the members of a group, use the fetchcomps=contact parameter on a GET request on the group URI.

>> Request <<

GET /rest/home/arnoldj/addressbook/grp2?fetchcomps=contact HTTP/1.1
Host: example.com
Content-Length: 0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

>> Response <<

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx
ETag: "c180de84f991g8"

{
    "entry": [
        {
            "uri": "/rest/home/arnoldj/addressbook/unique002.vcf",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "Jacques Martin"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                                "type": {"text": ["work"]}
                        }],
                        "text": "jako@example.com"
                    }
                ],
                "uid": {
                    "text": "urn:uuid:unique002"
                }
            }
        },
        {
            "uri": "/rest/home/arnoldj/personal/unique005.vcf",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "Jane Doe"
                    }
                ],
                "email": [
                    {
                        "parameters": [{
                                "type": {"text": ["home"]}
                        }],
                        "text": "jane.doe@gmail.com"
                    }
                ],
                "uid": {
                    "text": "urn:uuid:unique005"
                }
            }
        },
...
        {
            "uri": "/rest/directory/default/uid%3Djohndoe%2Cou%3DPeople%2Co%3Dexample.com%2Co%3Disp",
            "type": "contact",
            "vcard": {
                "fn": [
                    {
                        "text": "John Doe"
                    }
                ],
                "email": [
                    {
                        "parameters": [
                            {
                                "pref": {
                                    "integer": "1"
                                }
                            }
                        ],
                        "text": "john.doe@example.com"
                    }
                ],
                "kind": {
                    "text": "individual"
                },
                "lang": [
                    {
                        "text": "en"
                    }
                ],
                "n": [
                    {
                        "surname": [
                            "Doe"
                        ],
                        "given": [
                            "John"
                        ]
                    }
                ],
                "uid": {
                    "text": "uid=johndoe, ou=People, o=example.com, o=isp"
                }
            }
        },
...
        {
            "uri": "/rest/directory/default/cn%3Dstaff%2Cou%3DGroups%2Co%3Dexample.com%2Co%3Disp",
            "type": "contactgroup",
            "vcard": {
                "fn": [
                    {
                        "text": "staff"
                    },
                ],
                "email": [
                    {
                        "parameters": [
                            {
                                "pref": {
                                    "integer": "1"
                                }
                            }
                        ],
                        "text": "staff@example.com"
                    }
                ],
                "kind": {
                    "text": "group"
                },
                "member": [
                    {
                        "uri": "uid%3Dstaff-1%2C%20ou%3DPeople%2C%20o%3Dexample.com%2C%20o%3Disp"
                    },
                    {
                        "uri": "uid%3Dstaff-2%2C%20ou%3DPeople%2C%20o%3Dexample.com%2C%20o%3Disp"
                    },
                    {
                        "uri": "uid%3Dstaff-3%2C%20ou%3DPeople%2C%20o%3Dexample.com%2C%20o%3Disp"
                    },
                    {
                        "uri": "uid%3Dstaff-4%2C%20ou%3DPeople%2C%20o%3Dexample.com%2C%20o%3Disp"
                    },
                ],
                "uid": {
                    "text": "cn=staff,ou=Groups,o=example.com,o=isp"
                }
            }
        }
    ],
    "totalResults": "5"
}

Example

A JSON Contact Containing Most of the Properties

{
  "entry": [{
    "vcard": {
      "uid": { "text": "12" },
      "kind": {"text": "individual"},
      "fn": [{ "text": "John Doe" },
             { "text": "J. Doe, Esq"}],
      "n": [{
        "parameters": {
          "sort-as": { "text": ["Doe", "John"] }
        },
        "surname": ["Doe"],
        "given": ["J."],
        "additional": ["Jack"],
        "suffix": ["Ph.D."]
      }],
      "nickname":[{
        "parameters": {
          "type": { "text": ["work", "home"] },
          "language": { "text": "fr" },
          "pref": { "integer": "1" }
        },
        "text": ["Patron"]
      },{
        "text": ["Head Honcho"]
      }],
      "photo": [{
        "parameters": {
          "type": { "text": ["image/tiff"] }
        },
        "uri": "data:image/tiff;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4QBARXhp..." <-- NOTE: some data removed.
      }],
      "bday": [{"date-and-or-time": "10102010"}, {"date-and-or-time": "Oct. 10, 2010"}],
      "anniversary": [{"date-and-or-time": "10102010"}, {"date-and-or-time": "Oct. 10, 2010"}],
      "gender": {"sex": "M", "identity": "Fellow"},
      "adr": [{
        "parameters": {
          "type": { "text": ["work"] }
        },
        "street": ["282 Monroe Drive, Suite 101"],
        "locality": ["Mountain View"],
        "region": ["CA"],
        "code": ["94040"],
        "country": ["USA"]
      }],
      "tel": [{
        "parameters": {
          "type": {
            "text": [
              "work",
              "voice"
            ]
          },
          "pid": {
            "text": [
              "1.1", "2", "3"
            ]
          }
        },
        "text": "tel:+1-650-555-9254;ext=102"
      },
      {"text": "tel:+1-650-555-2222"}],
      "email": [{
        "parameters": {
          "type": { "text": ["work"] }
        },
        "text": "john.doe@example.com"
      },{
        "parameters": {
          "type": { "text": ["home"] }
        },
        "text": "john.doe@home.com"
      }],
      "impp": [{"uri": "im:alice@example.com"}, {"uri": "im:fred@example.com"}],
      "title": [{"text": "The boss"}, {"text": "Lead engineer"}],
      "org": [{
        "parameters": {
          "language": { "text": "en" },
          "type": { "text": ["work", "contract"]},
          "altid": { "integer": "1" }
        },
        "text":["ABC, Inc.", "North American Division", "Marketing"]
      },{
        "parameters": {
          "language": { "text": "fr" },
          "type": { "text": ["work"]},
          "altid": { "integer": "1" }
        },
        "text":["ABC, Inc.", "French Division"]
      }],
      "categories":[{
        "text":["Hobby","Fun,With,Commas"]
      }],
      "note": [{ "text": "line one.\nline two."}, {"text": "another note"}],
      "rev": {"text": "REV. 10.1"},
      "url": [{"uri": "http://www.bestrestaurants.com"}, {"uri": "http://www.worstrestaurants.com"}],
      "lang":[{
        "parameters": {
          "type": { "text": ["work"] },
          "pref": { "integer": "1" }
        },
        "text":"ja"
      },{
        "parameters": {
          "type": { "text": ["work"] },
          "pref": { "integer": "2" }
        },
        "text":"en"
      }],
      "an_unknown_prop": {
        "parameters": {
          "type": { "text": ["work"] }
        },
        "text": "Text from unknown property."
      },
      "an_unknown_prop_array": [
        {"text": "Text from unknown array 1."},
        {"text": "Text from unknown array 2."}
      ]
    }
  }]
}

Format

vCard to JSON Contacts Mapping Rules

The following rules are applied when translating a vCard text entry to vCard JSON:

  1. The root object is a vcard object within an entry object.
  2. Each vCard property is represented by an object property of the same name (lower case), except for the vCard VERSION property which is not outputted.
  3. Each vCard parameter is represented by a string property of the same name (lower case), except for the VALUE parameter which is not outputted.
  4. The value of each property is represented by a string property with the name text, except for structured properties (that is, N and ADR vCard properties).
  5. Multi-valued vCard properties or parameters that may appear more than once (as per vCard due to cardinality or presence of altid-param) are converted to array properties, regardless of whether there is more than one property in the array or not. The only expceptions are PHOTO and LOGO that are restricted to only one.
    1. Non-array valued properties are uid, rev, kind, gender, photo, and logo.
  6. Structured properties are represented by an object property containing string properties for each component (that is, for N: surname, given, additional, prefix, suffix; for ADR: pobox, ext, street, locality, region, code, country; for GENDER: sex, identity). For middlenames use the additional names field.
  7. Parameter values are represented as single string value. The only exceptions are pid, sort-as, and type. These are represented as array of strings.
  8. For each property and parameter values the vCard escaping is undone (that is, "\," is translated back to ",") and the JSON escaping is applied.
  9. Properties and parameters with empty values are dropped. This includes parts of structured values that are empty.
  10. Group construct value of properties are converted to a group parameter. For example:
    group1.FN:Jane Doe

    becomes

    "fn": [{"parameters": [{"group": {"text": "group1"}}], "text": "Jane Doe"}]
  11. vCard uses a line folding mechanism to limit lines of data to a maximum line length (typically 72 characters). Prior to converting vCard data into JSON, all folded lines must be unfolded.
  12. If a multi-valued vCard property has a pref parameter, it should be honored when returning the values in an array. Properties with no pref value set are emitted last.
  13. Unknown properties are treated as XProps and prefixed with "x-".
  14. All unknown property values including XProp values are represented as array of objects.
  15. All unknown parameters (any-param) are supported in additions to the specific ones given in the definitions.
  16. All unknown parameter values including XParam values are represented as single string values.

Example:

>>vCard entry <<

BEGIN:VCARD
VERSION:4.0
UID: unique001
FN;LANGUAGE=en:Akemi Akiko
FN;LANGUAGE=ja:????
N;LANGUAGE=ja:Akiko;Akemi;;;
EMAIL;PREF=1;TYPE=work:aa@example.com
EMAIL;TYPE=home:aa@isp.net
ADR;TYPE=home:;;282\, Monroe Dr;Mountain View;CA;94040;USA
TEL;VALUE=text;PREF=1;TYPE=voice,home:tel:+1-555-555-5555;ext=5555
END:VCARD

>> JSON translation <<

{
                "fn": [{
                        "parameters": [
                            { "language": {"text": "en"}}
                        ],
                        "text": "Akemi Akiko"
                    },
                    {
                        "parameters": [
                            { "language": {"text": "ja"}}
                        ],
                        "text": "????"
                    }
                ],
                "adr": [
                    {
                        "parameters": [
                            { "type": { "text": ["home"]}
                            }
                        ],
                        "street": [
                            "282, Monroe Dr"
                        ],
                        "locality": [
                            "Mountain View"
                        ],
                        "region": [
                            "CA"
                        ],
                        "code": [
                            "94040"
                        ],
                        "country": [
                            "USA"
                        ]
                    }
                ],
                "email": [
                    {
                        "parameters": [
                            { "pref": { "integer": "1"},
                              "type": { "text": ["work"]}
                            }
                        ],
                        "text": "aa@example.com"
                    },
                    {
                        "parameters": [
                            { "type": { "text": ["home"]}
                            }
                        ],
                        "text": "aa@isp.net"
                    }
                ],
                "n": [
                    {
                        "parameters": [
                            { "language": {"text": "ja" }}
                        ],
                    {
                        "surname": [
                            "Akiko"
                        ],
                        "given": [
                            "Akemi"
                        ]
                    }
                ],
                "tel": [
                    {
                        "parameters": [
                            {
                                "pref": { "integer": "1"},
                                "type": {"text": ["voice", "home"]}
                            }
                        ],
                        "text": "tel:+1-555-555-5555;ext=5555"
                    }
                ],
                "uid": {
                    "text": " unique001"
                }
            }

Property Definitions

This section provides detailed definitions of some properties.

Cardinality explanation:

Contacts Server RESTful value of ["the value"] indicates an array of values. So it could be something like ["value1","value2","value3"].

RESTful value of [{"text": "the value"}] indicates an array of objects like [{"text": value1}, {"text": "value2"}, {"text": "value3"}], where each object {"text":"a value"} can have multiple parameter entities associated with it. That is, {"text":"the value"} could be {"param1":"param1 val", "param2":"param2 val", "text":"the value"}

The vCard XML definitions uses the RelaxNG schema as stated in the vCard XML specification at:

http://tools.ietf.org/html/rfc6351#appendix-A

KIND Property

This property defines the type of the contact. This is used to define groups in address books. Addition of the KIND property allows or disallows inclusion of certain properties. For instance, the MEMBER property can be added only if the KIND property has also been added and the KIND property has a value set to group. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.1.4

vCard XML definition:
property-kind = element kind {element text { "individual" | "group" | "org" | "location" }*}

vCard Cardinality:
*1

NAB RESTful definition:
"kind" : {"text":"individual"} | {"text":"group"} | {"text":"org"} | {"text":"location"} | {"text":"any string value"}

NAB RESTful Cardinality:
*1

MEMBER Property

This property defines the members of a group. This property can only be used if the KIND property is also used and the KIND property value is set to group. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.6.5

vCard XML definition:
property member = element member { element parameters { param-altid, param-pid, param-pref,param-mediatype }?value-uri }

vCard Cardinality:
*

NAB RESTful definition:
"MEMBER" : [{ "parameters" [{ param-altid, param-mediatype, param-pid, param-pref}], {"uri" : "urivalue"}}]

NAB RESTful Cardinality:
*1

FN Property

The FN property displays the name of the contact. This property must be present. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.2.1

vCard XML definition:
property-fn = element fn { element parameters { param-language, param-altid, param-pid, param-pref, param-type }?, value-text }

vCard Cardinality:
1*

Contacts Server RESTful definition:
"fn" : ["parameters" [{ param-altid, param-type, param-language, param-pid, param-pref}], {"text": "the value"}]

Contacts Server RESTful Cardinality:
1*

N Property

The N property specifies the complete name. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.2.2

vCard XML definition:
property-n = element n { element parameters { param-language, param-sort-as, param-altid }?, element surname { value-text-list? },
element given { value-text-list? }, element additional { value-text-list? }, element prefix { value-text-list? },
element suffix { value-text-list? } }

vCard Cardinality:
*1 (each subcomponent is multivalued)

Contacts Server RESTful definition:
"n": ["parameters" [{ param-altid, param-language, param-sort-as}], {"surname":["the value"], "given":["the value"], "additional":["the value"], "prefix":["the value"], "suffix": ["the value"]}]
NOTE: Only one single value is supported for the ["the value"] array.
      Also, only one item of each type, e.g. "surname", "given", etc. is allowed in the property. If more than
      one of a type is given, only the last one will be used.

Contacts Server RESTful Cardinality:
*1

NICKNAME Property

This property specifies the nicknames of the contact. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.2.3

vCard XML definition:
property-nickname = element nickname { element parameters { param-language, param-altid, param-pid, param-pref, param-type }?, value-text-list }

vCard Cardinality:
*

Contacts Server RESTful definition:
nickname:["parameters" [{ param-altid, param-language, param-pid, param-pref, param-type}], {"text": ["the value"]}]

Contacts Server RESTful Cardinality:
*

PHOTO Property

This property specifies the photo of the contact. Though vCard standards allow multiple PHOTO properties per contact, Contacts Server allows only one. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.2.4

vCard XML definition:
property-photo = element photo { element parameters { param-altid, param-pid, param-pref, param-type, param-mediatype }?, value-uri }

vCard Cardinality:
* (But server supports only 1)

Contacts Server RESTful definition:
"photo":["parameters" [{ param-altid, param-mediatype, param-pid, param-pref, param-type}], {"uri" : "urivalue"}]
NOTE: Only one single value is supported in the array.
NAB RESTful Cardinality:
*1

BDAY Property

This property specifies the birthday of the contact. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.2.5

vCard XML definition:
property-bday = element bday { element parameters { param-altid, param-calscale }?, (value-date-and-or-time | value-text) } Use of "--"
instead of year when year is private or not available.

vCard Cardinality:
*1

Contacts Server RESTful definition:
"bday": ["parameters": [{param-altid, param-calscale}], {"date-and-or-time": "the value"}]

Contacts Server RESTful Cardinality:
*1

ANNIVERSARY Property

This property specifies the date of marriage or equivalent. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.2.6

vCard XML definition:
property-anniversary = element anniversary { element parameters { param-altid, param-calscale }?, (value-date-and-or-time | value-text) } Use
of "--" instead of year when year is private or not available.

vCard Cardinality:
*1

Contacts Server RESTful definition:
"anniversary": ["parameters" [{ param-altid, param-calscale}], {"date-and-or-time": "the value"}]

Contacts Server RESTful Cardinality:
*1

GENDER Property

This property specifies sex and gender identity information. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.2.7

vCard XML definition:
property-gender = element gender { element sex { element text { "M" | "F" | "O" | "N" | "U" }? }, element identity { value-text-list? } }

vCard Cardinality:
*1

Contacts Server RESTful definition:
"gender": {"sex":"M", "identity":"a value"} | {"sex":"F", "identity":"a value"} | {"sex":"O", "identity":"a value"} | {"sex":"N", "identity":"a value"} | {"sex":"U", "identity":"a value"}

Contacts Server RESTful Cardinality:
*1

ADR Property

This property specifies the delivery address of the contact. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.3.1

vCard XML definition:
property-adr = element adr { element parameters { param-language, param-altid, param-pid, param-pref, param-type, param-geo, param-tz,
     param-label }?, element pobox { value-text-list? }, element ext { value-text-list? }, element street { value-text-list? },
element locality { value-text-list? },&nbsp;element region { value-text-list? }, element code { value-text-list? },
element country { value-text-list? } }

vCard Cardinality:
*

Contacts Server RESTful definition:
"adr": ["parameters" [{ param-altid, param-geo, param-label, param-language, param-pid, param-pref, param-type, param-tz}], {"pobox":["a value"], "ext": ["a value"], "street": ["a value"], "locality": ["a value"], "region": ["a value"], "code": ["a value"], "country": ["a value"]}]
NOTE: Only one single value is supported for the ["a value"] array.
      Also, only one item of each type, e.g. "pobox", "ext", etc. is allowed in the property. If more than
      one of a type is given, only the last one will be used.

Contacts Server RESTful Cardinality:
*

TEL Property

This property specifies telephone numbers. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.4.1

vCard XML definition:
property-tel = element tel { element parameters { param-altid,param-pid,param-pref, element type
{ "work" | "home" | "text" |
    "voice" | "fax" | "cell" | "video" | "pager" | "textphone" }+ " macrohasbody="false" wikihasprecedingnewline="false" wikihastrailingnewline="false" >{ element text { "work" | "home" | "text" |
    "voice" | "fax" | "cell" | "video" | "pager" | "textphone" }+ }
?, param-mediatype }?, (value-text | value-uri) }

vCard Cardinality:
*

Contacts Server RESTful definition:
"tel": ["parameters" [{ param-altid, param-mediatype, param-pid, param-pref, param-type {"text": { ["work" | "home" | "text" | "voice" | "fax" | "cell" | "video" | "pager" | "textphone" }+ }}], {"text": "value"}]
One or more type params may be part of the value most of the time.

Contacts Server RESTful Cardinality:
*

EMAIL Property

This property specifies email addresses of the contact. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.4.2

vCard XML definition:
property-email = element email { element parameters { param-altid, param-pid, param-pref, param-type }
?, value-text }

vCard Cardinality:
*

Contacts Server RESTful definition:
"email":["parameters" [{ param-altid, param-pid, param-pref, param-type}], {"text":"a value"}]

Contacts Server RESTful Cardinality:
*

IMPP Property

This property specifies instant messaging addresses. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.4.3

vCard XML definition:
property-impp = element impp { element parameters { param-altid, param-pid, param-pref, param-type, param-mediatype }
?, value-uri }

vCard Cardinality:
*

Contacts Server RESTful definition:
"impp":["parameters" [{ param-altid, param-mediatype, param-pid, param-pref, param-type}], {"uri": "a value"}]

Contacts RESTful Cardinality:
*

LANG Property

This property specifies the language(s) that may be used for contacting the entity associated with the vCard.

http://tools.ietf.org/html/rfc6350#section-6.4.4

vCard XML definition:
lang = element lang { element parameters { param-pid, param-altid, param-pref, param-type }
?, value-text }

vCard Cardinality:
*

Contacts Server RESTful definition:
"lang":["parameters" [{ param-altid, param-pid, param-pref, param-type}], {"text": "a value"}]

Contacts Server RESTful Cardinality:
*

TITLE Property

This property specifies a job position or equivalent. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.6.1

vCard XML definition:
property-title = element title { element parameters { param-language, param-altid, param-pid, param-pref, param-type }?, value-text }

vCard Cardinality:
*

Contacts Server RESTful definition:
"title": ["parameters" [{ param-altid, param-language, param-pid, param-pref, param-type}], {"text": "a value"}]

Contacts Server RESTful Cardinality:
*

Note: The PortableContacts organizations object has many more field than what is listed here.

ORG Property

This property specifies the organizational name. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.6.4

vCard XML definition:
property-org = element org { element parameters { param-language, param-altid, param-pid, param-pref, param-type, param-sort-as }?,
value-text-list }

vCard Cardinality:
*

Contacts Server RESTful definition:
"org":["parameters" [{ param-altid, param-language, param-pid, param-pref, param-sort-as, param-type}], {"text": ["value"]}]
Where the "value" array contains one or more values with the first one treated as the Organization's name and the rest are Organizational units.

Contacts Server RESTful Cardinality:
*

CATEGORIES Property

This property specifies tags to a contact. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.7.1

vCard XML definition:
property-categories = element categories { element parameters { param-altid, param-pid, param-pref, param-type }?, value-text-list }

vCard Cardinality:
*

Contacts Server RESTful definition:
"categories": ["parameters" [{ param-altid, param-pid, param-pref, param-type}], {"text": "a value"}]

Contacts Server RESTful Cardinality:
*

NOTE Property

This property specifies any supplemental information on the contact including descriptions, comments, and so on. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.7.2

vCard XML definition:
property-note = element note { element parameters { param-language, param-altid, param-pid, param-pref, param-type }?, value-text }

vCard Cardinality:
*

Contacts Server RESTful definition:
"note":["parameters" [{ param-altid, param-language, param-pid, param-pref, param-type}], {"text": "a value"}]

Contacts Server RESTful Cardinality:
*

REV Property

This property specifies the timestamp of current revision of the entry. Its value corresponds to the "lastmodified" timestamp on the contact. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.7.4

vCard XML definition:
property-rev = element rev { value-timestamp }

vCard Cardinality:
*1

Contacts Server RESTful definition:
"rev": {"text": "a value"}

Contacts Server RESTful Cardinality:
*1

UID Property

This property specifies the unique identifier for the entry. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.7.6

vCard XML definition:
property-uid = element uid { value-uri }

vCard Cardinality:
1 (actually vCard says *1 but CardDAV makes it mandatory).

Contacts Server RESTful definition:
"uid": {"text": "a value"}

Contacts Server RESTful Cardinality:
1

URL Property

This property specifies URLs associated with this entry. For more information, see the topic at:

http://tools.ietf.org/html/rfc6350#section-6.7.8

vCard XML definition:
property-url = element url { element parameters { param-altid, param-pid,param-pref, param-type, param-mediatype }?, value-uri }

vCard Cardinality:
*

Contacts Server RESTful definition:
"url":["parameters" [{ param-altid, param-pid, param-pref, param-type, param-mediatype}], {"uri": "uri value"}]

Contacts Server RESTful Cardinality:
*

The vCard XML definition mandates a URI but not the vCard one. So neither does RESTful.

Other Properties

Most other properties are converted similar to the ones previously mentioned. They use "lowercased" name for property name and array of string or URI value objects for value. No array is used if only one value is possible. The cardinality is maintained as in vCard as much as possible.

The LOGO property is treated exactly like the PHOTO property with the ability to retrieve the relative URI and support for only one per contact.

The vCard VERSION property is not emitted.


Oracle
Copyright © 2011, 2016, Oracle and/or its affiliates. 
Legal Notices