---
title: HDAP API reference
description: HDAP APIs offer HTTP access to directory data as JSON resources. DS software maps JSON resources to LDAP entries.
component: pingds
version: 8.1
page_id: pingds:rest-guide:rest-operations
canonical_url: https://docs.pingidentity.com/pingds/8.1/rest-guide/rest-operations.html
revdate: 2025-10-22T14:42:39Z
keywords: ["REST API"]
section_ids:
  authenticate-rest: Authentication
  authenticate-rest-anon: Anonymous
  authenticate-rest-basic: Basic auth
  authenticate-rest-bearer: Bearer auth
  resources: Resources
  fields: Fields
  values: Values
  hdap-schema: Schema
  operations: Operations
  create: Create
  read: Read
  update: Update
  delete: Delete
  patch: Patch
  patch-add: Add
  patch-remove: Remove
  patch-replace: Replace
  patch-increment: Increment
  action: Action
  query: Query
  headers: Headers
  accept_api_version: Accept-API-Version
  x_forgerock_transactionid: X-ForgeRock-TransactionId
  query-parameters: Query parameters
  filter-expressions: Filter expressions
  http-status-codes: HTTP status codes
---

# HDAP API reference

HDAP APIs offer HTTP access to directory data as [JSON](https://json.org) resources. DS software maps JSON resources to LDAP entries.

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Examples in this documentation depend on features activated in [the `ds-evaluation` setup profile](../install-guide/setup-ds.html#about-ds-evaluation).The code samples demonstrate how to contact the server over HTTPS using the deployment CA certificate. Before trying the samples, generate the CA certificate in PEM format from the server deployment ID and password:```console
$ dskeymgr \
 export-ca-cert \
 --deploymentId $DEPLOYMENT_ID \
 --deploymentIdPassword password \
 --outputFile ca-cert.pem
``` |

## Authentication

### Anonymous

When you perform an operation without authenticating, HDAP responds like LDAP:

* If DS access control lets anonymous users perform the operation, the operation returns the expected result.

  The `ds-evaluation` profile lets anonymous users read and search many attributes.

* If anonymous users can't perform the operation, HDAP returns HTTP 401 Unauthorized.

  HTTP status code 401 means the user must authenticate.

- Curl

- JavaScript

- Python

- Ruby

```console
$ curl \
 --cacert ca-cert.pem \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=bjensen'
```

```javascript
const { doRequest, getOptions } = require('./utils')

const options = getOptions({
    path: '/hdap/dc=com/dc=example/ou=People/uid=bjensen',
    headers: { 'Content-Type': 'application/json' }
})

doRequest('HDAP: anonymous read', options)
    .then(response => { console.log(response) })
    .catch(error => { console.error(error) })
```

Source files for this sample: [anonymous-read.js](../_attachments/hdap/js/anonymous-read.js), [utils.js](../_attachments/hdap/js/utils.js)

```python
#!/usr/bin/env python3

import requests
import utils

response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People/uid=bjensen',
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))
```

Source files for this sample: [utils.py](../_attachments/hdap/py/utils.py), [anonymous-read.py](../_attachments/hdap/py/anonymous-read.py)

```ruby
require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('', '')
options = { ca_file: utils.ca_pem }
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
end
response = hdap.get('dc=com/dc=example/ou=People/uid=bjensen')

puts "Status code: #{response.status}\nJSON: #{response.body}"
```

Source files for this sample: [utils.rb](../_attachments/hdap/rb/utils.rb), [anonymous-read.rb](../_attachments/hdap/rb/anonymous-read.rb)

HDAP Ruby examples require Ruby 3.2 and the `faraday` and `json` gems.

### Basic auth

HDAP supports [HTTP Basic authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#basic_authentication_scheme) with the `_id` of resource as the HTTP username. The `_id` matches the suffix of the path to the resource.

When you set up DS with the `ds-evaluation` profile, Babs Jensen's `_id` is `dc=com/dc=example/ou=People/uid=bjensen`.

Use HTTPS to avoid sending the password over an insecure connection.

* Curl

* JavaScript

* Python

* Ruby

HTTP Basic authentication

```console
$ curl \
 --user dc=com/dc=example/ou=People/uid=bjensen:hifalutin \
 --cacert ca-cert.pem \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=bjensen?_fields=cn'
```

> **Collapse: Show output**
>
> ```
> {"_id":"dc=com/dc=example/ou=People/uid=bjensen","_rev":"<revision>","cn":["Barbara Jensen","Babs Jensen"]}
> ```

HTTP Basic with credentials in the URL

```console
$ curl \
 --cacert ca-cert.pem \
 'https://dc=com%2Fdc=example%2Fou=People%2Fuid=bjensen:hifalutin@localhost:8443/hdap/dc=com/dc=example/ou=People/uid=bjensen?_fields=cn'
```

> **Collapse: Show output**
>
> ```
> {"_id":"dc=com/dc=example/ou=People/uid=bjensen","_rev":"<revision>","cn":["Barbara Jensen","Babs Jensen"]}
> ```

```javascript
const { doRequest, getOptions } = require('./utils')

const options = getOptions({
    path: '/hdap/dc=com/dc=example/ou=People/uid=bjensen?_fields=cn',
    credentials: 'dc=com/dc=example/ou=People/uid=bjensen:hifalutin'
})

doRequest('HDAP: Basic auth', options)
    .then(response => { console.log(response) })
    .catch(error => { console.error(error) })
```

Source files for this sample: [basic-auth.js](../_attachments/hdap/js/basic-auth.js), [utils.js](../_attachments/hdap/js/utils.js)

```python
#!/usr/bin/env python3

import requests
from requests.auth import HTTPBasicAuth
import utils

response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People/uid=bjensen',
    auth=HTTPBasicAuth('dc=com/dc=example/ou=People/uid=bjensen', 'hifalutin'),
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))
```

Source files for this sample: [utils.py](../_attachments/hdap/py/utils.py), [basic-auth.py](../_attachments/hdap/py/basic-auth.py)

```ruby
require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('', '')
options = { ca_file: utils.ca_pem }
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: { '_fields': 'cn' }, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, :basic, 'dc=com/dc=example/ou=People/uid=bjensen', 'hifalutin'
end
response = hdap.get('dc=com/dc=example/ou=People/uid=bjensen')

puts "Status code: #{response.status}\nJSON: #{response.body}"
```

Source files for this sample: [utils.rb](../_attachments/hdap/rb/utils.rb), [basic-auth.rb](../_attachments/hdap/rb/basic-auth.rb)

HDAP Ruby examples require Ruby 3.2 and the `faraday` and `json` gems.

### Bearer auth

HDAP supports HTTP Bearer authorization using an access token. The access token is a JSON Web Token (JWT) DS returns for a successful authentication action.

|   |                                                                                                                                                                                                                                                                                                                                                                                      |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|   | Using a JWT bearer token for authorization means DS only has to authenticate the user once during the lifetime of the token.Use this when performing multiple operations as a user with a strong password storage scheme. The computational cost to validate the password is high, but you only pay the cost once. The cost to validate a JWT token is low for each later operation. |

Use HTTPS POST to the path for the account to authenticate with `_action=authenticate` in the query string and a JSON object `{ "password": "<password>" }` as the request payload.

On success, the HTTP status code is 200 OK, and the response body is a JSON resource with an `access_token`. Use the bearer token to authorize later HTTP requests.

* Curl

* JavaScript

* Python

* Ruby

```console
$ curl \
 --request POST \
 --header 'Content-Type: application/json' \
 --data '{ "password": "hifalutin" }' \
 --cacert ca-cert.pem \
 'https://localhost:8443/hdap/dc=com/dc=example/ou=People/uid=bjensen?_action=authenticate'
```

> **Collapse: Show output**
>
> ```
> {"access_token":"<jwt>","expires_in":"299","token_type":"Bearer"}
> ```

```javascript
(async () => {
    const { authenticate, doRequest, getOptions } = require('./utils')
    const resource = '/hdap/dc=com/dc=example/ou=People/uid=bjensen'
    const options = getOptions({ path: resource })
    const jwt = await authenticate(options)
    options.headers['Authorization'] = 'Bearer ' + jwt
    const response = await doRequest('HDAP: JWT auth', options)
    console.log(response)
})().catch(error => { console.error(error) })
```

Source files for this sample: [basic-auth.js](../_attachments/hdap/js/bearer-auth.js), [utils.js](../_attachments/hdap/js/utils.js)

```python
#!/usr/bin/env python3

import requests
import utils

jwt = utils.authenticate('dc=com/dc=example/ou=People/uid=bjensen', 'hifalutin')
headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer {jwt}' }
response = requests.get(
    f'https://{utils.host}:{utils.port}/hdap/dc=com/dc=example/ou=People/uid=bjensen',
    headers=headers,
    verify=utils.ca_pem)
print('Status code: %d\nJSON: %s' % (response.status_code, response.json()))
```

Source files for this sample: [utils.py](../_attachments/hdap/py/utils.py), [basic-auth.py](../_attachments/hdap/py/bearer-auth.py)

```ruby
require_relative 'utils.rb'
require 'faraday'

utils = Utils.new('dc=com/dc=example/ou=People/uid=bjensen', 'hifalutin')
options = { ca_file: utils.ca_pem }
jwt = utils.authenticate
hdap = Faraday.new(url: "https://#{utils.host}:#{utils.port}/hdap/", params: { '_fields': 'cn' }, ssl: options) do |f|
    f.headers['Content-Type'] = 'application/json'
    f.request :authorization, 'Bearer', jwt
end
response = hdap.get('dc=com/dc=example/ou=People/uid=bjensen')

puts "Status code: #{response.status}\nJSON: #{response.body}"
```

Source files for this sample: [utils.rb](../_attachments/hdap/rb/utils.rb), [basic-auth.rb](../_attachments/hdap/rb/bearer-auth.rb)

HDAP Ruby examples require Ruby 3.2 and the `faraday` and `json` gems.

Learn about alternative authentication options:

* [Configure HTTP authorization](../config-guide/http-access.html#setup-http-authorization)

* [Identity mappers](../ldap-guide/client-auth.html#client-auth-identity-mappers)

## Resources

HDAP resources are JSON objects whose top-level elements are fields with string identifiers; for example:

```json
{
  "_id" : "dc=com/dc=example/ou=People/uid=user.0",
  "_rev" : "0d3ce3bf-4107-3b34-9e5a-fa71deb8b504",
  "objectClass" : [ "top", "person", "organizationalPerson", "inetOrgPerson" ],
  "cn" : [ "Aaccf Amar" ],
  "description" : [ "This is the description for Aaccf Amar." ],
  "employeeNumber" : "0",
  "givenName" : [ "Aaccf" ],
  "homePhone" : [ "+1 720 204 9090" ],
  "initials" : [ "AAA" ],
  "l" : [ "Harrisonburg" ],
  "mail" : [ "user.0@example.com" ],
  "mobile" : [ "+1 412 030 0042" ],
  "pager" : [ "+1 439 180 6470" ],
  "postalAddress" : [ "Aaccf Amar$31206 Spring Street$Harrisonburg, IL  04284" ],
  "postalCode" : [ "04284" ],
  "sn" : [ "Amar" ],
  "st" : [ "IL" ],
  "street" : [ "31206 Spring Street" ],
  "telephoneNumber" : [ "+1 485 381 2060" ],
  "uid" : [ "user.0" ]
}
```

HDAP resources have the following special fields:

* `_id`

  Unique identifier.

  The resource `_id` matches the trailing components of its path. For example, the resource at `/hdap/dc=com/dc=example/ou=People/uid=bjensen` has `"_id":"dc=com/dc=example/ou=People/uid=bjensen"`.

  The path elements of an `_id` are URL path-encoded RDN strings. When you create a resource:

  * Percent-encode each path element.

  * If the path element includes characters to escape in LDAP, `" # + , ; < = > \`, escape those characters in the LDAP RDN string before percent-encoding the result for HDAP.

  | CN value      | LDAP RDN           | HDAP path element     |
  | ------------- | ------------------ | --------------------- |
  | `Babs Jensen` | `cn=Babs Jensen`   | `cn=Babs%20Jensen`    |
  | `Babs/Jensen` | `cn=Babs/Jensen`   | `cn=Babs%2FJensen`    |
  | `Babs\Jensen` | `cn=Babs\\Jensen`  | `cn=Babs%5C%5CJensen` |
  | `Babs,Jensen` | `cn=Babs\2CJensen` | `cn=Babs%5C2Jensen`   |

* `_rev`

  The resource revision.

  HDAP versions individual resources with revision numbers corresponding to the LDAP `ETag` operational attribute. HDAP uses the `If-Match: <revision>` header to determine whether to apply changes to a resource.

The other JSON fields have the same names as the LDAP attributes they represent.

### Fields

Multivalued LDAP attributes correspond to arrays in JSON. Unlike arrays in JavaScript, these arrays have set semantics. No duplicates are allowed and the element order is arbitrary.

By default, HDAP behaves like a normal LDAP client application, returning JSON fields for all non-empty LDAP user attributes.

* To return JSON fields for operational LDAP attributes, request them specifically with the `_fields` parameter.

  Use `+`, which encodes to `%2B`, to return fields for all operational attributes.

* To return empty fields, set the advanced HDAP endpoint configuration property `return-null-for-missing-properties:true`.

  With the feature enabled, HDAP returns empty single-valued fields as `null` and empty multivalued fields as `[]`, except for password fields, which HDAP returns as an array even if they are constrained to being single-valued.

  access control instruction (ACI) *(tooltip: \<div class="paragraph">
  \<p>An instruction or rule that can be used to grant or deny access to users to perform operations on a server.\</p>
  \</div>)* `deny` rules can cause misleading results, where an "empty" attribute exists, but you can't read it. Check the applicable ACIs when HDAP doesn't return an expected field.

* To return field names as specified with the `_fields` query parameter or as stored in the LDAP entry, set the HDAP endpoint configuration property `normalize-attribute-names:false`.

  By default, HDAP returns resources with normalized field names.

### Values

HDAP derives its resource field values from LDAP attribute values based on the attribute syntax.

| LDAP attribute type   | LDAP example                                                                                                           | JSON field type                                                                                                  | JSON example                                                                                                                 |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| ACI                   | `(targetattr="userPassword")(version 3.0; acl "Read own password";allow (read,search,compare) userdn="ldap:///self";)` | ACI string[1](#hdap-values-footnote-strings)                                                                     | `(targetattr=\"userPassword\")(version 3.0; acl \"Read own password\";allow (read,search,compare) userdn=\"ldap:///self\";)` |
| Binary                | A binary photo or a certificate                                                                                        | Base64-encoded string                                                                                            | A base64-encoded photo or certificate                                                                                        |
| Boolean               | `true`                                                                                                                 | Boolean                                                                                                          | `true`                                                                                                                       |
| DN                    | `uid=bjensen,ou=People,dc=example,dc=com`                                                                              | `_id` string                                                                                                     | `dc=com/dc=example/ou=People/uid=bjensen`                                                                                    |
| JSON                  | `{"array":[{"x":1,"y":2},{"x":3,"y":4}]}`                                                                              | JSON                                                                                                             | `{"array":[{"x":1,"y":2},{"x":3,"y":4}]}`                                                                                    |
| Number                | `42`                                                                                                                   | Number                                                                                                           | `42`                                                                                                                         |
| Password              | A password hash                                                                                                        | Password string                                                                                                  | The same password hash                                                                                                       |
| Postal address        | `1234 Main St.$Anytown, CA 12345$USA`                                                                                  | Array of strings[1](#hdap-values-footnote-strings)                                                               | `["1234 Main St.","Anytown, CA 12345","USA"]`                                                                                |
| String                | `Hello world!`                                                                                                         | String[1](#hdap-values-footnote-strings)                                                                         | `Hello world!`                                                                                                               |
| Subtree specification | `{ base "ou=people", specificationFilter "(uid=bjensen)" }`                                                            | Subtree specification object[1](#hdap-values-footnote-strings),[2](#hdap-values-footnote-subtree-specifications) | `{ "base": "ou=people", "filter": "uid eq \"bjensen\"" }`                                                                    |
| Telephone number      | `+1 408 555 1212`                                                                                                      | Telephone number string                                                                                          | `+1 408 555 1212`                                                                                                            |
| Time                  | `20230622065924Z`                                                                                                      | ISO 8601 string                                                                                                  | `2023-06-22T06:59:24Z`                                                                                                       |
| UUID                  | `597ae2f6-16a6-1027-98f4-d28b5365dc14`                                                                                 | UUID string                                                                                                      | `597ae2f6-16a6-1027-98f4-d28b5365dc14`                                                                                       |

1 JSON strings are enclosed in double quotes, so double quotes are escaped with a backslash `\"`.

2 DS supports more subtree specification features than demonstrated in this simple example. For complex subtree specifications, add an example from LDIF, read the resource, and review the resulting JSON.

### Schema

HDAP provides two ways to read [JSON schema](https://json-schema.org/) for resources:

* Read the schema for an existing resource or a resource to create with [the `schema` action](action-rest.html#action-schema).

* Read the schema for an individual field or object class directly.

  The fields map to LDAP attribute types. A resource's `objectClass` values map to LDAP object classes.

  | To read the schema for | Use                                                                                                                                              |
  | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
  | An individual field.   | HTTP GET on `schemas/attributeTypes/type`:```http
  GET /hdap/schemas/attributeTypes/cn HTTP/1.1
  Host: example.com
  Accept: application/json
  ```    |
  | An object class.       | HTTP GET on `schemas/objectClasses/class`:```http
  GET /hdap/schemas/objectClasses/person HTTP/1.1
  Host: example.com
  Accept: application/json
  ``` |

## Operations

HDAP APIs support the following operations:

| HDAP operation    | Description                             | HTTP method |
| ----------------- | --------------------------------------- | ----------- |
| [Create](#create) | Add a new resource                      | PUT or POST |
| [Read](#read)     | Retrieve a single resource              | GET         |
| [Update](#update) | Replace content in an existing resource | PUT         |
| [Delete](#delete) | Remove an existing resource             | DELETE      |
| [Patch](#patch)   | Modify an existing resource             | PATCH       |
| [Action](#action) | Perform a predefined action             | POST        |
| [Query](#query)   | List resources                          | GET         |

### Create

Use either HTTP POST or HTTP PUT.

Use HTTP POST with the query string parameter `_action=create` and the JSON resource as a payload. Accept a JSON response. HDAP builds the `_id` using the parent resource path and the field in the resource corresponding to the LDAP RDN:

```http
POST /hdap/dc=com/dc=example/ou=People?_action=create HTTP/1.1
Host: example.com
Accept: application/json
Content-Length: ...
Content-Type: application/json
{ JSON resource }
```

Use HTTP PUT with the `_id` in the resource and the URL path. Use the `If-None-Match: *` header. Accept a JSON response:

```http
PUT /hdap/dc=com/dc=example/ou=People/uid=newuser HTTP/1.1
Host: example.com
Accept: application/json
Content-Length: ...
Content-Type: application/json
If-None-Match: *
{ JSON resource }
```

The response indicates the resource location in the `Location` header.

* If you include the `If-None-Match` header, you must use `If-None-Match: *`.

  The request creates the object if it does not exist. It fails if the object does exist.

  If you include any value other `If-None-Match: *`, HDAP returns an HTTP 400 Bad Request error. For example, creating an object with `If-None-Match: revision` returns a bad request error.

* If you do not include `If-None-Match: *`, the request creates the object if it does not exist and *updates* the object if it does exist.

Supported [parameters](#query-parameters):

* `_action=create`

* `dryRun=true`

* `_fields`

* `manageDsaIT=true`

* `passwordQualityAdvice=true`

* `_prettyPrint=true`

* `relax=true`

Learn more in [Create](create-rest.html).

### Read

Read a resource with HTTP GET and accept a JSON response:

```http
GET /hdap/dc=com/dc=example/ou=People/uid=newuser HTTP/1.1
Host: example.com
Accept: application/json
```

Supported [parameters](#query-parameters):

* `_fields`

* `manageDsaIT=true`

* `_prettyPrint=true`

Learn more in [Read](read-rest.html).

### Update

Update a resource with HTTP PUT and the JSON resource as the payload. Accept a JSON response.

* Unlike other Common REST applications, HDAP does not require the full JSON resource.

  HDAP replaces the fields in the resource with the fields in the payload, operating like a patch [Replace](#patch-replace). Other fields retain their existing values.

* Use the `If-Match: _rev` header to update the resource only if the revision matches.

  Use `If-Match: *` to apply the update irrespective of the revision.

```http
PUT /hdap/dc=com/dc=example/ou=People/uid=newuser HTTP/1.1
Host: example.com
Accept: application/json
Content-Length: ...
Content-Type: application/json
If-Match: _rev
{ JSON resource }
```

Supported [parameters](#query-parameters):

* `dryRun=true`

* `_fields`

* `manageDsaIT=true`

* `passwordQualityAdvice=true`

* `_prettyPrint=true`

* `relax=true`

Learn more in [Update](update-rest.html).

### Delete

Use HTTP DELETE and accept a JSON response:

```http
DELETE /hdap/dc=com/dc=example/ou=People/uid=newuser HTTP/1.1
Host: example.com
Accept: application/json
```

Supported [parameters](#query-parameters):

* `dryRun=true`

* `_fields`

* `manageDsaIT=true`

* `_prettyPrint=true`

* `subtreeDelete=true`

Learn more in [Delete](delete-rest.html).

### Patch

Use HTTP PATCH request with a JSON array of patch objects appropriate to the operation. Each patch object in the payload can have these fields:

* `operation`

  HDAP supports these patch operations:

  * [`add`](#patch-add)

  * [`remove`](#patch-remove)

  * [`replace`](#patch-replace)

  * [`increment`](#patch-increment)

HDAP does not support the common REST `copy`, `move`, or `transform` operations.

* `field`

  A JSON pointer to the target field

* `value`

  The value for the patch

The patch request has the following format:

```http
PATCH /hdap/dc=com/dc=example/ou=People/uid=newuser HTTP/1.1
Host: example.com
Accept: application/json
Content-Length: ...
Content-Type: application/json
If-Match: _rev
[ JSON array of patch operations ]
```

Patch operations apply to these types of target fields:

* **Single-valued**, such as an object, string, boolean, or number.

* **Set semantics array**, where the elements are not ordered and duplicates are not allowed.

  If you reference array values by index, HDAP returns an error.

Supported [parameters](#query-parameters):

* `dryRun=true`

* `_fields`

* `manageDsaIT=true`

* `passwordQualityAdvice=true`

* `_prettyPrint=true`

* `relax=true`

Learn more in [Patch](patch-rest.html).

#### Add

Patch `add` ensures the target field contains the value provided, creating parent fields as necessary.

* If the target field is single-valued and a value already exists, HDAP replaces the value with the value you provide.

  *HDAP does not return an error when adding a value to a single-valued field with an existing value.*

* If the target field is multivalued (an array), HDAP merges the array of values you provide with the existing values.

  For arrays, HDAP adds new values and ignores duplicates.

Add a telephone number

```javascript
[{
  "operation" : "add",
  "field" : "/telephoneNumber",
  "value" : "+1 408 555 1212"
}]
```

#### Remove

Patch `remove` ensures the target field does not contain the value provided.

* If you do not provide a value and the target field exists, HDAP removes the entire field.

* If you provide a value and the target field is single-valued, the value must match the existing value to remove; otherwise, HDAP does not change the field.

* If the target field is multivalued, HDAP removes the values in the array you provide from the existing set of values.

Remove all telephone numbers

```javascript
[{
  "operation" : "remove",
  "field" : "/telephoneNumber"
}]
```

Remove a specific telephone number

```javascript
[{
  "operation" : "remove",
  "field" : "/telephoneNumber",
  "value" : "+1 408 555 1212"
}]
```

#### Replace

Patch `replace` removes existing values on the target field and replaces them with the values you provide. It is equivalent to a `remove` of the field followed by an `add`.

Reset the telephone number

```javascript
[{
  "operation" : "replace",
  "field" : "/telephoneNumber",
  "value" : "+1 408 555 1212"
}]
```

#### Increment

Patch `increment` changes the value(s) in the target field by the amount you specify.

* Use a positive number to increment or a negative number to decrement the value(s).

* The target field must hold a number or a set of numbers.

* The value you provide must be a single number.

Lower the temperature

```javascript
[{
  "operation" : "increment",
  "field" : "/temperature",
  "value" : -2
}]
```

### Action

Use HTTP POST with the `_action` parameter to request a predefined action.

* `_action=accountUsability`: Determine whether the user can authenticate to the directory.

* `_action=create`: Create a resource with HTTP POST.

* `_action=modifyPassword`: Change your password.

* `_action=rename`: Rename a resource, changing its `_id`.

* `_action=resetPassword`: Change another user's password.

* `_action=schema`: Get the JSON schema for an object.

Supported [parameters](#query-parameters):

* `_action`

* `deleteOldRdn=true` (rename operation)

* `dryRun=true` (create, password, and rename operations)

* `_fields`

* `manageDsaIT=true` (rename operation)

* `objectClasses` (schema operation)

* `passwordQualityAdvice=true` (password operations)

* `_prettyPrint=true`

* `relax=true` (rename operation)

The request and response depend on the action. Learn more in [Actions](action-rest.html).

### Query

Use HTTP GET with the `_queryFilter` parameter to list resources at or under a target resource and matching a query filter. Accept a JSON response.

```http
GET /hdap/dc=com/dc=example/ou=People?_queryFilter=... HTTP/1.1
Host: example.com
Accept: application/json
```

HDAP returns the result as a JSON object including a `results` array. Other response fields depend on the parameters.

Supported [parameters](#query-parameters):

* `_countOnly=true`

* `_fields`

* `_pagedResultsCookie`

* `_pageSize`

* `_prettyPrint=true`

* `_queryFilter`

* `scope`

* `_sortKeys`

* `subentries=true`

* `_totalPagedResultsPolicy`

Learn more in [Query](query-rest.html).

## Headers

In addition to the headers described for HDAP [Operations](#operations), HDAP APIs support these Common REST headers.

### Accept-API-Version

The `Accept-API-Version` header specifies protocol and resource versions:

```
Accept-API-Version: protocol=version,resource=version
```

* `protocol`

  The version reflects changes in the Common REST protocol, such as common method parameters and headers specified by the protocol itself, or the input or response conventions it prescribes.

  For example, protocol version 2.2 introduced the `_countOnly` parameter.

* `resource`

  The version reflects changes in the resource implementation, including JSON representation of resources, input parameters required, and incompatible behavior changes.

  For example, the version changes when `errorMessage` changes to `message` in a JSON response.

The `Content-API-Version` response header specifies the protocol and resource versions for the operation. The default HDAP settings are equivalent to:

```
Accept-API-Version: protocol=2.1,resource=1.0
```

### X-ForgeRock-TransactionId

The optional `X-ForgeRock-TransactionId` header helps to track related requests through the Ping Identity Platform.

```
X-ForgeRock-TransactionId: transactionID
```

The transactionID consists of a unique identifier for the transaction optionally followed by a sequence number for the individual request.

You configure platform products to trust transaction IDs and let them propagate for audit purposes. For DS, learn more in [Log LDAP access to files](../logging-guide/ldap-access.html) or [Log HTTP access to files](../logging-guide/http-access.html).

## Query parameters

HDAP supports the following query string parameters.

|   |                                                                                       |
| - | ------------------------------------------------------------------------------------- |
|   | Some parameter values are not safe for URLs.URL-encode parameter values as necessary. |

* `_action=<action>`

  Perform an extended action as part of an HTTP POST.

  The \<action> is one of:

  * `accountUsability`

  * `create`

  * `modifyPassword`

  * `rename`

  * `resetPassword`

  * `schema`

* `_countOnly=true`

  Return a count of query results without returning the resources.

  This parameter requires protocol version 2.2 or later in the `Accept-API-Version` request header:

  ```
  Accept-API-Version: protocol=2.2,resource=1.0
  ```

* `deleteOldRdn=true`

  Delete the old RDN value when renaming a resource.

* `dryRun=true`

  Discover how a server reacts to an operation without performing the operation.

  This parameter relies on the LDAP no-op control, OID `1.3.6.1.4.1.4203.1.10.2`.

* `_fields=<field>[,<field>…​]`

  Return only the specified fields in the body of the response.

  The \<field> values are JSON pointers. In `{"parent":{"child":"value"}}`, `parent/child` refers to `"child": "value"`.

  When the request omits the `_field` parameter, HDAP returns fields for all LDAP user attributes.

  HDAP returns fields for operational attributes only when specifically requested. Use `+`, which encodes to `%2B`, to return fields for all operational attributes.

* `manageDsaIT=true`

  Manage [referrals](../config-guide/referrals.html).

  This parameter relies on the LDAP manage DSAIT request control, OID `2.16.840.1.113730.3.4.2`.

* `objectClasses=<objectClass>[,<objectClass>…​]`

  Return JSON schema for a resource to create based on the LDAP object classes and the parent resource.

* `_pagedResultsCookie=<cookie>`

  The \<cookie> is an opaque string HDAP uses when paging to keep track of the position in the query results:

  1. Set the `_pageSize` in the request to a non-zero number.

     HDAP returns the cookie with the first request.

  2. Supply the cookie in later requests until HDAP returns a `null` cookie when it reaches the final page.

* `_pageSize=<number>`

  Return query results in pages of this size.

  After the initial request, use `_pagedResultsCookie` or `_pageResultsOffset` to page through the results.

* `passwordQualityAdvice=true`

  Get additional information for a failed password update.

  The `passwordQualityAdvice` parameter relies on the DS LDAP password quality advice control, OID `1.3.6.1.4.1.36733.2.1.5.5`.

* `_prettyPrint=true`

  Format the body of the response.

* `_queryFilter=filter-expression`

  Query resources matching the [filter expression](#filter-expressions).

  You must URL-escape the filter-expression.

* `relax=true`

  Relax data and service rules temporarily for the requested update.

  This parameter relies on the LDAP relax rules control, OID `1.3.6.1.4.1.4203.666.5.12`.

* `scope=<scope>`

  Scope of the query; one of:

  * `base`: Query only the target resource.

  * `one` (default): Query direct child resources of the target resource.

  * `sub`: Query the target resource and all child resources recursively.

  * `subordinates`: Query all child resources recursively but do not include the target resource.

* `_sortKeys=(|-)[.var]##<field>##[,(|-)<field>…​]`

  Sort the query results based on the specified field(s).

  * Use `+` for ascending order (default, encoded as `%2B`).

  * Use `-` for descending order.

* `subentries=true`

  Return resources corresponding to LDAP subentries. Subentries aren't returned by default.

  This parameter relies on the LDAP subentries request control, OID `1.3.6.1.4.1.4203.1.10.1`.

* `subtreeDelete=true`

  Delete an entire subtree of resources.

  This parameter relies on the LDAP subtree delete control, OID `1.2.840.113556.1.4.805`.

* `_totalPagedResultsPolicy=<policy>`

  When a `_pageSize` is non-zero, HDAP can calculate `totalPagedResults`. It returns the `totalPagedResults` in the response depending on the \<policy>:

  * `"totalPagedResults": -1` by default, when `_pageSize` is not set, or when `_totalPagedResultsPolicy=NONE`.

  * An estimated count when `_totalPagedResultsPolicy=ESTIMATE`.

  * The exact count when `_totalPagedResultsPolicy=EXACT`, if possible.

### Filter expressions

Query filters request entries matching the filter expression. You must URL-escape the filter expression.

The string representation of the filter expression is:

```none
Expr           = OrExpr
OrExpr         = AndExpr ( 'or' AndExpr ) *
AndExpr        = NotExpr ( 'and' NotExpr ) *
NotExpr        = '!' PrimaryExpr | PrimaryExpr
PrimaryExpr    = '(' Expr ')' | ComparisonExpr | PresenceExpr | LiteralExpr
ComparisonExpr = Pointer OpName JsonValue
PresenceExpr   = Pointer 'pr'
LiteralExpr    = 'true' | 'false'
Pointer        = JSON pointer
OpName         = 'eq' |  # equal to
                 'co' |  # contains
                 'sw' |  # starts with
                 'lt' |  # less than
                 'le' |  # less than or equal to
                 'gt' |  # greater than
                 'ge' |  # greater than or equal to
                 STRING  # extended operator
JsonValue      = NUMBER | BOOLEAN | '"' UTF8STRING '"'
STRING         = ASCII string not containing white-space
UTF8STRING     = UTF-8 string possibly containing white-space
```

JsonValue components of filter expressions follow [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://www.rfc-editor.org/rfc/rfc7159.html). In particular, as described in section 7 of the RFC, the escape character in strings is the backslash character. For example, to match the identifier `test\`, use `_id eq 'test\\'`. In the JSON resource, the `\` is escaped the same way: `"_id":"test\\"`.

When using a query filter in a URL, the filter expression is part of a query string parameter and requires URL encoding. Learn more in [RFC 3986: Uniform Resource Identifier (URI): Generic Syntax](https://www.rfc-editor.org/rfc/rfc3986.html). For example, spaces, double quotes, parentheses, and exclamation characters need URL encoding. The following rules apply to URL query components:

```none
query       = *( pchar / "/" / "?" )
pchar       = unreserved / pct-encoded / sub-delims / ":" / "@"
unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
pct-encoded = "%" HEXDIG HEXDIG
sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
                  / "*" / "+" / "," / ";" / "="
```

`ALPHA`, `DIGIT`, and `HEXDIG` are core rules of [RFC 5234: Augmented BNF for Syntax Specifications](https://www.rfc-editor.org/rfc/rfc5234.html):

```none
ALPHA       =  %x41-5A / %x61-7A   ; A-Z / a-z
DIGIT       =  %x30-39             ; 0-9
HEXDIG      =  DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
```

A backslash escape character in a JsonValue component is percent-encoded in the URL query string parameter as `%5C`. To encode the query filter expression `uid eq 'test\\'`, use `uid+eq'test%5C%5C'+`, for example.

A simple filter expression can represent a comparison, presence, or a literal value.

For comparison expressions use json-pointer comparator json-value, where the comparator is one of the following:

`eq` (equals)\
`co` (contains)\
`sw` (starts with)\
`lt` (less than)\
`le` (less than or equal to)\
`gt` (greater than)\
`ge` (greater than or equal to)

For presence, use json-pointer pr to match resources where:

* The JSON pointer is present.

* The value it points to is not `null`.

Literal values include `true` (match anything) and `false` (match nothing).

Complex expressions employ `and`, `or`, and `!` (not), with parentheses, `(expression)`, to group expressions.

## HTTP status codes

When working with HDAP APIs, client applications should expect at least these HTTP status codes:

* 200 OK

  The request succeeded and HDAP returned a resource, depending on the request.

* 201 Created

  The request succeeded and the HDAP created the resource.

* 204 No Content

  The action request succeeded and there was no content to return.

* 304 Not Modified

  The read request included an `If-None-Match` header and the value of the header matched the revision value of the resource.

* 400 Bad Request

  The request was malformed.

* 401 Unauthorized

  The request requires user authentication.

* 403 Forbidden

  Access was forbidden during an operation on a resource.

* 404 Not Found

  The specified resource could not be found, perhaps because it does not exist.

* 405 Method Not Allowed

  The HTTP method is not allowed for the requested resource.

* 406 Not Acceptable

  The request contains unacceptable parameters, such as an unsupported resource or protocol version.

* 409 Conflict

  The request would have resulted in a conflict with the current state of the resource.

* 410 Gone

  The requested resource is no longer available and will not become available again. This can happen when resources expire, for example.

* 412 Precondition Failed

  The resource's current version does not match the version provided.

* 413 Content Too Large

  The search results exceeded the size limit.

* 415 Unsupported Media Type

  The request is in a format not supported by the requested resource for the requested method.

* 428 Precondition Required

  The resource requires a version and no version was supplied in the request.

* 500 Internal Server Error

  HDAP encountered an unexpected condition preventing it from fulfilling the request.

* 501 Not Implemented

  The resource does not support the functionality required to fulfill the request.

* 503 Service Unavailable

  The requested resource was temporarily unavailable.
