
# List directory users

`GET /v1/directories/{directory_id}/users` · permission `directories:read`

Lists the live user records the identity provider provisioned into the directory, ordered by ID: the normalized attributes, the user's directory groups, the link to the environment user and the drift flag. Deleted records are not returned. The `state` and `group_id` filters can be combined. Only forward paging exists; the cursor is bound to the directory and the filters.

Without the `users:read_pii` permission the credential receives masked personal data: `user_name` as its first character and `***`, `emails[].value` as `a***@e***.com`, `given_name`, `family_name` and `display_name` as initials, and `attributes` as `null`. `external_id`, `locale`, `zoneinfo`, the groups and the IDs are never masked. A secret key carries every permission.

## Request

| Field | Type | Required | Description |
|---|---|---|---|
| `directory_id` | path | yes | SCIM directory ID (`dir_…`). |
| `state` | query | no | Only users in this state: `active`, `inactive` or `held` (in a mass deprovision hold). |
| `group_id` | query | no | Only members of this directory group (`dsg_…`); a group of another directory returns an empty page. |
| `limit` | query | no | 1–100, default 20. |
| `after` | query | no | The cursor from `list_metadata.after`. |

There is no request body.

## Response

`200 OK` with a page of directory users.

```json
{
  "data": [
    {
      "id": "dsu_01j9xp4q6r8s0t2v4w6x8y0z2b",
      "directory_id": "dir_01j9xm2n4p6q8r0s2t4v6w8y0z",
      "external_id": "00u1a2b3c4",
      "user_name": "jane@example.com",
      "emails": [{ "value": "jane@example.com", "primary": true }],
      "given_name": "Jane",
      "family_name": "Doe",
      "display_name": "Jane Doe",
      "locale": "en-US",
      "zoneinfo": "Europe/Berlin",
      "state": "active",
      "attributes": { "department": "Engineering" },
      "groups": [{ "id": "dsg_01j9xn3p5q7r9s1t3v5w7x9y1a", "name": "Engineering" }],
      "user_id": "usr_01j9xq5r7s9t1v3w5x7y9z1a3c",
      "link_status": "linked",
      "drift": false,
      "created_at": "2026-10-20T09:00:00Z",
      "updated_at": "2026-10-20T09:05:00Z"
    }
  ],
  "list_metadata": {
    "before": null,
    "after": null
  }
}
```

`link_status` is one of `linked`, `invited`, `blocked_other_org`, `duplicate`, `mirror_only` or `unlinked`; `user_id` is `null` when the record is not linked. Empty values are `null`.

## Errors

| HTTP | code | When |
|---|---|---|
| 400 | `invalid_cursor` | The cursor is invalid or belongs to another directory or filter. |
| 404 | `not_found` | The directory does not exist in this environment. |
| 422 | `validation_failed` | `state` or `group_id` is invalid or repeated, `limit` is out of range, or `before` or `order` was given (`unsupported`). |
| 401 | `unauthenticated` | The credential is missing, invalid or revoked. |
| 403 | `insufficient_permissions` | The credential lacks the required permission. |
| 429 | `rate_limited` | The rate limit was exceeded; retry after the `Retry-After` period. |
| 503 | `service_unavailable` | Directory sync is temporarily unavailable or not configured in this deployment; retry after the `Retry-After` period. |

## Example

```bash
curl -i "https://api.eu.keenauth.com/v1/directories/dir_01j9xm2n4p6q8r0s2t4v6w8y0z/users?state=active&limit=20" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY"
```

## Personal data

This endpoint carries personal data: directory (SCIM) users. [Personal data in the KeenAuth APIs](/docs/policies/personal-data) describes what is stored, how long it is kept and how it is deleted. Do not send special categories of personal data (health, biometric data, religion, political opinions, sexual orientation) in any field.
