How do you create an employee via the API?
POST /v1/employees creates an employee. Required body fields: email, name, surname, gender, and active. Access requires
the employees.write scope.
Endpoint
| Parameter | Value | | -------------- | ---------------------- | | Method | POST | | Path | /api/v1/employees | | Base
URL | https://smartway.pro | | Auth | Bearer token | | Required scope | employees.write |
Purpose
This endpoint is used to create a new employee within the company from the Bearer token.
The active value controls not only the business flag, but also the creation or absence of a linked user on the
authorisation server.
Prerequisites
The client must send a valid Bearer token.
The token must contain company context.
The token must contain the employees.write scope.
idCompany is not sent in the body or query string.
Request
Body parameters
| Field | Type | Required | Description | | ------------- | -------- | ------------ |
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| | email | string | yes | Employee email. | | name | string | yes | Employee first name. This is the source of truth
for generating fullName during creation. | | surname | string | yes | Employee surname. This is the source of truth for
generating fullName during creation. | | gender | string | yes | Only Male or Female are allowed. | | active | boolean |
yes | Only JSON-boolean values true or false are allowed. true creates or synchronises personal account access through
the authorisation server; false creates the employee without that access. | | manager | boolean | no | Department
manager role flag. Only JSON-boolean values true or false are allowed; true creates or synchronises access with the
employee and department manager roles, even if active=false. | | department | string | no | Primary department. If not
provided, null is stored. | | departments | string[] | no | Set of departments. If not provided, the collection remains
empty. | | jobTitle | string | no | Primary job title. If not provided, null is stored. | | jobTitles | string[] | no |
Set of job titles. If not provided, the collection remains empty. | | phone | string | no | Phone number. If not
provided, null is stored. | | notes | string | no | Notes. If not provided, null is stored. |
curl example
Create an employee with primary fields and arrays
curl -X POST 'https://smartway.pro/api/v1/employees' \
-H 'Authorization: Bearer <access_token>' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
--data-binary @- <<'JSON'
{
"email": "employee@example.com",
"name": "Ivan",
"surname": "Petrenko",
"gender": "Female",
"active": false,
"manager": false,
"department": "Management",
"departments": ["КЛ"],
"jobTitle": "Manager",
"jobTitles": ["Coordinator"],
"phone": "+380000000000",
"notes": "New employee from public API"
}
JSON
Create an employee only with departments/jobTitles arrays
curl -X POST 'https://smartway.pro/api/v1/employees' \
-H 'Authorization: Bearer <access_token>' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
--data-binary @- <<'JSON'
{
"email": "employee@example.com",
"name": "Ivan",
"surname": "Petrenko",
"gender": "Male",
"active": true,
"manager": true,
"departments": ["Management", "КЛ"],
"jobTitles": ["Manager", "Coordinator"],
"phone": "+380000000000",
"notes": "New employee from public API"
}
JSON
Response
Successful response: 201 Created. Returns the created Employee.
{
"employeeId": 4432,
"candidateId": 10748,
"email": "employee@example.com",
"fullName": "Ivan Petrenko",
"name": "Ivan",
"surname": "Petrenko",
"gender": "Female",
"department": "Management",
"departments": [
"Management",
"КЛ"
],
"jobTitle": "Manager",
"jobTitles": [
"Coordinator",
"Manager"
],
"phone": "+380000000000",
"active": false,
"manager": false
}
Response fields
Employee
| Field | Type | Description | | ------------- | -------- |
---------------------------------------------------------------------- | | employeeId | int64 | Employee ID. | |
candidateId | int64 | Linked candidate ID. | | email | string | Employee email. | | fullName | string | Full name
generated by the server from name + surname. | | name | string | First name. | | surname | string | Surname. | | gender
| string | Gender. | | department | string | Primary department. | | departments | string[] | Set of departments. | |
jobTitle | string | Primary job title. | | jobTitles | string[] | Set of job titles. | | phone | string | Phone number.
| | active | boolean | Active flag. | | manager | boolean | Department manager role flag. true means the employee has
this role. |
Business logic
The API determines companyId only from the Bearer token.
The API determines hrEmail from the Bearer token. hrEmail equals the email of the user with the HRADMIN role who created
or rotated the active company API key.
If the active API key is rotated by another HRADMIN, subsequent create operations automatically start using that
HRADMIN's hrEmail.
Repeating the same POST does not create a duplicate if an employee with the same email already exists; the API returns
409 Conflict.
gender accepts only Male or Female.
active accepts only JSON-boolean true or false.
active = true creates or synchronises the linked user account on the authorisation server and enables access to the
personal account.
active = false creates an employee without access to the personal account, that is, without a user account on the
authorisation server.
manager = true creates or synchronises access with the employee and department manager roles. If active = false is sent
at the same time, manager access takes priority and the employee is created as an active account user.
manager = false or omitting the manager field does not assign the department manager role.
manager is returned in the Employee response; after creation, this role can be changed through PATCH
/v1/employees/{employeeId}.
fullName in the response is generated by the server from name + surname.
If only departments or jobTitles is provided, the first array element becomes the primary value in department or
jobTitle.
If both a single field and an array are provided, the single field takes priority as primary, and the array is
supplemented with unique values.
If department, jobTitle, phone, or notes is not provided, null is stored in the corresponding single field.
If departments or jobTitles is not provided, the corresponding collection remains empty.
In the response, departments and jobTitles are returned in a stable sorted order.
Edge cases
| Scenario | API behaviour | | -------------------------------------------- |
----------------------------------------------------------------------------------- | | A required field is missing |
The API returns 400 Bad Request. | | gender is not Male or Female | The API returns 400 Bad Request with an explanation.
| | active is sent as a string or number | The API returns 400 Bad Request because active must be JSON-boolean. | |
manager is sent as a string or number | The API returns 400 Bad Request because manager must be JSON-boolean. | |
active=false and manager=true | Manager access takes priority; the employee is created as active. | | email already
exists | The API returns 409 Conflict. | | Only departments is provided | The first array element becomes department. |
| department and departments are provided | department remains primary, and departments is supplemented with unique
values. | | department or jobTitle is not provided | null is stored in the corresponding single field. | | departments
or jobTitles is not provided | The corresponding collection remains empty. |
Errors
Error responses
| HTTP status | When it occurs | | --------------------------- |
---------------------------------------------------------------------------------------------- | | 400 Bad Request | At
least one required parameter is missing: email, name, surname, gender, or active. | | 400 Bad Request | gender is not
Male or Female. | | 400 Bad Request | active is not a JSON-boolean value true or false. | | 400 Bad Request | manager is
not a JSON-boolean value true or false. | | 401 Unauthorized | Bearer token is missing or invalid. | | 403 Forbidden |
Insufficient permissions or token without company context. | | 409 Conflict | An Employee with this email already
exists. | | 500 Internal Server Error | Unexpected API error. | | 503 Service Unavailable | Internal server integration
failure. |
Usage
Create an active employee with access to the personal account: active = true.
Create an employee without access to the personal account: active = false.
Create an employee with the department manager role: manager = true.
Synchronise employees from an external HR system.
Common mistakes
Typical integration mistakes
| Common mistake | Correct approach | | -------------------------------------------------------- |
------------------------------------------------------------------------ | | Sending active as the string "true" or
"false" | Send true or false as a JSON boolean. | | Sending manager as the string "true" or "false" | Send true or false
as a JSON boolean. | | Sending gender with a value other than Male/Female | Use only Male or Female. | | Sending
idCompany or hrEmail | Do not send these values; the API determines them from the Bearer token. | | Expecting
idempotency through Idempotency-Key | In the current implementation, Idempotency-Key is not used. | | Sending fullName
instead of name and surname | Send name and surname; the server generates fullName. |
FAQ
Which fields are required to create an employee?
email, name, surname, gender, and active.
What does active = true do?
The server creates or synchronises the linked user account on the authorisation server and enables access to the
personal account.
What does active = false do?
The employee is created without access to the personal account, that is, without a user account on the authorisation
server.
What does manager = true do?
The server creates or synchronises access with the employee and department manager roles. If active = false is sent at
the same time, the employee is still created as an active account user.
What happens if the email already exists?
The API returns 409 Conflict.
Do I need to send hrEmail?
No. The API determines hrEmail from the Bearer token.