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 | /v1/employees |
| Base URL | https://smartway.pro/api |
| 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 in Keycloak.
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.
-
hrEmail is not sent by the external client; the BFF takes it from the Bearer token.
-
In the current implementation, Idempotency-Key is not used.
Request
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
| 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 Keycloak; false creates the employee without that access. |
| 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,
"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,
"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
}
Response fields
Employee
| Field | Type | Description |
|---|---|---|
| employeeId | int64 | Employee ID. |
| candidateId | int64 | Linked candidate ID. |
| 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. |
Business logic
-
The BFF determines companyId only from the Bearer token.
-
The BFF takes 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 in Keycloak and enables access to the personal account.
-
active = false creates an employee without access to the personal account, that is, without a user in Keycloak.
-
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
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. |
| 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. |
| The client sends fullName | fullName is not described in the create request. The server generates fullName from name + surname. |
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. |
| 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 BFF error. |
| 503 Service Unavailable | Internal integration failure BFF -> back2. |
Usage
-
Create an active employee with access to the personal account: active = true.
-
Create an employee without access to the personal account: active = false.
-
Send multiple departments or job titles with a defined primary value.
-
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 gender with a value other than Male/Female | Use only Male or Female. |
| Sending idCompany or hrEmail | Do not send these values; the BFF takes 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 in Keycloak 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 in Keycloak.
What happens if the email already exists?
The API returns 409 Conflict.
Do I need to send hrEmail?
No. The BFF takes hrEmail from the Bearer token.