Creates a new administrative user account in the system
POST /api/users
- Products: Operator (
FOH) - Features: Front of House Generic Access (
FOHGENERIC)
Overview
Creates a staff (back-office) user account for the tenant. These are the people who operate the leisure centre — not members or customers — and the account created here is what they sign in with. It returns 201 Created with no response body; read the new account back with Retrieves detailed information for a specific administrative user using the username you sent.
Two things have to exist before you call this. The site group — a named collection of sites that configuration is applied across — must already be set up, and the site you name in preferredSiteId must be one of the sites inside it. List the available groups and their member sites with Retrieves all site groups with their configuration details.
The username is effectively permanent. Deleting a user (see Permanently deletes a user account from the system) keeps the deleted account on record, and deleted accounts still count when this endpoint checks for duplicates — so a username that has ever been used cannot be used again, and re-creating a deleted user returns 409.
Password rules are per-tenant configuration, not a fixed policy. The password is checked against a regular expression drawn from the tenant's PasswordComplexity setting (low, medium or high) before anything else happens, and a failure returns 400 with the tenant's own wording, so do not hard-code a complexity rule in your client.
Endpoint
POST {base_url}/api/users
{base_url} is the environment URL issued to your integration. See Authenticating with Gladstone APIs.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
username | string | Yes | The sign-in name for the new account, and the identifier every other endpoint on this group takes in its path. Rejected with 400 if blank or longer than 8 characters (Username cannot be more than 8 characters); existing usernames can be up to 15 characters, but this endpoint accepts no more than 8. Must be unique across the tenant, including against previously deleted accounts, or the call fails with 409 and The user: {username} already exists. |
password | string | Yes | The initial sign-in password, sent in plain text over TLS and stored hashed. Rejected with 400 if blank or longer than 128 characters. It is validated against the tenant's configured complexity regular expression before any other check; when it fails, the 400 body is a JSON object {"errorMessage": "…", "isPasswordError": true} carrying the tenant's own message, rather than a plain string. Also recorded in the user's password history, so it cannot be reused later through Updates the password for a specific user account. |
firstName | string | Yes | The user's given name, used to build displayName when you do not supply one. Rejected with 400 if blank or longer than 25 characters. |
lastName | string | Yes | The user's family name, used to build displayName when you do not supply one. Rejected with 400 if blank or longer than 25 characters. |
displayName | string | No | The name shown to other staff in the back office. Rejected with 400 above 50 characters. Omitted or blank, it defaults to "{firstName} {lastName}" — so leave it out unless you need a different form, such as a shortened or preferred name. |
email | string | No | Contact address for the account. Rejected with 400 above 255 characters, and — when non-empty — validated against an RFC-style address pattern, failing with The given email address is invalid. Omit it or send an empty string to create the account with no address; the format check is skipped in that case. |
cardId | string | No | The identifier printed on or encoded in the physical staff card this user presents at a reader or till. Rejected with 400 above 50 characters. Omit it if the user has no card. |
siteGroupId | string | Yes | The site group this user belongs to, taken from id in Retrieves all site groups with their configuration details. It must resolve to an existing group or the call fails with 400 and The given site group doesn't exist., and it also constrains preferredSiteId. Rejected with 400 if blank. |
preferredSiteId | string | Yes | The site this user works at by default. It must be one of the sites listed inside siteGroupId, compared case-insensitively; anything else fails with 400 and The preferred site ID must be contained in the given site group. Rejected with 400 if blank. It is saved as a user preference named PreferredSiteId rather than as a field of the account, and comes back in that form through Retrieves detailed information for a specific administrative user. |
avatarId | string | No | The profile image the back office shows for this user. Rejected with 400 above 25 characters. On ObjectId-role tenants (see roleId), omitting it or sending an empty string saves the literal value default. On numeric-role tenants no default is applied and the value is not saved at all — the user-retrieval endpoints return avatarId: null for such accounts. |
roleId | string | No | The permission role to grant, as a 24-character hexadecimal ObjectId string. Honoured only on ObjectId-role tenants — those whose users' roleId values are 24-character hexadecimal strings in Retrieves all administrative users configured in the system — where the role must already exist or the call fails with 400 and The given role ID does not exist. On numeric-role tenants it is ignored entirely and the account is placed in the tenant's default user group instead. Omit it to create the account with no role claim. Note that a non-hexadecimal or wrong-length value is not validated and returns 500, not 400. |
sharedSiteGroupId | integer (int32) | No | Ignored on input. Whatever you send is replaced with the numeric identifier of the site group resolved from siteGroupId, so there is no need to populate it. |
Sample request
curl -X POST '{base_url}/api/users' \
-H 'Authorization: Bearer {accessToken}' \
-H 'X-Use-SSO: true' \
-H 'Content-Type: application/json' \
-d '{
"username": "string",
"password": "string",
"firstName": "string",
"lastName": "string",
"displayName": "string",
"email": "member@example.com",
"cardId": "string",
"siteGroupId": "string",
"preferredSiteId": "string",
"avatarId": "string",
"roleId": "string",
"sharedSiteGroupId": 12345
}'Errors
| Status | Meaning | When |
|---|---|---|
400 | Bad request | The password does not match the tenant's configured complexity pattern. The body is a JSON object {"errorMessage": "…", "isPasswordError": true} carrying the tenant's own message, not a plain string. |
400 | Bad request | A required field is blank, or a field exceeds its maximum length — for example Username cannot be more than 8 characters or DisplayName cannot be more than 50 characters. |
400 | Bad request | email is non-empty but not a valid address: The given email address is invalid. |
400 | Bad request | siteGroupId does not resolve to a site group: The given site group doesn't exist. |
400 | Bad request | preferredSiteId is not one of the sites in siteGroupId: The preferred site ID must be contained in the given site group. |
400 | Bad request | On ObjectId-role tenants only, roleId is a well-formed ObjectId that matches no role: The given role ID does not exist. |
409 | Conflict | The username is already taken: The user: {username} already exists. Deleted accounts still occupy their username, so this also fires when you re-create a user you previously deleted. |
409 | Conflict | The new account clashes with an existing record on a value that must be unique: This entry already exists in the database. |
500 | Internal server error | The tenant's password security configuration is missing or names a complexity level with no matching regular expression — this endpoint does not translate that fault into a 422. Also returned when roleId is not a valid 24-character hexadecimal ObjectId, and for other unexpected server-side failures, such as the account failing to save completely. |