The Zendesk API is often used to import users from other systems into a Zendesk Support instance. This article describes how. It assumes the user data was exported from a third party application such as QuickBooks to an Excel worksheet.

If your user data is stored in a SaaS (software as a service) application with its own API, you can modify the code so that it taps both APIs to transfer the data directly to Zendesk Support.

The scripting language used in the article is Python 3, a powerful but beginner-friendly programming language with a clear and readable syntax. If you work in another language, you should still be able to follow the code logic and adapt it to your script. The logic is similar in all languages.

Make sure to configure your account settings in Zendesk Support to get the results you want when the users are imported. For example, do you want welcome emails to be sent automatically to the new users? See Sending the email verification message to users you add .

Topics covered in this article:

Disclaimer: Zendesk provides this article for instructional purposes only. Zendesk does not support or guarantee the code. Zendesk also can't provide support for third-party technologies such as Python. Please post any issue in the comments section or search for a solution online.

Deciding to import users

In many cases, you don't have to do anything to import users into Zendesk Support. Most user accounts in Zendesk Support are created automatically when a customer submits a ticket for the first time.

To decide if you need to import users, look at how your Zendesk Support instance is set up. A Zendesk Support instance can be set up to be open to all users, restricted to a group of users with specific email domains, or closed to all users except the ones you specify.

  • If you have an open Zendesk Support instance , you don't need to import users. The site is accessible to the general public. A new user account is created in Zendesk Support when a user submits a ticket for the first time.
  • If you have a restricted Zendesk Support instance , where only users with email addresses in approved email domains can submit tickets, you don't need to import users either. A new user account is created automatically in Zendesk Support when a user from an approved email domain submits a ticket for the first time.
  • If you have a closed Zendesk Support instance , only the users that you add can sign in and submit tickets. A typical example is an IT support department.

Even if you have a closed Zendesk Support instance, you don't have to use the API to import users. You can use the bulk user import feature in the Zendesk Support admin interface. See Bulk importing users and organizations . Each option has its strengths and weaknesses. For example, the API only accepts up to 100 users per request while the bulk import feature accepts up to 2,000 users at a time. The bulk import feature however can't import certain data that the API can, such as the user's time zone, photo, and language preference.

Users API basics

The following endpoint in the Users API lets you import multiple users at once:

POST /api/v2/users/create_many.json

It creates up to 100 users per request.

Some systems may have more than one way to identify the user. Possible user identities include a secondary email address, a Twitter handle, or a phone number. To create users with multiple user identities, see Create user with multiple identities .

Extracting the user data from an Excel workbook

After exporting the customer data from your system to an Excel file, place the file where your script can access it.

In Python, you can use the xlrd (Excel Read) utility to extract data from Excel workbooks. To install it, run the following command at the command prompt:

$ pip install xlrd

pip is a utility for installing and managing Python packages. If the pip command doesn't work, see these instructions to download and install pip. If you have Python 3.4 or better, you already have pip.

Choose the properties you want to set for each user. See Users in the API docs for the properties you can set. You can also create custom user fields to accommodate your data. See Adding custom fields to users .

Assume you want to set the following properties for each user imported into Zendesk Support:

  • name (required)
  • email
  • user_fields , to accommodate a "Membership Level" field in your system

To include your "Membership Level" field, you create a custom user field in Zendesk Support. You specify member_level as its field key. With this information, you can specify the user_fields property in the API request as follows:

"user_fields": {"member_level": "gold"}

Assume the names, emails, and membership levels are contained in columns C , D , and H respectively in your Excel worksheet. Convert the column positions to index numbers, something programming languages have an easier time following. Because indexes typically start with 0, the C , D , and H columns correspond to indexes 2 , 3 , and 7 .

  • name - index 2
  • email - index 3
  • user_fields - index 7

Assuming the Excel file is named users_list.xlsx and it's located in the same folder as your script, you can extract the worksheet's data with the following code:

import xlrd
users_dict = {'users': []}book = xlrd.open_workbook('users_list.xlsx')sheet = book.sheet_by_name('Sheet1')
for row in range(1, sheet.nrows):    if sheet.row_values(row)[2]:        users_dict['users'].append(            {                'name': sheet.row_values(row)[2],                'email': sheet.row_values(row)[3],                'user_fields': {'member_level': sheet.row_values(row)[7]}            }        )

Number values : If a column in your Excel worksheet consists of integers (1, 2, 3), xlrd reads them as floats and adds a trailing 0 (1.0, 2.0, 3.0). (Excel treats all numbers as floats.) You must convert the values back to integers with the int() method when you extract the values. Example:

...    'locale_id': int(sheet.row_values(row)[5]),

How it works

The code extracts the values from the workbook into a data structure that matches the JSON format expected by the API. According to the API docs , the structure should look like this:

{  "users": [    {      "name": "Roger Wilco",      "email": "[email protected]",      "user_fields": {"member_level": "gold"}    },    {      "name": "Woger Rilco",      "email": "[email protected]",      "user_fields": {"member_level": "silver"}    },    {      ...    }  ]}

In Python, you match the JSON structure by creating a dictionary with one key named 'users' containing a list of dictionaries describing each user. Dictionaries are called hashes in Ruby and Perl, associative arrays in PHP, and object literals in JavaScript.

The script leads off by creating the top-level dictionary:

users_dict = {'users': []}

Next, it uses the xlrd utility to load the worksheet into memory so it can be processed:

book = xlrd.open_workbook('users_list.xlsx')sheet = book.sheet_by_name('Sheet1')

The script then iterates over each row in the worksheet:

for row in range(1, sheet.nrows):    ...

The Python range() function generates a list of numbers to iterate through the rows. For example, range(3) generates the list [0, 1, 2] . In this case, the first argument starts the list at 1 instead of the default 0 because the first row of the worksheet contains column headers that should be skipped. Omit the first argument if you don't have any headers in your worksheet. Example:

for row in range(sheet.nrows):    ...

The first line in the loop checks to make sure the name exists in the worksheet's cell:

if sheet.row_values(row)[2]:        ...

A name is required to create a user in Zendesk Support. If the cell is blank, the script ignores the row and moves to the next one.

Next, the script assigns the values from columns 2, 3, and 7 to a new dictionary, which is then appended to the 'users' list in the users_dict dictionary:

users_dict['users'].append(            {                'name': sheet.row_values(row)[2],                'email': sheet.row_values(row)[3],                'user_fields': {'member_level': sheet.row_values(row)[7]}            }        )

The row_values() method returns the value of the cell at the specified row number and column index -- the row variable and 2, 3, and 7 in this case.

After iterating through all the rows in the worksheet, the users_dict variable contains the name, email, and membership level of each user in the Excel file. You can test this by adding the following snippet flush left after the for loop:

for user in users_dict['users']:    print(user)

Delete the 2 lines when you're done testing.

Packaging the data in 100-user payloads

Because the Create Many Users endpoint only accepts up to 100 users at a time, the script needs to distribute the users across several payloads if the worksheet contains more than 100 users. You can distribute the users by adding the following code (in bold):

import json

payloads = []

for row in range(1, sheet.nrows):
    if sheet.row_values(row)[2]:
                'name': sheet.row_values(row)[2],
                'email': sheet.row_values(row)[3],
                'user_fields': {'user_level': sheet.row_values(row)[7]}

    if len(users_dict['users']) == 100:
        users_dict = {'users': []}

if users_dict['users']:

How it works

The script starts by importing the built-in json library:

import json

It'll use the library to convert the user data to the JSON format required by the Zendesk API.

Next, the script creates a payloads list to store the payloads to be created:

payloads = []

The script checks the size of the users_dict['users'] list during each interation of the for loop:

if len(users_dict['users']) == 100:

After each row in the worksheet, the list of users grows by one. When the list reaches 100 users ( len(users_dict['users']) == 100: ), the script converts the users_dict data structure to JSON and appends it to the payloads list:


It then resets the users_dict['users'] list:

users_dict = {'users': []}

Like a machine at a bottling plant, the script fills each payload to the top before filling the next empty bottle in line.

After the script iterates through all the rows in the worksheet, the users_dict['users'] list might still contain users because it never reached the 100-user limit. The script checks it one last time and creates a final payload if it finds any stragglers:

if users_dict['users']:    payloads.append(json.dumps(users_dict))

You can display the payloads by adding the following snippet flush left after the for loop:

for payload in payloads:    print(payload)

Delete the two lines when you're done testing.

Making the API requests

The payloads variable should now contain a list of JSON payloads ready to be sent to the API:

payloads = [  {"users": [{_user 1_}, {_user 2_}, ...]},  {"users": [{_user 101_}, {_user 102_}, ...]},  ... ]

You can update the script with the following code (in bold) to post each payload to the API to create the users in Zendesk Support:

import json
import xlrd
import requests

session = requests.Session()
session.headers = {'Content-Type': 'application/json'}
session.auth = '{your_zd_email}', '{your_zd_password}'
url = 'https://{your_subdomain}'

... # extracting the user data from Excel worksheet...
... # creating the payloads...

for payload in payloads:
    response =, data=payload)
    if response.status_code != 200:
        print('Import failed with status {}'.format(response.status_code))
    print('Successfully imported a batch of users')

Replace the {your_zd_email} , {your_zd_password} , and {your_subdomain} placeholders with your values. For security reasons, only enter your password when you're ready to run the script. Delete it when you're done.

How it works

The script starts by importing the requests library, a third-party Python library for making HTTP requests:

import requests

To install the library on your computer, use the following command on the command line:

$ pip install requests

Next, the code creates a requests session object and configures it with your authentication information. The session object is useful for making multiple requests, such as when making multiple POST requests when importing hundreds of users.

session = requests.Session()session.headers = {'Content-Type': 'application/json'}session.auth = '{your_zd_email}', '{your_zd_password}'

The endpoint is assigned to a variable:

url = 'https://{your_subdomain}'

For details, see Create Many Users in the API reference.

With the requests session configured, the script can iterate through the payloads list and post one payload at a time to Zendesk Support:

for payload in payloads:    response =, data=payload)    if response.status_code != 200:        print('Import failed with status {}'.format(response.status_code))        exit()    print('Successfully imported a batch of users')

Code complete

The following sample script assumes a spreadsheet named users_list.xlsx with text data in columns C, D, and H of a worksheet named Sheet1 . It was written tested using Python 3.

Learn more

Join the discussion about this article in the community.