Bulk import
A bulk import creates or updates many users from one CSV file. It works in two steps, and nothing in Active Directory changes before the second one:
- Upload and preview. Vertex reads the file, checks every row against the directory and shows what each row would do: create, update or invalid (with the reasons).
- Commit. You confirm with a step-up; Vertex applies the valid rows and skips the invalid ones. A result file lists the outcome of every row.
Imports need the Tenant admin role and the users write switch.
The API calls are given in brackets (Vertex API).
The file
- Encoding: UTF-8. A byte-order mark (BOM, as Excel writes it) is fine.
- Delimiter:
;or,, detected from the header line (whichever occurs more often there). Values that contain the delimiter, quotes or line breaks are quoted with", as usual in CSV. - Header row: required, the first line. Column names are case-insensitive; their order does not matter.
- Rows: at most 10,000 users per file (the request is at most 5 MB). Empty lines are skipped. Line numbers count the header as line 1.
- Values are trimmed, except passwords, which keep their spaces.
The template (GET …/imports/template) shows the common columns:
sAMAccountName;password;givenName;sn;displayName;ou;mail;department;title;groups;enabled;mustChangePassword
ipetrov;Change-Me-2026!;Ivan;Petrov;Ivan Petrov;OU=Students,OU=School,DC=school,DC=local;[email protected];10A;Student;Students;true;true
Columns
| Column | Aliases | Meaning |
|---|---|---|
sAMAccountName | sam, username, login, logon | The logon name. Required. It identifies the user: rows are matched to existing users by it. At most 20 characters, none of " / \ [ ] : ; | = , + * ? < > @. |
password | The password. Optional; see Defaults. At most 256 characters. | |
ou | path | The DN of the OU for a new user, or to move an existing user to. Must be a managed OU or below one. |
name | cn | The CN of a new user (at most 64 characters). Not used for existing users. |
givenName | firstName | First name. |
sn | surname, lastName | Last name. |
displayName | Display name. | |
userPrincipalName | upn | UPN (name@suffix). |
enabled | true/false (see below). | |
mustChangePassword | changePasswordAtLogon | Must change the password at next logon: true/false. |
groups | memberOf | Groups to add the user to, separated by ; (see Groups). |
email | Written to mail. | |
| common attributes | These may be used by their LDAP names: mail, description, department, title, company, telephoneNumber, mobile, homePhone, ipPhone, physicalDeliveryOfficeName, employeeID, employeeNumber, employeeType, initials, streetAddress, l, st, postalCode, co, c, manager, info, wWWHomePage, homeDirectory, homeDrive, profilePath. | |
attr:<ldapName> | Any other attribute by its LDAP display name, for example attr:extensionAttribute1 or attr:employeeType. Binary values as b64:<base64>. Attributes on the deny list are refused. |
- A column name Vertex does not know stops the upload (
unknown_columns; useattr:<ldapName>for other attributes); so do a column that appears twice (duplicate_column), a missingsAMAccountNamecolumn (missing_column) and a deniedattr:column (invalid_column). - Each attribute column gives one value. An empty cell leaves the attribute as it is.
- Booleans (
enabled,mustChangePassword):true,yes,y,1,on,даorfalse,no,n,0,off,не(any case); an empty cell means "not given".
Groups
The groups cell lists groups separated by ;. Each group may be given
by its DN, its name or its logon name (case-insensitive). Only
groups below the managed OUs that are not protected can be used; any
other name makes the row invalid (unknown group …). At most 100 groups
per row.
When the file itself is separated by ;, a cell with several groups must
be quoted:
sAMAccountName;givenName;sn;groups
mivanova;Maria;Ivanova;"Students;Class 10A"
Groups are only added: an import never removes a user from a group.
Modes
| Mode | A new logon name | An existing logon name |
|---|---|---|
create | Created | Invalid (a user with this logon name exists) |
update | Invalid (no user with this logon name) | Updated |
upsert | Created | Updated |
An existing user that is outside the managed OUs or protected makes its row invalid in every mode.
Defaults
Options of the import fill in what the file leaves out:
| Option | Applies to | Default |
|---|---|---|
Default OU (default_ou) | New users without ou | The settings' default user OU. Without either, the row is invalid. |
UPN suffix (upn_suffix) | New users without userPrincipalName | The settings' UPN suffix: <logon name>@<suffix>. |
Enabled (enabled) | New users without an enabled value | Enabled when a password is given, else disabled. With the option set, a user is enabled only if the option is on and the row has a password. |
Must change password (must_change_password) | New users without the column | Yes. |
For a new user, the name (CN) is name, else "first name last name",
else the logon name. An enabled value of true without a password makes
the row invalid (an enabled new user needs a password).
Updating an existing user:
- attributes, UPN, first, last and display name are written only where they differ from the directory (a row with no difference ends as unchanged);
- a
passwordresets the password; mustChangePasswordandenabledare applied when given;- an
oudifferent from the user's moves the user there; groupsadds the user to groups it is not in yet;nameis ignored (existing users are not renamed).
Preview
Upload the file (POST …/imports with csv, filename, mode and
options). The answer is the validated import with its counters:
total, invalid, to_create and to_update. Its rows
(GET …/imports/{importID}/rows, filterable by action and status)
show each row as parsed, without the password (has_password says
whether one was given), its action and its problems, for example:
- sAMAccountName is invalid, the same sAMAccountName as line 7;
- ou … is outside the managed OUs, no ou (and no default OU);
- userPrincipalName is invalid, name is invalid, password is too long;
- unknown group Teachers;
- attribute "info" value too long;
- 4 values for 3 columns.
The preview is checked against Vertex's mirror; run a sync first if the
directory changed outside Vertex. The upload is recorded in the audit log
(directory.import.create).
Nothing has been written yet. Fix the file and upload it again, or
cancel the import (POST …/imports/{importID}/cancel), which discards
it and its passwords.
Commit
Commit (POST …/imports/{importID}/commit with a step_up_token)
applies the valid rows; invalid rows are marked skipped. An import can
be committed once, and only within 24 hours of the upload
(import_not_validated otherwise).
- The rows are sent to the connector in batches of up to 200 users
(
bulk.usersoperations), which run one after another. Each batch may run for up to an hour. - A committed import is one confirmed action: it does not count against the per-minute change limits. The connector's own cap does apply: each batch counts as many writes as it has rows; the default of 1,000 writes per minute fits a full batch (The local guard).
- Each row ends as created, updated, unchanged, failed
(with
error_codeanderror, for examplepassword_policyoralready_exists) or skipped. One failing row does not stop the others. - The import's counters (
created,updated,unchanged,failed) grow as the batches finish, and thevertex.importevent of the live stream announces each change. When no row is pending any more, the import is completed, or failed if every applied row failed. - If a whole batch fails (for example the connector's guard refuses it, or it expires before the connector runs it), all its rows are marked failed with the batch's error code.
- Passwords are kept encrypted until the import is committed or cancelled, handed to the connector once per batch, and never shown again.
Result file
GET …/imports/{importID}/result.csv returns every row with its outcome.
It is separated by ;, UTF-8 with a BOM (it opens in Excel), and never
contains passwords:
line;sAMAccountName;action;status;problems;error_code;error;objectGUID
2;ipetrov;create;created;;;;3f1c…
3;mivanova;update;unchanged;;;;9a0b…
4;gdimitrov;invalid;skipped;unknown group Teachers;;;
Cells that a spreadsheet would read as a formula (starting with =, +,
-, @) are prefixed with '.
Limits
| Limit | Value |
|---|---|
| Users per file | 10,000 |
| Request size | 5 MB |
| Users per batch on the connector | 200 |
| Groups per row | 100 |
| Time to commit after the upload | 24 hours |
| A batch waits for the connector at most | 6 hours |
| A batch runs at most | 1 hour |