Skip to content

Reference

Directories

A directory keeps your user list in step with the customer's own source of truth, whether that is a SCIM endpoint at their identity provider or an HR system that knows about people before IT does. You read the result; the reconciliation, retries and per-vendor quirks stay on our side.

The directory object

A directory belongs to exactly one organization. Like connections, directories are created by the customer rather than by you — the credentials involved are theirs, and the endpoint they push to is provisioned during setup.

FieldTypeDescription
idstringUnique identifier, prefixed directory_.
objectstringAlways "directory".
organization_idstringThe tenant whose user list this directory carries.
namestringDisplay name, usually chosen by the IT admin who connected it.
typestringThe source system, such as okta scim v2.0, azure scim v2.0, gsuite directory or generic scim v2.0.
domainstring | nullThe primary email domain associated with the directory.
statestringlinking, active, validating, inactive or invalid_credentials. Only active directories are receiving updates.
created_attimestampRFC 3339.
updated_attimestampRFC 3339. Moves on configuration changes, not on every synced record.

The directory user object

A directory user is a record from the source system, not an account in your application. The two are related by idp_id, and keeping that relationship explicit is what lets you answer both of the questions that matter: who does the customer think works here, and who can actually sign in.

FieldTypeDescription
idstringPrefixed directory_user_. Distinct from the account-level user id.
objectstringAlways "directory_user".
directory_idstringThe directory this record came from.
idp_idstringThe identifier the source system uses. This is the value to key on: it survives a name change and a domain migration.
emailsarrayObjects with primary and value. A person can have several; exactly one is primary.
first_namestring | nullGiven name as sent by the source.
last_namestring | nullFamily name as sent by the source.
job_titlestring | nullPresent when the source populates it, which HR systems usually do and SCIM often does not.
statestringactive or suspended. A suspended user has been deactivated at the source, not deleted.
groupsarrayThe directory groups this person belongs to, each with an id and a name.
custom_attributesobjectEverything the source sent that does not map to a standard field, normalised to strings.

Suspended is not deleted

Most identity providers deactivate rather than delete. A suspended directory user should lose access immediately, but keeping the record lets you restore them in one step when somebody returns from leave — and lets your audit log explain what happened.

Endpoints

Paths are relative to https://api.paycux.com. The reference overview covers authentication.

MethodPathWhat it does
GET/directoriesList directory connections, filtered by organization, domain or state.
GET/directories/:idRetrieve one directory and its current sync state.
GET/directory_usersList synced users, filtered by directory or by group.
GET/directory_users/:idRetrieve one synced user, including every raw attribute the source sent.
GET/directory_groupsList synced groups, filtered by directory or by user.
DELETE/directories/:idDisconnect a directory and stop accepting updates from the source.

List directories

Directories are created by the customer's IT team through the Admin Portal, in the same way connections are, so this endpoint reads rather than creates. Filter by state to find the ones whose credentials have expired.

GET /directories
1curl "https://api.paycux.com/directories?organization_id=org_01HQ8ZK3M4N5P6R7S8T9V0W1X2" \
2 -H "Authorization: Bearer sk_example_123456789"
response
1HTTP 200
2{
3 "object": "list",
4 "data": [
5 {
6 "object": "directory",
7 "id": "directory_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
8 "organization_id": "org_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
9 "name": "Foo Corp SCIM",
10 "type": "okta scim v2.0",
11 "domain": "foo-corp.example",
12 "state": "active",
13 "created_at": "2026-04-14T10:02:19.441Z",
14 "updated_at": "2026-05-30T06:11:02.007Z"
15 }
16 ],
17 "list_metadata": { "before": null, "after": null }
18}

Retrieve a directory

The state field is the useful one. A directory sitting in invalid_credentials has stopped receiving updates, which means your user list is quietly drifting away from the customer's — the failure mode nobody notices until an offboarded employee still has access.

GET /directories/:id
1curl https://api.paycux.com/directories/directory_01HQ8ZK3M4N5P6R7S8T9V0W1X2 \
2 -H "Authorization: Bearer sk_example_123456789"
response
1HTTP 200
2{
3 "object": "directory",
4 "id": "directory_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
5 "organization_id": "org_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
6 "name": "Foo Corp SCIM",
7 "type": "okta scim v2.0",
8 "domain": "foo-corp.example",
9 "state": "active",
10 "created_at": "2026-04-14T10:02:19.441Z",
11 "updated_at": "2026-05-30T06:11:02.007Z"
12}

List directory users

Filter by group to answer the question a directory is usually bought for: who is in Engineering today. Filtering by directory and paginating gives you the full roster, which is what a nightly reconciliation job wants.

GET /directory_users
1curl "https://api.paycux.com/directory_users?directory=directory_01HQ8ZK3M4N5P6R7S8T9V0W1X2&limit=1" \
2 -H "Authorization: Bearer sk_example_123456789"
response
1HTTP 200
2{
3 "object": "list",
4 "data": [
5 {
6 "object": "directory_user",
7 "id": "directory_user_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
8 "directory_id": "directory_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
9 "idp_id": "00u1a0ufowBJlzPlk357",
10 "emails": [{ "primary": true, "value": "avery@foo-corp.example" }],
11 "first_name": "Avery",
12 "last_name": "Lindqvist",
13 "job_title": "Principal Engineer",
14 "state": "active",
15 "groups": [
16 { "id": "directory_group_01HQ8ZK3M4N5P6R7S8T9V0W1X2", "name": "Engineering" }
17 ],
18 "custom_attributes": { "department": "Platform", "employee_number": "4812" }
19 }
20 ],
21 "list_metadata": { "before": null, "after": "directory_user_01HQ8ZK3M4N5P6R7S8T9V0W1X3" }
22}

Retrieve a directory user

Read a single record when you are debugging a mapping. custom_attributes holds everything that did not fit a standard field, which is where the answer usually is when a customer says their department is missing.

GET /directory_users/:id
1curl https://api.paycux.com/directory_users/directory_user_01HQ8ZK3M4N5P6R7S8T9V0W1X2 \
2 -H "Authorization: Bearer sk_example_123456789"
response
1HTTP 200
2{
3 "object": "directory_user",
4 "id": "directory_user_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
5 "directory_id": "directory_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
6 "idp_id": "00u1a0ufowBJlzPlk357",
7 "emails": [{ "primary": true, "value": "avery@foo-corp.example" }],
8 "first_name": "Avery",
9 "last_name": "Lindqvist",
10 "job_title": "Principal Engineer",
11 "state": "active",
12 "groups": [{ "id": "directory_group_01HQ8ZK3M4N5P6R7S8T9V0W1X2", "name": "Engineering" }],
13 "custom_attributes": {
14 "department": "Platform",
15 "employee_number": "4812",
16 "cost_center": "CC-2200"
17 }
18}

List directory groups

Groups are how customers express who should get what. Read them once when you build your role mapping screen, and read them again on the group events rather than polling for changes.

GET /directory_groups
1curl "https://api.paycux.com/directory_groups?directory=directory_01HQ8ZK3M4N5P6R7S8T9V0W1X2" \
2 -H "Authorization: Bearer sk_example_123456789"
response
1HTTP 200
2{
3 "object": "list",
4 "data": [
5 {
6 "object": "directory_group",
7 "id": "directory_group_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
8 "directory_id": "directory_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
9 "idp_id": "00g1a0ufowBJlzPlk357",
10 "name": "Engineering",
11 "created_at": "2026-04-14T10:04:41.118Z"
12 }
13 ],
14 "list_metadata": { "before": null, "after": null }
15}

Disconnect a directory

Disconnecting stops the sync; it does not delete the users in your own application, and it does not sign anybody out. Decide explicitly what should happen to the people the directory was managing, because after this call nothing will tell you they left.

DELETE /directories/:id
1curl -X DELETE https://api.paycux.com/directories/directory_01HQ8ZK3M4N5P6R7S8T9V0W1X2 \
2 -H "Authorization: Bearer sk_example_123456789"
response
1HTTP 204
2(no body)

Errors

Reads against a directory in invalid_credentials still succeed and return the last synced state, because stale data is more useful than an error — but treat the state field as part of the response rather than decoration. A directory id from another environment returns 404.

Pagination

Directory lists are the ones that genuinely need pagination: a large customer can have tens of thousands of records. Walk the cursor and process each page, rather than accumulating the whole roster in memory.

reconcile.ts
1let after = null;
2
3do {
4 const page = await paycux.directorySync.listUsers({
5 directory: 'directory_01HQ8ZK3M4N5P6R7S8T9V0W1X2',
6 limit: 100,
7 after,
8 });
9
10 await reconcile(page.data);
11 after = page.listMetadata.after;
12} while (after);