For AI agents: markdown of this page — /docs-content-en/entities/users.md documentation index — /llms.txt
Employees
Manage Bitrix24 account employees: list, get by ID, invite a new one, update, deactivate. The entity stores an employee's contact data, position, department, and user fields (UF).
Bitrix24 API: user.*
Scope: user
Create employee
POST /v1/users
Creates a new employee in the Bitrix24 account. The minimum required field is email. Returns the ID and the full record of the just-created employee.
For integrations with user input,
POST /v1/users/inviteis more convenient: it validates email on the Vibecode side (EMAIL_REQUIRED,EMAIL_INVALID) and automatically setsdepartmentId: [1]for intranet employees. This endpoint is the low-level form; errors are propagated from Bitrix24 as-is.
Request fields (body)
| Parameter | Type | Req. | Description |
|---|---|---|---|
email |
string | yes | Email — must be unique across all employees in the Bitrix24 account |
name |
string | no | First name |
lastName |
string | no | Last name |
secondName |
string | no | Middle name |
workPosition |
string | no | Position |
workPhone |
string | no | Work phone |
personalPhone |
string | no | Personal phone |
personalMobile |
string | no | Mobile phone |
personalBirthday |
string | no | Date of birth (ISO 8601) |
personalGender |
string | no | Gender: M — male, F — female |
personalCity |
string | no | City |
departmentId |
number[] | conditional | Array of department IDs. For intranet employees it is required — without it Bitrix24 returns wrong_email. Not used for extranet (EXTRANET: "Y") |
xmlId |
string | no | External identifier |
EXTRANET |
string | no | "Y" for an extranet user. Then instead of departmentId you need SONET_GROUP_ID (array of workgroup IDs) |
SONET_GROUP_ID |
number[] | conditional | Array of workgroup IDs — required with EXTRANET: "Y". List: GET /v1/workgroups |
Full list — Employee fields. User fields (UF_*) are also accepted.
Examples
curl — personal key
curl -X POST "https://vibecode.bitrix24.com/v1/users" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "John",
"lastName": "Brown",
"email": "john.brown@example.com",
"workPosition": "Manager",
"departmentId": [1]
}'
curl — OAuth application
curl -X POST "https://vibecode.bitrix24.com/v1/users" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "John",
"lastName": "Brown",
"email": "john.brown@example.com",
"workPosition": "Manager",
"departmentId": [1]
}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/users', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'John',
lastName: 'Brown',
email: 'john.brown@example.com',
workPosition: 'Manager',
departmentId: [1],
}),
})
const { success, data } = await res.json()
console.log('User ID:', data.id)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/users', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'John',
lastName: 'Brown',
email: 'john.brown@example.com',
workPosition: 'Manager',
departmentId: [1],
}),
})
const { success, data } = await res.json()
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data.id |
number | ID of the created employee |
The response contains the full record with all employee fields — the same format as GET /v1/users/:id.
The employee card URL in Bitrix24 is built from id:
https://<portal>.bitrix24.com/company/personal/user/<id>/
<portal> — the Bitrix24 account domain. Access is restricted by the employee's rights in Bitrix24.
Response example
{
"success": true,
"data": {
"id": 1331,
"xmlId": "74668002",
"active": true,
"name": "John",
"lastName": "Brown",
"email": "john.brown@example.com",
"lastLogin": null,
"dateRegister": "2026-05-06T00:00:00.000Z",
"isOnline": false,
"timestampX": {},
"personalGender": null,
"personalBirthday": null,
"departmentId": [1],
"workPosition": "Manager",
"userType": "employee"
}
}
Error response example
400 — email is not passed or duplicates an existing employee:
{
"success": false,
"error": {
"code": "BITRIX_ERROR",
"message": "wrong_email",
"hint": "Bitrix24 `user.add` returns `wrong_email` for several distinct cases, not only malformed email: (a) the email is already used by ANOTHER Bitrix24 user globally — check with GET /v1/users?filter[EMAIL]=the-email first; (b) the email domain is not allowed by portal policy (some portals restrict external domains); (c) missing UF_DEPARTMENT for intranet users — it is required for intranet invites (try `UF_DEPARTMENT: [1]` for the root department); (d) for external users pass `EXTRANET: \"Y\"` + `SONET_GROUP_ID: [groupId]` instead of UF_DEPARTMENT. For a convenience wrapper, try POST /v1/users/invite which sets sensible defaults. If the email is valid and unused, ask the portal admin to check user-invite settings."
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | BITRIX_ERROR (wrong_email) |
Email is not passed, duplicates an existing employee, failed the portal domain policy, or departmentId is not specified for an intranet employee |
| 401 | TOKEN_MISSING |
The API key has no configured tokens |
| 403 | SCOPE_DENIED |
The API key lacks the user scope |
Full list of common API errors — Errors.
Known specifics
Email must be globally unique. Bitrix24 checks uniqueness across all employees in the Bitrix24 account including previously deactivated ones. Before creation — search via GET /v1/users?filter[EMAIL]=john.brown@example.com. If a record is found and deactivated, bring it back with PATCH /v1/users/:id { active: true } — this preserves the employee's action history and relations, unlike creating a duplicate.
Ambiguity of the wrong_email error. Bitrix24 returns wrong_email for several different situations: email already taken, domain forbidden by Bitrix24 account policy, departmentId not specified for an intranet employee, SONET_GROUP_ID for an external one. The message does not clarify which one. To separate these cases on the Vibecode side, use POST /v1/users/invite — the wrapper returns explicit codes (EMAIL_REQUIRED, EMAIL_INVALID, SONET_GROUP_ID_REQUIRED) before the request to Bitrix24.
See also
- Invite employee — a wrapper with validation and defaults
- Employee fields — full field list
- List employees — find existing ones
- Departments — source of
departmentId - Limits and optimization