> ## Documentation Index
> Fetch the complete documentation index at: https://docs-staging-actions-triggers-prototype.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Learn how to perform bulk user imports with the Management API.

# Bulk User Imports

export const AuthCodeGroup = ({children, dropdown}) => {
  const [processedChildren, setProcessedChildren] = useState(children);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      unsubscribe = window.autorun(() => {
        const processChildren = node => {
          if (typeof node === "string") {
            let processedNode = node;
            for (const [key, value] of window.rootStore.variableStore.values.entries()) {
              const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
              processedNode = processedNode.replaceAll(new RegExp(escapedKey, "g"), value);
            }
            return processedNode;
          } else if (Array.isArray(node)) {
            return node.map(processChildren);
          } else if (node && node.props && node.props.children) {
            return {
              ...node,
              props: {
                ...node.props,
                children: processChildren(node.props.children)
              }
            };
          }
          return node;
        };
        setProcessedChildren(processChildren(children));
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  return <CodeGroup dropdown={dropdown}>{processedChildren}</CodeGroup>;
};

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASKED*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

You can bulk import user data into Auth0 using the [Create Import Users Job](https://auth0.com/docs/api/management/v2#!/Jobs/post_users_imports) endpoint. Bulk imports are useful for migrating users from an existing database or service to Auth0.

<Warning>
  If you try to use more than one migration method (for example, automatic migration then bulk user import), you may encounter a `DUPLICATED_USER` error. This error indicates that the user exists in Auth0's internal user store but not in your tenant. To correct this error, delete the user with the Auth0 Management API [Delete a Connection User](https://auth0.com/docs/api/management/v2#!/Connections/delete_users_by_email) endpoint and then re-attempt the import.
</Warning>

## Prerequisites

Before you launch the import users job:

* Configure a database connection to import the users into and enable it for at least one application.
* If you are importing passwords, make sure the passwords are hashed using one of the supported algorithms. Users with passwords hashed by unsupported algorithms will need to reset their password when they log in for the first time after the bulk import.
* If you are importing <Tooltip tip="Multi-factor authentication (MFA): User authentication process that uses a factor in addition to username and password such as a code via SMS." cta="View Glossary" href="/docs/glossary?term=MFA">MFA</Tooltip> enrollments, make sure they are a supported type: `email`, `phone`, or `totp`.
* [Get a Management API token](/docs/secure/tokens/access-tokens/management-api-access-tokens) for job endpoint requests.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  If you are using an export file from an Auth0 tenant, you must convert the exported file from `ndjson` to [JSON](/docs/manage-users/user-migration/bulk-user-exports#json-compatible-format). To keep the same user IDs, you must remove the `auth0| prefix` from all imported user IDs.

  The import process automatically adds the `auth0| prefix` to the imported user IDs. If you do not remove the `auth0|` prefix before importing, the user IDs return as `auth0|auth0|...`
</Callout>

## Create users JSON file

Create a JSON file with the user data you want to import into Auth0. How you export user data to a JSON file will vary depending on your existing user database. The <Tooltip tip="Management API: A product to allow customers to perform administrative tasks." cta="View Glossary" href="/docs/glossary?term=Management+API">Management API</Tooltip> endpoint expects sections of the JSON file. So instead of using `fs.readFileSync`, it requires `fs.createReadStream`. The endpoint expects a piped read stream instead of the whole JSON file.

To learn more about the JSON file schema and see examples, read [Bulk Import Database Schema and Examples](/docs/manage-users/user-migration/bulk-user-import-database-schema-and-examples).

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  The file size limit for a bulk import is 500KB. You will need to start multiple imports if your data exceeds this size.
</Callout>

## Request bulk user import

To start a bulk user import job, make a `POST` request to the [Create Import Users Job](https://auth0.com/docs/api/management/v2#!/Jobs/post_users_imports) endpoint. Be sure to replace the `MGMT_API_ACCESS_TOKEN`, `USERS_IMPORT_FILE.json`, `CONNECTION_ID`, and `EXTERNAL_ID` placeholder values with your Management API <Tooltip tip="Access Token: Authorization credential, in the form of an opaque string or JWT, used to access an API." cta="View Glossary" href="/docs/glossary?term=Access+Token">Access Token</Tooltip>, users JSON file, database [connection ID](/docs/authenticate/identity-providers/locate-the-connection-id), and external ID, respectively.

<AuthCodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://{yourDomain}/api/v2/jobs/users-imports' \
    --header 'authorization: Bearer MGMT_API_ACCESS_TOKEN' \
    --form users=@USERS_IMPORT_FILE.json \
    --form connection_id=CONNECTION_ID \
    --form external_id=EXTERNAL_ID
  ```

  ```csharp C# theme={null}
  var client = new RestClient("https://{yourDomain}/api/v2/jobs/users-imports");
  var request = new RestRequest(Method.POST);
  request.AddHeader("authorization", "Bearer MGMT_API_ACCESS_TOKEN");
  request.AddHeader("content-type", "multipart/form-data; boundary=---011000010111000001101001");
  request.AddParameter("multipart/form-data; boundary=---011000010111000001101001", "-----011000010111000001101001\r
  Content-Disposition: form-data; name="users"; filename="USERS_IMPORT_FILE.json"\r
  Content-Type: text/json\r
  \r
  \r
  -----011000010111000001101001\r
  Content-Disposition: form-data; name="connection_id"\r
  \r
  CONNECTION_ID\r
  -----011000010111000001101001\r
  Content-Disposition: form-data; name="external_id"\r
  \r
  EXTERNAL_ID\r
  -----011000010111000001101001--\r
  ", ParameterType.RequestBody);
  IRestResponse response = client.Execute(request);
  ```

  ```go Go theme={null}
  package main

  import (
  	"fmt"
  	"strings"
  	"net/http"
  	"io/ioutil"
  )

  func main() {

  	url := "https://{yourDomain}/api/v2/jobs/users-imports"

  	payload := strings.NewReader("-----011000010111000001101001\r
  Content-Disposition: form-data; name="users"; filename="USERS_IMPORT_FILE.json"\r
  Content-Type: text/json\r
  \r
  \r
  -----011000010111000001101001\r
  Content-Disposition: form-data; name="connection_id"\r
  \r
  CONNECTION_ID\r
  -----011000010111000001101001\r
  Content-Disposition: form-data; name="external_id"\r
  \r
  EXTERNAL_ID\r
  -----011000010111000001101001--\r
  ")

  	req, _ := http.NewRequest("POST", url, payload)

  	req.Header.Add("authorization", "Bearer MGMT_API_ACCESS_TOKEN")
  	req.Header.Add("content-type", "multipart/form-data; boundary=---011000010111000001101001")

  	res, _ := http.DefaultClient.Do(req)

  	defer res.Body.Close()
  	body, _ := ioutil.ReadAll(res.Body)

  	fmt.Println(res)
  	fmt.Println(string(body))

  }
  ```

  ```java Java theme={null}
  HttpResponse<String> response = Unirest.post("https://{yourDomain}/api/v2/jobs/users-imports")
    .header("authorization", "Bearer MGMT_API_ACCESS_TOKEN")
    .header("content-type", "multipart/form-data; boundary=---011000010111000001101001")
    .body("-----011000010111000001101001\r
  Content-Disposition: form-data; name="users"; filename="USERS_IMPORT_FILE.json"\r
  Content-Type: text/json\r
  \r
  \r
  -----011000010111000001101001\r
  Content-Disposition: form-data; name="connection_id"\r
  \r
  CONNECTION_ID\r
  -----011000010111000001101001\r
  Content-Disposition: form-data; name="external_id"\r
  \r
  EXTERNAL_ID\r
  -----011000010111000001101001--\r
  ")
    .asString();
  ```

  ```javascript Node.JS theme={null}
  var axios = require("axios").default;

  var options = {
    method: 'POST',
    url: 'https://{yourDomain}/api/v2/jobs/users-imports',
    headers: {
      authorization: 'Bearer MGMT_API_ACCESS_TOKEN',
      'content-type': 'multipart/form-data; boundary=---011000010111000001101001'
    },
    data: '-----011000010111000001101001\r
  Content-Disposition: form-data; name="users"; filename="USERS_IMPORT_FILE.json"\r
  Content-Type: text/json\r
  \r
  \r
  -----011000010111000001101001\r
  Content-Disposition: form-data; name="connection_id"\r
  \r
  CONNECTION_ID\r
  -----011000010111000001101001\r
  Content-Disposition: form-data; name="external_id"\r
  \r
  EXTERNAL_ID\r
  -----011000010111000001101001--\r
  '
  };

  axios.request(options).then(function (response) {
    console.log(response.data);
  }).catch(function (error) {
    console.error(error);
  });
  ```

  ```php PHP theme={null}
  $curl = curl_init();

  curl_setopt_array($curl, [
    CURLOPT_URL => "https://{yourDomain}/api/v2/jobs/users-imports",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => "-----011000010111000001101001\r
  Content-Disposition: form-data; name="users"; filename="USERS_IMPORT_FILE.json"\r
  Content-Type: text/json\r
  \r
  \r
  -----011000010111000001101001\r
  Content-Disposition: form-data; name="connection_id"\r
  \r
  CONNECTION_ID\r
  -----011000010111000001101001\r
  Content-Disposition: form-data; name="external_id"\r
  \r
  EXTERNAL_ID\r
  -----011000010111000001101001--\r
  ",
    CURLOPT_HTTPHEADER => [
      "authorization: Bearer MGMT_API_ACCESS_TOKEN",
      "content-type: multipart/form-data; boundary=---011000010111000001101001"
    ],
  ]);

  $response = curl_exec($curl);
  $err = curl_error($curl);

  curl_close($curl);

  if ($err) {
    echo "cURL Error #:" . $err;
  } else {
    echo $response;
  }
  ```

  ```python Python theme={null}
  import http.client

  conn = http.client.HTTPSConnection("")

  payload = "-----011000010111000001101001\r
  Content-Disposition: form-data; name="users"; filename="USERS_IMPORT_FILE.json"\r
  Content-Type: text/json\r
  \r
  \r
  -----011000010111000001101001\r
  Content-Disposition: form-data; name="connection_id"\r
  \r
  CONNECTION_ID\r
  -----011000010111000001101001\r
  Content-Disposition: form-data; name="external_id"\r
  \r
  EXTERNAL_ID\r
  -----011000010111000001101001--\r
  "

  headers = {
      'authorization': "Bearer MGMT_API_ACCESS_TOKEN",
      'content-type': "multipart/form-data; boundary=---011000010111000001101001"
      }

  conn.request("POST", "/{yourDomain}/api/v2/jobs/users-imports", payload, headers)

  res = conn.getresponse()
  data = res.read()

  print(data.decode("utf-8"))
  ```

  ```ruby Ruby theme={null}
  require 'uri'
  require 'net/http'
  require 'openssl'

  url = URI("https://{yourDomain}/api/v2/jobs/users-imports")

  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE

  request = Net::HTTP::Post.new(url)
  request["authorization"] = 'Bearer MGMT_API_ACCESS_TOKEN'
  request["content-type"] = 'multipart/form-data; boundary=---011000010111000001101001'
  request.body = "-----011000010111000001101001\r
  Content-Disposition: form-data; name="users"; filename="USERS_IMPORT_FILE.json"\r
  Content-Type: text/json\r
  \r
  \r
  -----011000010111000001101001\r
  Content-Disposition: form-data; name="connection_id"\r
  \r
  CONNECTION_ID\r
  -----011000010111000001101001\r
  Content-Disposition: form-data; name="external_id"\r
  \r
  EXTERNAL_ID\r
  -----011000010111000001101001--\r
  "

  response = http.request(request)
  puts response.read_body
  ```
</AuthCodeGroup>

| Parameter               | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `users`                 | File in JSON format that contains the users to import.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `connection_id`         | ID of the connection to which users will be inserted. You can retrieve the ID using the [GET /api/v2/connections](https://auth0.com/docs/api/management/v2#!/Connections/get_connections) endpoint.                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `upsert`                | Boolean value; `false` by default. When set to `false`, pre-existing users that match on email address, user ID, phone, or username will fail. When set to true, pre-existing users that match on email address will be updated, but only with upsertable attributes. For a list of user profile fields that can be upserted during import, see [User Profile Structure: User profile attributes](/docs/manage-users/user-accounts/user-profiles/user-profile-structure#user-profile-attributes). Note: Providing a duplicated user entry in the import file will cause an error. In this case, Auth0 will not do an insert followed by an update. |
| `external_id`           | Optional user-defined string that can be used to correlate multiple jobs. Returned as part of the job status response.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `send_completion_email` | Boolean value; `true` by default. When set to `true`, sends a completion email to all tenant owners when the import job is finished. If you do *not* want emails sent, you must explicitly set this parameter to `false`.                                                                                                                                                                                                                                                                                                                                                                                                                          |

If the request is successful, you'll receive a response similar to the following:

```json lines theme={null}
{
  "status": "pending",
  "type": "users_import",
  "created_at": "",
  "id": "job_abc123",
  "connection_id": "CONNECTION_ID",
  "upsert": false,
  "external_id": "EXTERNAL_ID",
  "send_completion_email": true
}
```

The returned entity represents the import job.

When the user import job finishes and if `send_completion_email` was set to `true`, the tenant administrator(s) will get an email notifying them that job either failed or succeeded. An email for a job that failed might notify the administrator(s) that it failed to parse the users JSON file when importing users.

### Concurrent import jobs

The [Create Import Users Job](https://auth0.com/docs/api/management/v2#!/Jobs/post_users_imports) endpoint has a limit of two concurrent import jobs. Requesting additional jobs while there are two pending returns a `429 Too Many Requests` response:

```json lines theme={null}
{
  "statusCode": 429,
  "error": "Too Many Requests",
  "message": "There are 2 active import users jobs, please wait until some of them are finished and try again
}
```

## Check job status

To check a job's status, make a `GET` request to the [Get a Job](https://auth0.com/docs/api/management/v2#!/Jobs/get_jobs_by_id) endpoint. Be sure to replace the `MGMT_API_ACCESS_TOKEN` and `JOB_ID` placeholder values with your Management API Access Token and user import job ID.

<AuthCodeGroup>
  ```bash cURL theme={null}
  curl --request GET \
    --url 'https://{yourDomain}/api/v2/jobs/JOB_ID' \
    --header 'authorization: Bearer MGMT_API_ACCESS_TOKEN' \
    --header 'content-type: application/json'
  ```

  ```csharp C# theme={null}
  var client = new RestClient("https://{yourDomain}/api/v2/jobs/JOB_ID");
  var request = new RestRequest(Method.GET);
  request.AddHeader("content-type", "application/json");
  request.AddHeader("authorization", "Bearer MGMT_API_ACCESS_TOKEN");
  IRestResponse response = client.Execute(request);
  ```

  ```go Go theme={null}
  package main

  import (
  	"fmt"
  	"net/http"
  	"io/ioutil"
  )

  func main() {

  	url := "https://{yourDomain}/api/v2/jobs/JOB_ID"

  	req, _ := http.NewRequest("GET", url, nil)

  	req.Header.Add("content-type", "application/json")
  	req.Header.Add("authorization", "Bearer MGMT_API_ACCESS_TOKEN")

  	res, _ := http.DefaultClient.Do(req)

  	defer res.Body.Close()
  	body, _ := ioutil.ReadAll(res.Body)

  	fmt.Println(res)
  	fmt.Println(string(body))

  }
  ```

  ```java Java theme={null}
  HttpResponse<String> response = Unirest.get("https://{yourDomain}/api/v2/jobs/JOB_ID")
    .header("content-type", "application/json")
    .header("authorization", "Bearer MGMT_API_ACCESS_TOKEN")
    .asString();
  ```

  ```javascript Node.JS theme={null}
  var axios = require("axios").default;

  var options = {
    method: 'GET',
    url: 'https://{yourDomain}/api/v2/jobs/JOB_ID',
    headers: {
      'content-type': 'application/json',
      authorization: 'Bearer MGMT_API_ACCESS_TOKEN'
    }
  };

  axios.request(options).then(function (response) {
    console.log(response.data);
  }).catch(function (error) {
    console.error(error);
  });
  ```

  ```php PHP theme={null}
  $curl = curl_init();

  curl_setopt_array($curl, [
    CURLOPT_URL => "https://{yourDomain}/api/v2/jobs/JOB_ID",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
      "authorization: Bearer MGMT_API_ACCESS_TOKEN",
      "content-type: application/json"
    ],
  ]);

  $response = curl_exec($curl);
  $err = curl_error($curl);

  curl_close($curl);

  if ($err) {
    echo "cURL Error #:" . $err;
  } else {
    echo $response;
  }
  ```

  ```python Python theme={null}
  import http.client

  conn = http.client.HTTPSConnection("")

  headers = {
      'content-type': "application/json",
      'authorization': "Bearer MGMT_API_ACCESS_TOKEN"
      }

  conn.request("GET", "/{yourDomain}/api/v2/jobs/JOB_ID", headers=headers)

  res = conn.getresponse()
  data = res.read()

  print(data.decode("utf-8"))
  ```

  ```ruby Ruby theme={null}
  require 'uri'
  require 'net/http'
  require 'openssl'

  url = URI("https://{yourDomain}/api/v2/jobs/JOB_ID")

  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE

  request = Net::HTTP::Get.new(url)
  request["content-type"] = 'application/json'
  request["authorization"] = 'Bearer MGMT_API_ACCESS_TOKEN'

  response = http.request(request)
  puts response.read_body
  ```
</AuthCodeGroup>

Depending on the status of the user import job, you'll receive a response similar to one of the following:

**Pending**

```json lines theme={null}
{
  "status": "pending",
  "type": "users_import",
  "created_at": "",
  "id": "job_abc123",
  "connection_id": "CONNECTION_ID",
  "external_id": "EXTERNAL_ID"
}
```

**Completed**

If a job is completed, the job status response will include totals of successful, failed, inserted, and updated records.

```json lines theme={null}
{
  "status": "completed",
  "type": "users_import",
  "created_at": "",
  "id": "job_abc123",
  "connection_id": "CONNECTION_ID",
  "external_id": "EXTERNAL_ID",
  "summary": {
    "failed": 0,
    "updated": 0,
    "inserted": 1,
    "total": 1
  }
}
```

**Failed**

If there is an error in the job, it will return as failed. However, note that invalid user information, such as an invalid email, will not make the entire job fail.

```json lines theme={null}
{
  "status": "failed",
  "type": "users_import",
  "created_at": "",
  "id": "job_abc123",
  "connection_id": "CONNECTION_ID",
  "external_id": "EXTERNAL_ID",
}
```

To learn details for failed entries see **Retrieve failed entries** below.

## Job timeouts

All user import jobs timeout after **two (2) hours**. If your job does not complete within this time frame, it is marked as failed.

Furthermore, all of your job-related data is automatically deleted after 24 hours and cannot be accessed afterward. As such, **we strongly recommend storing job results using the storage mechanism of your choice**.

## Retrieve failed entries

<Warning>
  All of the job-related data is automatically deleted after 24 hours and cannot be accessed thereafter. Because of this, we strongly recommend storing the job results using the storage mechanism of your choice.
</Warning>

If there were errors in the user import job, you can get the error details by making a `GET` request to the [Get Job Error Details](https://auth0.com/docs/api/management/v2#!/Jobs/get_errors) endpoint. Be sure to replace the `MGMT_API_ACCESS_TOKEN` and `JOB_ID` placeholder values with your Management API Access Token and user import job ID.

<AuthCodeGroup>
  ```bash cURL theme={null}
  curl --request GET \
    --url 'https://{yourDomain}/api/v2/jobs/JOB_ID/errors' \
    --header 'authorization: Bearer MGMT_API_ACCESS_TOKEN' \
    --header 'content-type: application/json'
  ```

  ```csharp C# theme={null}
  var client = new RestClient("https://{yourDomain}/api/v2/jobs/JOB_ID/errors");
  var request = new RestRequest(Method.GET);
  request.AddHeader("content-type", "application/json");
  request.AddHeader("authorization", "Bearer MGMT_API_ACCESS_TOKEN");
  IRestResponse response = client.Execute(request);
  ```

  ```go Go theme={null}
  package main

  import (
  	"fmt"
  	"net/http"
  	"io/ioutil"
  )

  func main() {

  	url := "https://{yourDomain}/api/v2/jobs/JOB_ID/errors"

  	req, _ := http.NewRequest("GET", url, nil)

  	req.Header.Add("content-type", "application/json")
  	req.Header.Add("authorization", "Bearer MGMT_API_ACCESS_TOKEN")

  	res, _ := http.DefaultClient.Do(req)

  	defer res.Body.Close()
  	body, _ := ioutil.ReadAll(res.Body)

  	fmt.Println(res)
  	fmt.Println(string(body))

  }
  ```

  ```java Java theme={null}
  HttpResponse<String> response = Unirest.get("https://{yourDomain}/api/v2/jobs/JOB_ID/errors")
    .header("content-type", "application/json")
    .header("authorization", "Bearer MGMT_API_ACCESS_TOKEN")
    .asString();
  ```

  ```javascript Node.JS theme={null}
  var axios = require("axios").default;

  var options = {
    method: 'GET',
    url: 'https://{yourDomain}/api/v2/jobs/JOB_ID/errors',
    headers: {
      'content-type': 'application/json',
      authorization: 'Bearer MGMT_API_ACCESS_TOKEN'
    }
  };

  axios.request(options).then(function (response) {
    console.log(response.data);
  }).catch(function (error) {
    console.error(error);
  });
  ```

  ```php PHP theme={null}
  $curl = curl_init();

  curl_setopt_array($curl, [
    CURLOPT_URL => "https://{yourDomain}/api/v2/jobs/JOB_ID/errors",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
      "authorization: Bearer MGMT_API_ACCESS_TOKEN",
      "content-type: application/json"
    ],
  ]);

  $response = curl_exec($curl);
  $err = curl_error($curl);

  curl_close($curl);

  if ($err) {
    echo "cURL Error #:" . $err;
  } else {
    echo $response;
  }
  ```

  ```python Python theme={null}
  import http.client

  conn = http.client.HTTPSConnection("")

  headers = {
      'content-type': "application/json",
      'authorization': "Bearer MGMT_API_ACCESS_TOKEN"
      }

  conn.request("GET", "/{yourDomain}/api/v2/jobs/JOB_ID/errors", headers=headers)

  res = conn.getresponse()
  data = res.read()

  print(data.decode("utf-8"))
  ```

  ```ruby Ruby theme={null}
  require 'uri'
  require 'net/http'
  require 'openssl'

  url = URI("https://{yourDomain}/api/v2/jobs/JOB_ID/errors")

  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE

  request = Net::HTTP::Get.new(url)
  request["content-type"] = 'application/json'
  request["authorization"] = 'Bearer MGMT_API_ACCESS_TOKEN'

  response = http.request(request)
  puts response.read_body
  ```
</AuthCodeGroup>

If the request is successful, you'll receive a response similar to the following. Sensitive fields such as `hash.value` will be redacted in the response.

```json lines theme={null}
[
    {
        "user": {
            "email": "test@test.io",
            "user_id": "7af4c65cb0ac6e162f081822422a9dde",
            "custom_password_hash": {
                "algorithm": "ldap",
                "hash": {
                    "value": "*****"
                }
            }
        },
        "errors": [
            {
                "code": "...",
                "message": "...",
                "path": "..."
            }
        ]
    }
]
```

Each error object will include an error code and a message explaining the error in more detail. The possible error codes are:

* ANY\_OF\_MISSING
* ARRAY\_LENGTH\_LONG
* ARRAY\_LENGTH\_SHORT
* CONFLICT
* CONFLICT\_EMAIL
* CONFLICT\_USERNAME
* CONNECTION\_NOT\_FOUND
* DUPLICATED\_USER
* ENUM\_MISMATCH
* FORMAT
* INVALID\_TYPE
* MAX\_LENGTH
* MAXIMUM
* MFA\_FACTORS\_FAILED
* MIN\_LENGTH
* MINIMUM
* NOT\_PASSED
* OBJECT\_REQUIRED
* PATTERN

## Best practices for large-scale migrations

When importing large user populations (requiring 10 or more jobs), follow these recommendations to ensure a successful migration:

### File size and chunking

Split user records into small chunks of less than 400KB per file. This allows for approximately 1,000 users per job with fewer than 10 metadata fields per user, while staying well under the 500KB file size limit.

### Job scheduling and concurrency

Since Auth0 restricts user imports to two concurrent jobs per tenant, use a job scheduler framework (such as [Bull](https://github.com/OptimalBits/bull) or [Agenda](https://github.com/agenda/agenda)) to:

* Schedule import jobs systematically
* Enforce the required concurrency limit
* Track import progress to restart where you left off if interrupted
* Maintain job history and current statuses

### Error handling strategy

* Do not interrupt the import process on single user failures. Import all users and handle issues afterward.
* Implement a "finalizer" job that reviews all spawned jobs and collects failed records into a new file.
* Fix any errors in the collected failed records and import them as a new job.
* Include a retry strategy to handle network connection drops and temporary failures.

### Upsert mode considerations

Use caution when enabling `upsert` mode:

* Imports with upsert are slower than standard imports.
* Upsert mode does not support merging of `user_metadata` or `app_metadata`. The existing metadata will be completely overwritten with new values.
* Only use upsert mode when you need to update existing users and understand these limitations.

### Data retention

Remember that all job-related data is automatically deleted after 24 hours. Store job results and error details using your own storage mechanism for long-term tracking and analysis.

## Learn more

* [Configure Automatic Migration from Your Database](/docs/manage-users/user-migration/configure-automatic-migration-from-your-database)
* [User Import / Export Extension](/docs/manage-users/user-migration/user-import-export-extension)
* [Bulk User Import Database Schema and Examples](/docs/manage-users/user-migration/bulk-user-import-database-schema-and-examples)
* [User Migration Scenarios](/docs/manage-users/user-migration/user-migration-scenarios)
