This guide explains the concepts used by the Form User API in Form LMS. For required fields and current request and response schemas, use the API reference.
Note: User lookups use an internal UUID or email address. The external-ID lookup rules for organisation units and groups do not apply to user endpoints.
External and internal IDs
The API uses identifiers to match objects in your application with objects in Form. Organisation units and groups have two identifiers:
- Internal ID: Form creates this identifier automatically. It is a 36-character universally unique identifier (UUID), version 4.
- External ID: Your application supplies this string when it creates the object. It must be unique for that object type.
For example, an organisation unit and a group can both have the external ID "1". Two organisation units cannot share that ID.
ID format
External IDs are strings. "1", "01" and "001" are different IDs, even though they represent the same number.
The id field refers to the external ID from your application. Fields named internalId, or similar, refer to Form's internal IDs.
Look up an object
For organisation units and groups, you can use either ID unless the endpoint specifies otherwise. The API looks for a matching external ID first, then an internal ID. If neither matches, it returns an error.
If a request accepts both IDs and you supply both, they must identify the same object.
Important: Avoid external IDs that match existing internal IDs. This can cause a lookup to find the wrong object.
Workspace configuration
Organisation units
Organisation units represent your organisation's structure. You can assign users and apply enrolment rules to each unit.
Units form a hierarchy, with parent units and child units. For example, your Sales department could have child units for regional sales teams. Each unit can have multiple children.
- Organisation (top-level organisation unit)
- Sales (child of Organisation)
- North region (child of Sales)
- South region (child of Sales)
- Sales (child of Organisation)
Sales is a child of Organisation and the parent of both regional units. Groups are separate from this hierarchy.
New workspaces have no organisation units.
Create an organisation unit
Send POST /api/organisation-units with a JSON body. This example creates a top-level unit:
{
"id": "sales",
"name": "Sales",
"parentId": null
}
idis your application's external ID. Use a non-empty string that is unique within the workspace.nameis the display name. Names must be unique among units with the same parent.parentIdidentifies the parent unit. Omit it or usenullto create a top-level unit. There can be only one top-level unit.
Use parentId when creating a unit. The parent field in a read response is a different field; it is not the create-request parameter.
suggestedCourses is populated on invitations for enrolment processing. It is not a parameter on the public organisation-unit create request. Configure enrolment rules in Form as described in Getting started.
Open the create request in the API reference.
Read organisation units
GET /api/organisation-unitsreturns the organisation structure for the workspace.GET /api/organisation-unit/{unitId}returns a unit and its descendants: children, their children and further levels.
The structure response includes the workspace name and a structure tree. If there is no organisation structure, the endpoint returns null.
| Field | Meaning |
|---|---|
id |
External ID from your application. |
internalId |
Form's internal UUID. |
parent |
Parent unit's external ID; null for the top-level unit. |
parentInternalId |
Parent unit's internal ID; null for the top-level unit. |
name |
Display name, up to 255 characters. |
children |
Child units, each with the same object structure. |
See organisation structure and individual units for the current response schemas.
Invitation
Send POST /api/users/invite to create a user profile and send an invitation. This example uses placeholder user details:
{
"emailAddress": "learner@example.com",
"firstName": "Example",
"lastName": "Learner",
"roles": ["learner"],
"customFields": {},
"organisationUnit": null,
"expireDate": null,
"managedOrganisationUnits": [],
"workspaceGroups": []
}
Prepare the invitation
- Supply the email address, first name, last name and roles required by the request schema.
- Use
organisationUnitandworkspaceGroupsto identify the unit and groups the user should join. - If you grant the Manager role, supply the organisation units they will manage in
managedOrganisationUnits. expireDatecan benullor a date inYYYY-MM-DDformat, today or later in UTC.customFieldsuses your workspace's configured field names and types. Retrieve these usingGET /api/settings/custom-fields.
Custom fields can include numbers, dates, email addresses and text. Use the returned field definition to choose the value type, rather than copying example field names.
A successful invite returns 201. See the invitation lifecycle for acceptance, profile activation and enrolment timing.
Manage invitations
| Task | Request details |
|---|---|
| Create an invitation | POST /api/users/invite |
| Resend an invitation | PATCH /api/user/{userId}/invite-resend |
| Cancel an invitation | DELETE /api/user/{userId}/invite-cancel |
| Update an invitation's email address | PUT /api/invitation/{userId}/email-address |
Use the user's internal UUID or email address for userId. Check the endpoint's responses if the invitation has already been handled or the user is unavailable.
User
List and find users
GET /api/users returns a paginated list. Its query parameters are:
| Parameter | Use |
|---|---|
page |
Page number; default 1. |
pageSize |
Number of users per page; default 12. |
sortDirection |
Sort direction: asc or desc. |
sortColumn |
Sort by lastName or emailAddress; default lastName. |
Use GET /api/user/{userId} to read one user. For defaults, constraints and response fields, see list users and get a user.
Update user details
PATCH /api/user/{userId} updates only the fields you supply. When supplying a complex field such as customFields, include all its values.
Custom fields
Use GET /api/settings/custom-fields to read the field names, types and requirements configured for your workspace. Send customFields as a JSON object whose keys are those field names and whose values match their types. Example names shown in the API reference are placeholders, not fields available in every workspace.
For PATCH /api/user/{userId}, omit customFields to leave existing values unchanged. When supplying values, include the complete set you want to retain. An empty object does not clear existing values on this endpoint.
The Swagger invitation examples omit optional custom fields. Add any custom fields required by your workspace before sending an invitation.
Change an email address
PUT /api/user/{userId} accepts users in the active or invited state. After the change, use the new email address for email-based lookups.
For an invited user, Form updates the invitation and sends it to the new address. You do not need a separate resend request after a successful change.
PUT /api/invitation/{userId}/email-address is an alias with the same request and response behaviour. Both routes accept active and invited users.
400can indicate invalid input or an unsupported user state.409means another user already uses the email address.422indicates a failure to update the address in the user store. Check the response before retrying.502means the address changed, but the invitation resend failed. Retry the invitation resend separately.
Open the email change request.
Change membership and roles
| Task | Request details |
|---|---|
| Remove an organisation-unit assignment | DELETE /api/user/{userId}/organisation-unit |
| Assign an organisation unit | PATCH /api/user/{userId}/organisation-unit |
| Replace user roles | PATCH /api/user/{userId}/roles |
A role update replaces the assigned roles. Any role omitted from the request is removed. To grant the Manager role, include the organisation units they will manage.
For example, roles: ["manager"] removes the Learner role if it was assigned. Send roles: ["learner", "manager"] to retain both. A learner without the Manager role must not have a non-empty managedOrganisationUnits list. Use the invitation roles endpoint for invited users, especially when assigning Manager.
Replacement behaviour
| Update | Effect |
|---|---|
PATCH /api/user/{userId}/roles and PATCH /api/invitation/{userId}/roles |
Replace the role list. Include all roles to retain. |
PATCH /api/invitation/{userId}/groups |
Replaces the invitation's group list. Include every group you want to keep. An empty list is rejected. Remove one group using DELETE /api/invitation/{userId}/group/{groupId}. |
PATCH /api/user/{userId} with non-empty customFields |
Supply the complete set of custom-field values to retain. Omitting the field or sending an empty object leaves existing values unchanged. |
PATCH /api/user/{userId} with expireDate |
Omit to keep the date. Send null to clear it. |
Operations that send invitation emails
| Request | Email effect |
|---|---|
POST /api/users/invite |
Triggers an invitation email. |
PATCH /api/user/{userId}/invite-resend |
Sends another invitation email for an invitation awaiting acceptance. |
PUT /api/user/{userId} or PUT /api/invitation/{userId}/email-address |
For an invited user, updates the email address and resends the invitation to the new address. For an active user, this invitation-resend step is skipped. |
For email changes, 502 means the address changed but the invitation resend failed. Retry the resend separately. After a timeout, check the current state before repeating a request that sends an email.
The API reference holds the complete endpoint definitions, including required fields, response codes and schemas. For troubleshooting, see Responses and errors.