Create a user: Migration guide

This guide outlines the changes introduced in the Create an invited user v2 endpoint (previously known as createOrInviteUser in v1).

💡

Key changes

  • Invitation email: The v2 endpoint now always creates a new user in an invited state and immediately sends them an invitation email to them. Currently, there is no option to suppress this initial email.
  • Security enhancement: v2 removes the ability to send user credentials (passwords) directly via email. This is a deliberate security enhancement. If you set a user's password programmatically (via the separate Replace the password of a user endpoint), you must find a secure alternative way to communicate it to the user, as the API v2 will not send emails containing credentials.
  • Single initial group membership: In v1, you could add users to multiple groups in a single call. This v2 endpoint allows you to add a user to only one group at the time of creation via the membership object. To add a user to additional groups after creation, use the dedicated Add a user's role v2 endpoint.
  • Multi-step process to activate users: After initial creation in an invited state, achieving a user in an active state, especially one with a pre-set password, now requires multiple steps.

For details on these key changes, refer to the Behavior changes section below.

Documentation links

Here are the links to the API reference for:

Endpoint mapping

Here's the direct correlation between the v1 and v2 endpoint URLs:

  • API v1: /api/v1/users
  • API v2: /api/v2/users

Behavior changes

Creating invited users

The main and crucial behavioral change is that the v2 endpoint always creates an invited user and immediately sends an invitation email to them.

💡

What is an invited user?

An invited user is an account that exists in the system but is not yet fully active. This means:

  • The user cannot log in or access the platform yet.
  • They are non-billable until activated.
  • They receive an invitation email with a link to activate their account and set their password.
  • Their account requires activation to become fully active, billable, and enable login. Activation can occur:
    • Via email: The user clicks the link in the invitation email.
    • Programmatically: By calling the Activate a user endpoint.

❗️

Crucially, it is no longer possible to create a fully active user via a single API call, and the user not receiving an invitation email. The initial Create an invited user call will always result in creating a user account in the invited state and sending an email inviting the user to join the platform.

Handling deleted users

If a user already exists with the same email in a deleted state, calling the Create an invited user v2 endpoint will restore them:

  • They will receive a new invitation email.
  • Their account will enter the invited state.
  • Their account also requires activation to become fully active, billable, and enable login.

Initial group assignment

Unlike API v1, where createOrInviteUser allowed assigning a user to multiple groups in a single call, API v2 now only supports assigning a user to a single initial group using the membership object.

To add a user to additional groups after creation, use the separate Add a user's role endpoint.

Achieving v1 outcomes in v2

Achieving certain user states that were previously possible in a single API v1 call may now require a sequence of API v2 calls.

Here's how different API v1 createOrInviteUser outcomes map to API v2 workflows:

API v1 createOrInviteUser scenarioAPI v1 outcome and notificationAPI v2 workflow
- password not defined in the payload.

- AND sendCredential set to false or not included in the payload.
- User is created in an invited state.
- User receives an invitation email.
Call Create an invited user.
The user will immediately receive an invitation email.
- password not defined in the payload.

- AND sendCredentials set to true.
- User is created in an active state.
- User receives an invitation email with system-generated credentials.
This exact scenario cannot be reproduced with API v2. API v2 does not send credentials via email for security purposes.

You can, however, create and activate a user who will receive an invitation email (no password) with the following steps:

1. Call Create an invited user.
The user will immediately receive an invitation email. The invitation email will not contain a password. You must find an alternative way to communicate passwords to your users.

2. Call Activate a user to change the user's status from invited to active.
- password defined in the payload.
- AND sendCredentials set to false or not included in the payload.
- User is created in an active state.
- User does not receive an invitation email.
This exact scenario cannot be reproduced with API v2 yet. Users created via API v2 will immediately receive an invitation email.

You can, however, create and activate a user with the following steps:

1. Call Create an invited user. The user will receive an invitation email at this step.

2. Call Activate a user to change the user's status from invited to active.
- password defined in the payload.

- AND sendCredentials set to true.
- User is created in an active state.
- User receives an invitation email with the password.
This exact scenario cannot be reproduced with API v2. API v2 does not send credentials via email for security purposes.

You can, however, create and activate a user who will receive an invitation email (no password) with the following steps:

1. Call Create an invited user.
The user will receive an invitation email at this step.

2. Call Replace the password of a user to set the password in the payload.
The password won't be sent to the user via email. You must find an alternative way to communicate the new password to your users.

3. Call Activate a user to change the user's status from invited to active.

Input changes

This section details the specific alterations to the input requirements between API versions.

API v1 input example

curl --location -g 'https://app.360learning.com/api/v1/users?company={{company}}&apiKey={{apiKey}}' \
--data-urlencode '[email protected]' \
--data-urlencode 'firstName=Paul' \
--data-urlencode 'lastName=Durand' \
--data-urlencode 'phone=0123456789' \
--data-urlencode 'lang=fr' \
--data-urlencode 'job=Tester' \
--data-urlencode 'roles%5B0%5D=learner' \
--data-urlencode 'organization=Org.' \
--data-urlencode 'custom=AZE12345' \
--data-urlencode 'groups%5B0%5D=5694ea540fa69fdd0ec0004f' \
--data-urlencode 'groups%5B1%5D=5ae6f128331332775cfb14be' \
--data-urlencode 'primaryGroupId=5694ea540fa69fdd0ec0004f'

API v2 input example

curl --request POST \
     --url https://app.360learning.com/api/v2/users \
     --header '360-api-version: v2.0' \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'authorization: Bearer access_token' \
     --data '
{
  "membership": {
    "role": "learner",
    "groupId": "507f1f77bcf86cd799439011"
  },
  "mail": "[email protected]",
  "username": "johnsmith",
  "custom": "Half-time worker",
  "firstName": "John",
  "lastName": "Smith",
  "job": "Boss",
  "lang": "en",
  "organization": "360Learning",
  "phone": "+33123456789"
}
'

Main input differences

Change typeAPI v1API v2
Removed
Body parameter
primaryGroupId: ID of the user's primary group.This parameter is removed from v2.
Removed
Body parameter
sendCredentials: Boolean to choose whether to send an email with credentials.This parameter is removed from v2.
Removed
Body parameter
password: Used to set a password for the user during creation. Removed from endpoint v2.Now handled by the separate Replace the password of a user endpoint.
Modified
Body parameter
groups & roles: Group IDs to which the user should be added, and the corresponding roles. This allowed adding a user to multiple groups in a single call.- membership: (Required) The initial group membership of the user, containing both groupId and role.
- Use Add a user's role to add the user to additional groups.

Output changes

The output has completely changed to follow RESTful principles. Instead of returning an acknowledgment of the user creation, we now return the created user object.

API v1 output example

{
  "status": "user_created",
  "_id": "5be2b954b44a1b6e3526e091"
}

API v2 output example

{
  "_id": "5be2b954b44a1b6e3526e091",
  "mail": "[email protected]",
  "username": "johnsmith",
  "deleted": true,
  "lang": "bg",
  "firstName": "John",
  "lastName": "Smith",
  "job": "Engineer",
  "organization": "360Learning",
  "phone": "+33123456789",
  "custom": "Half-time worker",
  "deletedAt": [
    "2025-06-06T13:21:38.271Z"
  ],
  "reactivatedAt": [
    "2025-06-06T13:21:38.271Z"
  ],
  "lastLoginDate": "2025-06-06T13:21:38.271Z",
  "toBeDeactivatedAt": "2025-06-06T13:21:38.271Z"
}

Main output differences

As shown in the example above, the response is completely different, so please refer to the Retrieve a user: Migration guide for more information.

Change typeAPI v1API v2
Removed
Output parameter
status
Removed
Error code
400 - user_already_exists-
Removed
Error code
400 - invitation_created-
Removed
Error code
400 - invitation_already_exists-
Removed
Error code
400 - unavailableEmails-
Removed
Error code
400 - invalid argument: email-
Removed
Error code
400 - faultyInvitations-
Removed
Error code
400 - user_not_member_of_primaryGroup-
Removed
Error code
400 - user_already_exists-
Added
Error code
-400 - deactivationDateInvalid: The given deactivation date must be set to a future date.
Added
Error code
-400 - loginIdentifierMultipleUsersFound: Mail and username match a different user each.
Added
Error code
-400 - mailInvalid: The given mail is invalid.
Added
Error code
-400 - mailAndUsernameUndefined: The given input must contain a mail or a username.
Added
Error code
-400 - mailAlreadyUsed: The given mail is already used.
Added
Error code
-400 - mailUsedTooManyTimes: The given mail is already used too many times.
Added
Error code
-400 - usernameAlreadyUsed: The given username is already used.
Added
Error code
-400 - usernameNotAllowed: The use of username for login is not allowed by your company.
Added
Error code
-404 - groupNotFound: The given groupId does not correspond to any existing group.