> For the complete documentation index, see [llms.txt](https://fusionauth.io/docs/llms.txt)

# Import Users

API documentation for the FusionAuth Import Users API.

# Import Users

This API is used to bulk import multiple Users into FusionAuth. Each User must have at least an **email** or a **username**, and a **password** (plaintext or hash). If you don't have the User's password, you can set this field to a long random string and require the User to reset their password at their next login. This request is useful for migrating data from an existing database into FusionAuth. Additionally, you can provide an Id for each User inside the JSON User object of the request body. When using this API, the recommended batch size per request is dependent on deployment scale (note: 100,000 users per request is a reasonable batch size for a production capable deployment). After completing an import, you should [reindex the Elasticsearch database](https://fusionauth.io/docs/lifecycle/manage-users/search.md#reindexing-elasticsearch) as well.

You should not make multiple calls to this API in parallel. Multiple sequential calls to this API are fine.

## Request

[!API Key Authentication](https://fusionauth.io/docs/apis/authentication.md#api-key-authentication)

Import Multiple Users

POST/api/user/import

OpenAPI Spec

#### Request Headers

`X-FusionAuth-TenantId`Stringoptional

The unique Id of the tenant used to scope this API request.

When only a single tenant is configured the tenant Id can be assumed and this additional header is optional. Once more than one tenant has been configured in FusionAuth the tenant Id is required for this request. The tenant Id may be provided through this header or by using a tenant locked API key to achieve the same result.

See [Making an API request using a Tenant Id](https://fusionauth.io/docs/apis/authentication.md#making-an-api-request-using-a-tenant-id) for additional information.

You must provide either the **email** or the **username** field for each User. This will be used to authenticate the User and is also the User's unique identifier. These fields are marked as optional below, but you must provide one of them. The **password** field (plaintext or hash) is also required.

#### Request Body

`encryptionScheme`Stringoptional

The encryption scheme used to encrypt plaintext passwords encountered in the request. If this value is omitted the system configured value will be used.

The following encryptors are provided with FusionAuth:

*   **[salted-md5](https://fusionauth.io/docs/reference/password-hashes.md#salted-md5)**
*   **[salted-sha256](https://fusionauth.io/docs/reference/password-hashes.md#salted-sha-256)**
*   **[salted-hmac-sha256](https://fusionauth.io/docs/reference/password-hashes.md#salted-hmac-sha-256)**
*   **[salted-pbkdf2-hmac-sha256](https://fusionauth.io/docs/reference/password-hashes.md#salted-pbkdf2-hmac-sha-256)**
*   **[salted-pbkdf2-hmac-sha256-512](https://fusionauth.io/docs/reference/password-hashes.md#salted-pbkdf2-hmac-sha-256)**
*   **[salted-pbkdf2-hmac-sha512-512](https://fusionauth.io/docs/reference/password-hashes.md#salted-pbkdf2-hmac-sha-512)**
*   **[bcrypt](https://fusionauth.io/docs/reference/password-hashes.md#salted-bcrypt)**
*   **[phpass-md5](https://fusionauth.io/docs/reference/password-hashes.md#phpass-md5)**
*   **[phpass-sha512](https://fusionauth.io/docs/reference/password-hashes.md#phpass-sha-512)**

`factor`Integeroptional

The factor used to encrypt plaintext passwords encountered in the request. If this value is omitted the system configured value will be used.

`users`Arrayrequired

The list of Users to import.

`users[x].active`BooleanoptionalDefaults to false

True if the User is active. False if the User has been deactivated. Deactivated Users will not be able to login. Generally this should be set to `true` during the bulk import.

`users[x].birthDate`Stringoptional

`YYYY-MM-DD` formatted date of the User's birth.

`users[x].data`Objectoptional

An object that can hold any information about a User that should be persisted.

`user[x].data.email`Stringoptional

This field will be used as the email address if no **user.email** field is found. This field may be modified by advanced registration forms or the API. Setting this value to another account's email address allows that account to, in some cases, access information about this user.

If user `richard` has a **user.data.email** with a value of `dinesh@fusionauth.io`, whoever controls `dinesh@fusionauth.io` has elevated access to the `richard` account. That user can now reset the password on the `richard` account, for example. This functionality may be useful in certain scenarios, such as when accounts must share an email address. Think through the security ramifications before using this feature.

This feature was removed in version 1.26.0 and added back in in 1.27.2.

`users[x].email`Stringoptional

The User's email address.

`users[x].encryptionScheme`Stringoptional

The method for encrypting the User's password. If the password value is already encrypted this value is required.

Omitting this value indicates the password is in plain text and it will be encrypted using the default password encryptor.

caution

Importing users with plain text passwords is very slow because FusionAuth will hash each one using the default scheme. Grab some popcorn and catch a movie it can take up to several hundred milliseconds per user.

The following encryptors are provided with FusionAuth:

*   **[salted-md5](https://fusionauth.io/docs/reference/password-hashes.md#salted-md5)**
*   **[salted-sha256](https://fusionauth.io/docs/reference/password-hashes.md#salted-sha-256)**
*   **[salted-hmac-sha256](https://fusionauth.io/docs/reference/password-hashes.md#salted-hmac-sha-256)**
*   **[salted-pbkdf2-hmac-sha256](https://fusionauth.io/docs/reference/password-hashes.md#salted-pbkdf2-hmac-sha-256)**
*   **[salted-pbkdf2-hmac-sha256-512](https://fusionauth.io/docs/reference/password-hashes.md#salted-pbkdf2-hmac-sha-256)**
*   **[salted-pbkdf2-hmac-sha512-512](https://fusionauth.io/docs/reference/password-hashes.md#salted-pbkdf2-hmac-sha-512)**
*   **[bcrypt](https://fusionauth.io/docs/reference/password-hashes.md#salted-bcrypt)**
*   **[phpass-md5](https://fusionauth.io/docs/reference/password-hashes.md#phpass-md5)**
*   **[phpass-sha512](https://fusionauth.io/docs/reference/password-hashes.md#phpass-sha-512)**

If you don't see the scheme needed for importing your existing password you can also create your own password encryptor or we can build it for you. See the [Custom Password Hashing](https://fusionauth.io/docs/extend/code/password-hashes/custom-password-hashing.md) section for more information.

`users[x].expiry`Longoptional

The expiration [instant](https://fusionauth.io/docs/reference/data-types.md#instants) of the User's account. After this instant is reached, the User's account will automatically be deactivated.

`users[x].factor`Stringoptional

The factor used by the password encryption scheme. If omitted the factor will determined either by the system configured factor or the default value defined by the `PasswordEncryptor`.

The factor will generally be used as an iteration count to generate the hash. The actual use of this value is up to the `PasswordEncryptor` implementation.

`users[x].firstName`Stringoptional

The first name of the User.

`users[x].fullName`Stringoptional

The User's full name as a separate field that is not calculated from **firstName** and **lastName**.

`users[x].id`UUIDoptionalDefaults to secure random UUID

The Id of the User. If not specified a secure random UUID will be generated.

`users[x].imageUrl`Stringoptional

The URL that points to an image file that is the User's profile image.

`users[x].insertInstant`LongoptionalDefaults to now

The [instant](https://fusionauth.io/docs/reference/data-types.md#instants) when the user was created.

`users[x].lastName`Stringoptional

The User's last name.

`users[x].memberships`Arrayoptional

The list of memberships for the User.

`users[x].memberships[x].data`Objectoptional

An object that can hold any information about the User for this membership that should be persisted.

`users[x].memberships[x].groupId`UUIDrequired

The Id of the Group of this membership.

`users[x].memberships[x].id`UUIDoptionalDefaults to secure random UUID

The unique Id of this membership. If not specified a secure random UUID will be generated.

`users[x].middleName`Stringoptional

The User's middle name.

`users[x].mobilePhone`Stringoptional

The User's mobile phone number. This is useful to send the User push notifications or SMS messages.

note

The phone number in this field can't be used for login. Use **users\[x\].phoneNumber** for a phone that can be used for login.

`users[x].password`Stringoptional

The User's password. If **encryptionScheme** is provided this value is the existing password hash, if **encryptionScheme** is not provided this value is assumed to be plain text and it will be hashed during import.

The value of **password** should contain only the password hash, or, if the **encryptionScheme** is omitted, the plain text password. Unless you are using a custom plugin that does not utilize base64, **password** should be base64 encoded. It is recommended to use a base64 encoded string, but if you are importing hashes from a legacy system that uses base16, base32, or another encoding and are writing a custom plugin, import the hash in the same format the plugin produces.

Please see the [Password Hashes](#password-hashes) section for more information about importing particular password hashes.

Since 1.59.0

Prior to version 1.59.0, this field is required. Beginning with version 1.59.0, this field is optional.

`users[x].passwordChangeReason`StringoptionalDefaults to Administrative

When **passwordChangeRequired** is set to `true` you may optionally set a reason for this change. The possible values are:

*   `Administrative` - the password must be changed due to an administrative action
*   `Breached` - the password must be changed due to it being identified as breached in some fashion
*   `Expired` - the password must be changed due to expiration
*   `Validation` - the password must be changed due to the password no longer meeting the configured minimum requirements

In practice, leaving the default makes the most sense. The other reasons are used by FusionAuth during runtime to automatically require a user to change their password.

`users[x].passwordChangeRequired`BooleanoptionalDefaults to false

Indicates that the User's password needs to be changed during the next login attempt.

`users[x].passwordLastUpdateInstant`LongoptionalDefaults to now

Indicates that last [instant](https://fusionauth.io/docs/reference/data-types.md#instants) the password was changed.

If `encryptionScheme` is omitted this value will be ignored and set to now.

Note that if you have enabled password expiration or plan to do so in the future and you set this value to `0` or some other arbitrary time in the past that is greater than the password expiration value in days, these users will be required to change their password. It is recommended that you omit this value and allow the default value to be set unless you know the last time the user changed their password.

`users[x].phoneNumber`StringoptionalAvailable since 1.59.0

The phone number of the User.

note

Use this field instead of **users\[x\].mobilePhone** for a phone number that is used to log in, just like an email address or a username.

`users[x].preferredLanguages`Array<String>optional

An array of locale strings of the user's preferred languages, ordered by preference from most to least.

Use the language preferences for email templates and other localized text. For more information, see [Locales](https://fusionauth.io/docs/reference/data-types.md#locales).

`users[x].registrations`Arrayoptional

The list of registrations for the User.

`users[x].registrations[x].applicationId`UUIDrequired

The Id of the Application that this registration is for.

`users[x].registrations[x].cleanSpeakId`UUIDoptional

This Id is used by FusionAuth when the User's username for this registration is sent to CleanSpeak to be moderated (filtered and potentially sent to the approval queue). It is the **content Id** of the username inside CleanSpeak.

`users[x].registrations[x].data`Objectoptional

An object that can hold any information about the User for this registration that should be persisted.

`users[x].registrations[x].id`UUIDoptionalDefaults to secure random UUID

The Id of this registration. If not specified a secure random UUID will be generated.

`users[x].registrations[x].insertInstant`LongoptionalDefaults to now

The [instant](https://fusionauth.io/docs/reference/data-types.md#instants) that this registration was created.

`users[x].registrations[x].lastLoginInstant`Longoptional

The [instant](https://fusionauth.io/docs/reference/data-types.md#instants) that the User last logged into the Application for this registration.

`users[x].registrations[x].preferredLanguages`Array<String>optional

An array of locale strings of the user's preferred languages, ordered by preference from most to least.

Use the language preferences for email templates and other localized text. For more information, see [Locales](https://fusionauth.io/docs/reference/data-types.md#locales).

`users[x].registrations[x].roles`Array<String>optional

The list of roles that the User has for this registration. The string is the role's **Name** not the role's **Id**, e.g. `admin` or **user-role**.

`users[x].registrations[x].username`Stringoptional

The username of the User for this registration only.

`users[x].registrations[x].usernameStatus`StringoptionalDefaults to ACTIVE

The current status of the username. This is used if you are moderating usernames via CleanSpeak. The possible values are:

*   `ACTIVE` - the username is active
*   `PENDING` - the username is pending approval/moderation
*   `REJECTED` - the username was rejected during moderation

This state is managed by CleanSpeak, it may be changed by setting it on this request.

`users[x].registrations[x].verified`BooleanoptionalDefaults to false

Set this value to `true` in order to mark this registration as verified.

`users[x].registrations[x].verifiedInstant`LongoptionalDefaults to now

The [instant](https://fusionauth.io/docs/reference/data-types.md#instants) this registration was verified. This value will be ignored if **verified** is `false`.

`users[x].salt`Stringoptional

The User's password salt. Required if `encryptionScheme` is provided. Empty string is allowed.

When using any of the FusionAuth provided password encryption schemes, the incoming value is expected to be a Base64 encoded string of UTF-8 bytes. If your salt is stored as a plain string, you will need to Base64 encode it prior to import.

`users[x].tenantId`UUIDoptional

The User's tenant Id. If more than one tenant exists and you do not provide the `X-FusionAuth-TenantId` HTTP header or use API key to indicate which Tenant this request is for then this field will be required to complete the request.

When an API key is used that is locked to a Tenant or the tenant `X-FusionAuth-TenantId` HTTP header is provided this field is ignored.

`users[x].timezone`Stringoptional

The User's preferred timezone. The string must be in an [IANA](https://www.iana.org/time-zones) time zone format.

`users[x].twoFactor.methods[x].authenticator.algorithm`Stringoptional

The algorithm used by the TOTP authenticator. With the current implementation, this must be `HmacSHA1` if provided. Any other value will be ignored.

`users[x].twoFactor.methods[x].authenticator.codeLength`Integeroptional

The length of code generated by the TOTP. With the current implementation, this must be `6` if provided. Any other value will be ignored.

`users[x].twoFactor.methods[x].authenticator.timeStep`Integeroptional

The time-step size in seconds. With the current implementation, this must be `30` if provided. Any other value will be ignored.

`users[x].twoFactor.methods[x].email`Stringoptional

The value of the email address for this method. Only present if **user.twoFactor.methods\[x\].method** is `email`.

`users[x].twoFactor.methods[x].method`Stringoptional

The type of this method. There will also be an object with the same value containing additional information about this method. The possible values are:

*   `authenticator`
*   `email`
*   `sms`

`users[x].twoFactor.methods[x].mobilePhone`Stringoptional

The value of the mobile phone for this method. Only present if **user.twoFactor.methods\[x\].method** is `sms`.

`users[x].twoFactor.methods[x].secret`Stringoptional

A base64 encoded secret.

This field is required when **method** is `authenticator`.

`users[x].twoFactor.recoveryCodes`Array<String>optional

A list of recovery codes. These may be used in place of a code provided by an MFA factor. They are single use.

If a recovery code is used in a disable request, all MFA methods are removed. If, after that, a Multi-Factor method is added, a new set of recovery codes will be generated.

Since `1.68.0`, plaintext recovery codes provided here will be hashed during import. For large imports with many users having recovery codes, this will increase import time. To avoid this, pre-hash recovery codes and provide `users[x].twoFactor.recoveryCodeEncryptionScheme` and `users[x].twoFactor.recoveryCodeWorkFactor`.

`users[x].twoFactor.recoveryCodeEncryptionScheme`StringoptionalAvailable since 1.68.0

The encryption scheme used to hash the recovery codes provided in `users[x].twoFactor.recoveryCodes`. When provided, FusionAuth will treat the recovery codes as pre-hashed values and will not hash them again during import.

If this field is omitted, any plaintext recovery codes provided in `users[x].twoFactor.recoveryCodes` will be hashed using the default scheme during import.

Any supported password encryption scheme may be used. See `users[x].encryptionScheme` for FusionAuth-provided values.

`users[x].twoFactor.recoveryCodeWorkFactor`IntegeroptionalAvailable since 1.68.0

The work factor used when the recovery codes in `users[x].twoFactor.recoveryCodes` were hashed. Required when `users[x].twoFactor.recoveryCodeEncryptionScheme` is provided.

`users[x].twoFactorDelivery`StringoptionalDefaults to NoneDEPRECATED

The User's preferred delivery for verification codes during a two-factor login request.

The possible values are:

*   `None`
*   `TextMessage`

When using `TextMessage` the User will also need a valid `mobilePhone`.

Removed in 1.26.0

`users[x].twoFactorEnabled`BooleanoptionalDefaults to false

Determines if the User has two-factor authentication enabled for their account or not.

See the [Enable Two-Factor](https://fusionauth.io/docs/apis/two-factor/enable-multi-factor.md) and [Disable Two-Factor](https://fusionauth.io/docs/apis/two-factor/disable-multi-factor.md) APIs as an alternative to performing this action using the User API.

Removed in 1.26.0

`users[x].twoFactorSecret`StringoptionalDEPRECATED

The Base64 encode secret used to generate Two-Factor verification codes.

You may optionally use value provided in the **secret** field returned by the [Two-Factor Secret](https://fusionauth.io/docs/apis/two-factor/generate-a-secret.md) API instead of generating this value yourself.

Unless you are using `TextMessage` as your delivery type, ensure you are able to share the secret with the User before enabling Two-Factor authentication. Beginning in version 1.17.0, if you do create a User with `TextMessage` set as the `twoFactorDelivery` type and you omit this value, the secret will be generated for you. The secret can be generated because it is not necessary to share the secret with the User for this delivery method.

When using `None` as the **twoFactorDelivery** this value will be required.

Removed in 1.26.0

`users[x].username`Stringoptional

The username of the User.

`users[x].usernameStatus`StringoptionalDefaults to ACTIVE

The current status of the username. This is used if you are moderating usernames via CleanSpeak. The possible values are:

*   `ACTIVE` - the username is active
*   `PENDING` - the username is pending approval/moderation
*   `REJECTED` - the username was rejected during moderation

This state is managed by CleanSpeak, it may be changed by setting it on this request.

`users[x].verified`BooleanoptionalDefaults to false

Set this value to `true` in order to mark the user as having a verified email address and/or phone number. If the user has both identity types, both will be marked as verified.

`users[x].verifiedInstant`LongoptionalDefaults to now

The [instant](https://fusionauth.io/docs/reference/data-types.md#instants) this user's email address or phone number was verified. This value will be ignored if **verified** is `false`.

`validateDbConstraints`BooleanoptionalDefaults to false

Set this value to `true` in order to perform additional validation of the request.

The import request is intended to be used to populate the initial set of users, this means FusionAuth does not expect to find duplicate users in the database. If a duplicate is encountered a `500` will be returned without this additional validation.

If you intend to use this API with existing users in FusionAuth set this value to `true` to request additional validation be performed on the input request and a `400` response will be returned with a JSON body indicating the duplicate values encountered.

Setting this value to `true` will dramatically decrease the performance of this request. If importing large numbers of users in a single request you may need to increase request timeouts to ensure this request does not timeout before it has completed.

*Example Request JSON*

```json
{
  "users": [
    {
      "active": true,
      "birthDate": "1976-05-30",
      "data": {
        "displayName": "Johnny Boy",
        "favoriteColors": [
          "Red",
          "Blue"
        ]
      },
      "email": "example@fusionauth.io",
      "encryptionScheme": "salted-sha256",
      "expiry": 1571786483322,
      "factor": 24000,
      "firstName": "John",
      "fullName": "John Doe",
      "imageUrl": "http://65.media.tumblr.com/tumblr_l7dbl0MHbU1qz50x3o1_500.png",
      "insertInstant": 1331449200000,
      "lastName": "Doe",
      "memberships": [
        {
          "data": {
            "externalId": "cc6714c6-286c-411c-a6bc-ee413cda1dbc"
          },
          "groupId": "2cb5c83f-53ff-4d16-88bd-c5e3802111a5"
        }
      ],
      "middleName": "William",
      "mobilePhone": "303-555-1234",
      "password": "5ac152b6f8bdb8bb12959548d542cb237c4a730064bf88bbb8dd6e204912baad",
      "passwordChangeRequired": false,
      "phoneNumber": "303-555-1212",
      "preferredLanguages": [
        "en",
        "fr"
      ],
      "registrations": [
        {
          "applicationId": "00000000-0000-0000-0000-000000000002",
          "data": {
            "birthplace": "Bremen"
          },
          "insertInstant": 1331449200000,
          "preferredLanguages": [
            "de"
          ],
          "roles": [
            "moderator"
          ],
          "username": "Mausebär",
          "verified": true
        }
      ],
      "salt": "NDdiYWZkZDMtYjk5ZC00ZmZkLWE1YmUtZTQxNGM4MDkwNWYw",
      "timezone": "America/Denver",
      "twoFactor": {
        "methods": [
          {
            "authenticator": {
              "algorithm": "HmacSHA1",
              "codeLength": 6,
              "timeStep": 30
            },
            "secret": "aGVsbG8Kd29ybGQKaGVsbG8gaGVsbG8=",
            "method": "authenticator"
          },
          {
            "method": "sms",
            "mobilePhone": "555-555-5555"
          },
          {
            "method": "email",
            "email": "example@fusionauth.io"
          }
        ]
      },
      "usernameStatus": "ACTIVE",
      "username": "johnny123",
      "verified": true
    }
  ]
}
```

## Response

Only a status code is available on the Import API, no JSON body will be returned.

*Response Codes*

| Code | Description |
| --- | --- |
| 200 | The request was successful. The response will contain a JSON body. |
| 400 | The request was invalid and/or malformed. The response will contain an [Errors](https://fusionauth.io/docs/apis/errors.md) JSON Object with the specific errors. This status will also be returned if a paid FusionAuth license is required and is not present. |
| 401 | You did not supply a valid Authorization header. The header was omitted or your API key was not valid. The response will be empty. See [Authentication](https://fusionauth.io/docs/apis/authentication.md). |
| 500 | There was an internal error. A stack trace is provided and logged in the FusionAuth log files. The response will be empty. |
| 503 | The search index is not available or encountered an exception so the request cannot be completed. The response will contain a JSON body. |
| 504 | One or more Webhook endpoints returned an invalid response or were unreachable. Based on the transaction configuration for this event your action cannot be completed. A stack trace is provided and logged in the FusionAuth log files. |

## Password Hashes

Password hashes can be imported into FusionAuth. This allows users to transparently use their old passwords while at no time exposing the plaintext password. This section contains details about importing specific password hashes.

You can also learn more about hashes in the [password hashing reference](https://fusionauth.io/docs/reference/password-hashes.md), and you can [implement your own custom hash](https://fusionauth.io/docs/extend/code/password-hashes/custom-password-hashing.md) as well.

## Encoding

The standard FusionAuth password hashing schemes require the password hash to be a base64 encoded string. If your password hashes are encoded in a different format, they will need to either be converted and imported as base64, or you can create a custom plugin using an alternative encoding. You can see an example of converting below.

It is recommended to use a base64 encoded string, but if importing hashes from a legacy system that uses base16, base32, or another encoding, import the hash in the same format the plugin produces.

*Example of Converting a Base16 Password Hash Value to Base64*

```ruby
hash_in_hex = "25d55ad283aa400af464c76d713c07ad"

def hex_to_base64_digest(hexdigest)
  [[hexdigest].pack("H*")].pack("m0")
end

puts hex_to_base64_digest(hash_in_hex)
```

## Bcrypt

When importing a bcrypt hash, you may have a value such as:

`$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy`

This single string represents the bcrypt version, factor, salt and hash.

The number before the final `$` is the factor, the 22 characters after the final `$` is the salt and the last 31 characters are the hash.

For the above bcrypt hash, `10` is the factor and should be placed in the **factor** field. `N9qo8uLOickgx2ZMRZoMye` is the salt and should be placed in the **salt** field. `IjZAgcfl7p92ldGxad68LJZdL17lhWy` is the hash value and should be placed in the **password** field.

## MD5

When importing an MD5 password hash, you may not have a salt. If this is the case, use the empty string, `''`, as the salt. You may still use the salted MD5 plugin provided by FusionAuth.

MD5 is commonly stored in hexadecimal format, such as `25d55ad283aa400af464c76d713c07ad`. The FusionAuth Import Users API requires imported password hashes to be base64 encoded. Convert any hexadecimal values to base64 before importing, or the import will not work.

Here is an example ruby script to convert hexadecimal values to base64 encoded:

*Convert a Hexadecimal Password Hash Value to Base64*

```ruby
hash_in_hex = "25d55ad283aa400af464c76d713c07ad"

def hex_to_base64_digest(hexdigest)
  [[hexdigest].pack("H*")].pack("m0")
end

puts hex_to_base64_digest(hash_in_hex)
```