User Endpoints

Endpoints are under /v1/users.

Base URL: https://api.gpcn.com/v1

See the API Reference → for examples in TypeScript, Python, Go, and C#.

Get Current User

GET /users/me

Returns the authenticated user's profile. No special permission required.

List Users

GET /users

Query Parameters

Parameter Type Default Description
page integer 1 Page number
limit integer 10 Items per page (max 100)
sort string createdAt:desc Sort field and direction
search string — Search by email, first name, or last name
entityId UUID — List the users of this tenant instead of your own (must be your own tenant or one beneath it)
excludeResourceGroupId UUID — Exclude users who are live members of this resource group. Naming the Default group excludes everyone, since every user is a member of it.
inviteStatus string — Filter: activated, pending, expired (repeatable)
resourceGroupId UUID — Filter by resource group (repeatable; OR'd together). Matches explicit memberships, except the tenant's Default group id matches every live user.
roleId string — Filter by role (repeatable; use 0 for no roles)
noResourceGroup boolean — Retired. Every user belongs to the tenant's Default group, so this answers 400 when true.
noRole boolean — Shorthand for roleId=0 — only users with no roles assigned
deletedFilter string exclude exclude, include, or only
curl https://api.gpcn.com/v1/users \
  -H "X-API-Key: gpcn_your_api_key_here"

Error: 400 Bad Request

The retired "no resource group" filter was used (noResourceGroup=true or resourceGroupId=0):

{
  "success": false,
  "message": "Filtering users by \"no resource group\" is retired: every user of a tenant belongs to its Default resource group.",
  "error": { "code": "Validation Error", "statusCode": 400 }
}

Create User (Invite or Register)

POST /users

Request Body (Invite)

{
  "email": "jane@example.com",
  "firstName": "Jane",
  "lastName": "Developer",
  "action": "invite",
  "roleNames": ["tenant-viewer"],
  "resourceGroupIds": ["880e8400-e29b-41d4-a716-446655440001"]
}

Request Body (Register)

{
  "email": "jane@example.com",
  "password": "SecurePass123!",
  "firstName": "Jane",
  "lastName": "Developer",
  "action": "register",
  "roleNames": ["tenant-viewer"],
  "resourceGroupIds": ["880e8400-e29b-41d4-a716-446655440001"],
  "entityId": "entity-uuid"
}
Field Type Required Description
email string Yes User email
action string No "invite" (default) or "register"
password string Register only 12–50 chars, mixed case + number + special
firstName string Yes on invite First name
lastName string Yes on invite Last name
roleNames string[] No Roles to assign, max 20. Defaults to ["tenant-viewer"]. An unknown name is a 422; a role above your own privilege is a 403.
resourceGroupIds UUID[] No Resource groups to add the user to besides the tenant's Default group, which every user belongs to automatically. Max 50; each must belong to the target tenant.
entityId UUID No Tenant to create in (defaults to yours; must be your own tenant or one beneath it)
curl -X POST https://api.gpcn.com/v1/users \
  -H "X-API-Key: gpcn_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "jane@example.com",
    "firstName": "Jane",
    "lastName": "Developer",
    "action": "invite",
    "roleNames": ["tenant-viewer"],
    "resourceGroupIds": ["880e8400-e29b-41d4-a716-446655440001"]
  }'

Error: 422 Unprocessable Entity

A resourceGroupIds list longer than 50, more than 20 roleNames, or an unknown role name:

{
  "success": false,
  "message": "Invalid Parameters: roleNames: Unknown role \"tenant-super\"",
  "error": { "code": "Validation Error", "statusCode": 422 }
}

Response (201 Created)

Get User Details

GET /users/{id}

Edit User

PUT /users/{id}

Request Body

{ "firstName": "Jane", "lastName": "Senior Dev", "email": "jane.new@example.com" }

Delete User

DELETE /users/{id}

Soft-delete. User can no longer sign in.

Response (204 No Content)

Resend Invitation

POST /users/{id}/resend-invite

Get User's Resource Groups

GET /users/{id}/resource-groups

Paginated list of resource groups the user is an explicit member of. The tenant's Default group isn't listed here, even though every user belongs to it implicitly.

Update Password (Self)

PUT /users/{id}/password

No special permission (self-service only).

Request Body

{ "currentPassword": "OldPass123!", "newPassword": "NewPass456!" }

Forgot Password

POST /users/forgot-password

Public endpoint (no auth required). Rate limited: 5 requests per IP per 15 minutes.

Request Body

{ "email": "jane@example.com" }

Get User's Roles

GET /users/{userId}/roles

Assign Role

POST /users/{userId}/roles

Requires role:create for an organization-wide assignment, or role:assign-scoped (held by Tenant Manager) for one scoped to a resource group.

Request Body

{ "roleName": "tenant-operator", "resourceGroupId": "880e8400-e29b-41d4-a716-446655440001" }
Field Type Required Description
roleName string Yes A system role or one of the tenant's custom roles
entityId UUID No Tenant scope (defaults to yours)
resourceGroupId UUID No Scopes the assignment to one resource group instead of the whole tenant

Error: 422 Unprocessable Entity

tenant-admin or tenant-manager named with a resourceGroupId:

{
  "success": false,
  "message": "tenant-admin and tenant-manager are tenant-wide roles and cannot be assigned to a resource group",
  "error": { "code": "Validation Error", "statusCode": 422 }
}

Revoke Role

DELETE /users/{userId}/roles/{roleName}

Pass resourceGroupId as a query parameter to revoke a resource-group-scoped assignment; omit it to revoke an organization-wide one.

Error: 404 Not Found

The user holds no live assignment of that role at that scope:

{
  "success": false,
  "message": "Role assignment not found",
  "error": { "code": "Role Not Found", "statusCode": 404 }
}

Response (204 No Content)

Bulk Delete Users

POST /users/bulk/delete
{ "ids": ["user-uuid-1", "user-uuid-2"] }

1–50 IDs.

Bulk Resend Invites

POST /users/bulk/resend-invite
{ "ids": ["user-uuid-1", "user-uuid-2"] }

Bulk Assign Roles

POST /users/bulk/assign-roles

Assigns a single organization-wide role to multiple users.

{ "userIds": ["user-uuid-1", "user-uuid-2"], "roleName": "tenant-viewer" }

1–50 user IDs.

Bulk Assign Resource Groups

POST /users/bulk/assign-resource-groups

Creates every user–group combination. Each assignment is attempted independently; partial success is possible.

{ "userIds": ["user-uuid-1"], "resourceGroupIds": ["880e8400-e29b-41d4-a716-446655440001"] }

1–50 IDs in each array.

Bulk Remove Resource Groups

POST /users/bulk/remove-resource-groups

Removes multiple users from multiple resource groups — every user–group pair, each attempted independently and reported under the id <userId>::<resourceGroupId>. Removing a user from a group also revokes any role assignment they hold scoped to it. A pair with no membership succeeds unchanged.

{ "userIds": ["user-uuid-1"], "resourceGroupIds": ["880e8400-e29b-41d4-a716-446655440001"] }

1–50 IDs in each array, no duplicates.

Error: 422 Unprocessable Entity

An empty array, more than 50 ids in either array, or a duplicate id:

{
  "success": false,
  "message": "Invalid Parameters: userIds: Array must contain at most 50 element(s)",
  "error": {
    "code": "Validation Error",
    "statusCode": 422,
    "details": { "issues": [{ "path": "userIds", "message": "Array must contain at most 50 element(s)" }] }
  }
}

A pair naming the tenant's Default group fails that one pair with "error": "Every user of the tenant is a member of the Default resource group" in its own result row — every user always belongs to it.

Next Steps