Skip to content

Reference

Users

A user is one person, held at the account level rather than inside a tenant. The same user can belong to several organizations through memberships, which is what lets a consultant sign in to three of your customers without three accounts. Users created through SSO or a directory are managed at the source; users you create through this API are yours to maintain.

The user object

Every read returns the same shape, whether the record originated in an SSO sign-in, a directory sync or a call you made yourself. Fields are not removed from responses; new ones are added over time, so parse the fields you need rather than asserting on the whole object.

FieldTypeDescription
idstringUnique identifier, prefixed user_. Stable for the life of the record.
objectstringAlways "user".
emailstringPrimary email address. Unique within an environment.
email_verifiedbooleanWhether the address has been confirmed. Users created through a verified SSO connection arrive as true.
first_namestring | nullGiven name, from the identity provider when SSO was used.
last_namestring | nullFamily name.
profile_picture_urlstring | nullAvatar URL, if the provider supplied one.
external_idstring | nullYour own identifier for the person. Set it once during a migration and you can look the user up without keeping a second table.
last_sign_in_attimestamp | nullRFC 3339. Null until the first successful sign-in.
metadataobjectUp to 40 string key/value pairs of your own. Returned on every read; never used for routing or authorization.
created_attimestampRFC 3339.
updated_attimestampRFC 3339. Moves when any field above changes, including a sign-in.

Identify people by id, not email

Email addresses change. People change surnames, companies rebrand domains, and an address that identified one person in March can belong to somebody else by December. Key your own records on the user id and treat email as a mutable attribute you keep up to date.

Endpoints

Paths are relative to https://api.paycux.com. Every request carries a secret key as a bearer token; the reference overview covers authentication and environments.

MethodPathWhat it does
GET/usersList users, filtered by email, organization or verification state.
POST/usersCreate a user, with or without a password.
GET/users/:idRetrieve a single user by id.
PUT/users/:idUpdate profile fields, metadata or verification state.
DELETE/users/:idDelete a user, their memberships and every live session.
GET/users/:id/membershipsList the organizations a user belongs to, with the role held in each.

List users

Returns a cursor-paginated list, newest first. Filters combine with AND, so sending both organization_id and email answers the question you usually have: is this person already a member of that tenant?

GET /users
1curl "https://api.paycux.com/users?organization_id=org_01HQ8ZK3M4N5P6R7S8T9V0W1X2&limit=2" \
2 -H "Authorization: Bearer sk_example_123456789"
response
1HTTP 200
2{
3 "object": "list",
4 "data": [
5 {
6 "object": "user",
7 "id": "user_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
8 "email": "avery@foo-corp.example",
9 "email_verified": true,
10 "first_name": "Avery",
11 "last_name": "Lindqvist",
12 "profile_picture_url": null,
13 "external_id": null,
14 "last_sign_in_at": "2026-06-18T08:03:11.220Z",
15 "metadata": {},
16 "created_at": "2026-04-11T09:22:41.310Z",
17 "updated_at": "2026-06-18T08:03:11.220Z"
18 }
19 ],
20 "list_metadata": { "before": null, "after": "user_01HQ8ZK3M4N5P6R7S8T9V0W1X3" }
21}

Create a user

Omit password and you get an account that can only sign in through SSO, a magic link or a social provider, which is what you want for enterprise tenants. Creating a user with an address that already exists returns 422 rather than quietly merging the two.

POST /users
1curl -X POST https://api.paycux.com/users \
2 -H "Authorization: Bearer sk_example_123456789" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "email": "avery@foo-corp.example",
6 "first_name": "Avery",
7 "last_name": "Lindqvist",
8 "email_verified": false
9 }'
response
1HTTP 201
2{
3 "object": "user",
4 "id": "user_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
5 "email": "avery@foo-corp.example",
6 "email_verified": false,
7 "first_name": "Avery",
8 "last_name": "Lindqvist",
9 "profile_picture_url": null,
10 "external_id": null,
11 "last_sign_in_at": null,
12 "metadata": {},
13 "created_at": "2026-04-11T09:22:41.310Z",
14 "updated_at": "2026-04-11T09:22:41.310Z"
15}

Retrieve a user

The canonical read. An id that does not exist in this environment returns 404, and so does a valid id belonging to a different environment, so an accidental cross-environment lookup fails closed rather than confirming that the record exists somewhere.

GET /users/:id
1curl https://api.paycux.com/users/user_01HQ8ZK3M4N5P6R7S8T9V0W1X2 \
2 -H "Authorization: Bearer sk_example_123456789"
response
1HTTP 200
2{
3 "object": "user",
4 "id": "user_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
5 "email": "avery@foo-corp.example",
6 "email_verified": true,
7 "first_name": "Avery",
8 "last_name": "Lindqvist",
9 "profile_picture_url": "https://cdn.paycux.com/avatars/user_01HQ8ZK3.png",
10 "external_id": "crm-4812",
11 "last_sign_in_at": "2026-06-18T08:03:11.220Z",
12 "metadata": { "plan": "growth" },
13 "created_at": "2026-04-11T09:22:41.310Z",
14 "updated_at": "2026-06-18T08:03:11.220Z"
15}

Update a user

Fields you omit are left alone; fields you send as null are cleared. A directory-managed user has its name and email overwritten at the next sync, so edits to those two belong at the source rather than here.

PUT /users/:id
1curl -X PUT https://api.paycux.com/users/user_01HQ8ZK3M4N5P6R7S8T9V0W1X2 \
2 -H "Authorization: Bearer sk_example_123456789" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "last_name": "Lindqvist-Reyes",
6 "metadata": { "plan": "enterprise" }
7 }'
response
1HTTP 200
2{
3 "object": "user",
4 "id": "user_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
5 "email": "avery@foo-corp.example",
6 "email_verified": true,
7 "first_name": "Avery",
8 "last_name": "Lindqvist-Reyes",
9 "metadata": { "plan": "enterprise" },
10 "updated_at": "2026-06-19T10:41:02.775Z"
11}

Delete a user

Deletion is immediate and cannot be undone. Sessions are revoked in the same operation, so a signed-in browser stops working at its next refresh rather than at the end of the access token's life. Audit log events that mention the user are not deleted with them.

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

List a user's memberships

A user is account-level; the tenant relationship lives on the membership, which is also where the role is held. The same person can hold different roles in different organizations, so an authorization decision always needs both ids.

GET /users/:id/memberships
1curl https://api.paycux.com/users/user_01HQ8ZK3M4N5P6R7S8T9V0W1X2/memberships \
2 -H "Authorization: Bearer sk_example_123456789"
response
1HTTP 200
2{
3 "object": "list",
4 "data": [
5 {
6 "object": "organization_membership",
7 "id": "om_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
8 "user_id": "user_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
9 "organization_id": "org_01HQ8ZK3M4N5P6R7S8T9V0W1X2",
10 "role": { "slug": "admin" },
11 "status": "active",
12 "created_at": "2026-04-11T09:23:04.918Z"
13 }
14 ],
15 "list_metadata": { "before": null, "after": null }
16}

Errors

A missing or malformed key returns 401. A valid key without access to the resource returns 403. An id that does not exist in the environment returns 404, and a body that fails validation returns 422 with a per-field list of what was wrong. Every error carries a request id — quote it when you need help with one specific call.

Pagination

List endpoints are cursor paginated. Pass limit (default 10, maximum 100) and walk forwards with the after cursor from list_metadata, or backwards with before. Cursors are opaque strings that happen to resemble ids; never construct or parse one.

paginate.ts
1let after = null;
2const all = [];
3
4do {
5 const page = await paycux.userManagement.listUsers({ limit: 100, after });
6 all.push(...page.data);
7 after = page.listMetadata.after;
8} while (after);