Employees are the people on your roster: current employees and former employees. Use these endpoints to keep Jadiroon's employee records in sync with your ERP or HR system. Candidates have their own endpoints (see Candidates).
All endpoints sit under /api/v1 and need an API key (Authorization: Bearer jdr_live_…) created by your Workspace Admin in Settings → Integrations.
Endpoints
| Method and path | What it does | Permission |
|---|---|---|
GET /api/v1/employees | List employees, current and former (cursor pagination, updatedSince, external-id lookup) | people.view |
POST /api/v1/employees | Create an employee | people.act |
GET /api/v1/employees/{id} | Get one employee | people.view |
PATCH /api/v1/employees/{id} | Update an employee; omitted fields stay unchanged | people.act |
DELETE /api/v1/employees/{id} | Offboard an employee: the status becomes FORMER_EMPLOYEE and the record stays | people.act |
POST /api/v1/employees/{id}/archive | Archive an employee | people.act |
PUT /api/v1/employees/by-external/{system}/{externalId} | Create or update by your own system's id | people.act |
POST /api/v1/employees/bulk | Upsert up to 1,000 employees by external id, async (see Bulk upsert) | people.act |
people.act includes people.view. An id that belongs to a candidate, or to another workspace, returns 404 not_found.
The employee object
| Field | Type | Notes |
|---|---|---|
id | string | Jadiroon id. Ids differ between Jadiroon environments; link your records with externalRefs. |
status | string | EMPLOYEE or FORMER_EMPLOYEE. |
firstName, lastName | string | |
email, phone | string or null | Contact details. Employees' contact details are not masked. |
nationality | string or null | ISO 3166-1 alpha-2 code, for example SA. |
nationalId | string or null | National ID or Iqama number. |
employeeNumber | string or null | Your employee number. A business field; link records with externalRefs. |
gender | string or null | MALE or FEMALE. |
birthDate, startDate | ISO 8601 or null | |
managerId | string or null | The employee's manager (another employee). |
currentPositionId | string or null | The position the employee holds (see Positions). |
managementLevel | string or null | SENIOR_MANAGEMENT or INDIVIDUAL_CONTRIBUTOR. |
specialization, education | string or null | |
yearsExperience | integer or null | Total years of experience. |
govExperienceYears, civilServiceExperienceYears, entityExperienceYears | integer or null | Government, civil-service and in-entity experience. |
archivedAt | ISO 8601 or null | Set when the employee is archived. |
externalRefs | array | [{ system, externalId }] links to your systems. |
createdAt, updatedAt | ISO 8601 |
Creating and updating
POST needs firstName and lastName; every other field is optional. status defaults to EMPLOYEE; send FORMER_EMPLOYEE to load a past employee. Unknown fields are rejected with 422 validation_failed.
manager and currentPosition name the record by Jadiroon id or by your own id, and null clears them:
{
"manager": { "externalSystem": "oracle-hcm", "externalId": "EMP-1001" },
"currentPosition": { "id": "cmv…" }
}
The manager must be an employee (current or former) of your workspace and the position must belong to your workspace; otherwise the response is 422 unresolved_reference. Other checks follow the app's rules:
409 conflictwithdetails.reasonposition_fullwhen the position has no free seat.409 conflictwithdetails.reasonduplicate_personwhen another active person in the workspace has the same email, national ID / Iqama or employee number (on create).422 validation_failedwithdetails.reason, for exampleself_manager(an employee can't manage themselves) orinvalid_nationality.
Upsert by external id
PUT /api/v1/employees/by-external/oracle-hcm/EMP-1001 looks up the employee linked to oracle-hcm / EMP-1001:
- Linked employee found: the body is applied like a
PATCHand the response is200. - No linked employee: an employee is created from the body (send at least
firstNameandlastName) and linked to the external id, and the response is201.
If the linked employee was deleted in the app, the old link is dropped and the call creates a new employee with a new link. To find an employee by your id without changing them, call GET /api/v1/employees?externalSystem=oracle-hcm&externalId=EMP-1001 (send both parameters).
Offboarding, archiving and deleting
DELETE /api/v1/employees/{id} offboards the employee: status becomes FORMER_EMPLOYEE, the record and its history stay, and the response is the updated employee. Offboarding a former employee changes nothing. To bring someone back, PATCH { "status": "EMPLOYEE" }.
POST /api/v1/employees/{id}/archive sets archivedAt. Archiving an archived employee changes nothing and returns it as is.
The API never deletes a person. When a person is deleted in the app (on the People page or through the data editor), the deletion appears in GET /api/v1/deleted?resource=employee for 180 days, with the external links the person had.
Webhook events
| Event | When | data.object |
|---|---|---|
employee.created | An employee is added one at a time (in the app or through the API), a candidate is hired (with application.hired; the candidate's externalRefs move to the employee, except a link another employee already holds), or a candidate is turned into an employee in the People editor | The employee |
employee.updated | An employee changes, including being assigned to a position on the org chart, or a former employee losing their position when it is deleted (changedFields: ["currentPositionId"]); data.changedFields lists the fields when known | The employee |
employee.offboarded | An employee is offboarded (through DELETE, in the app, or by setting status to FORMER_EMPLOYEE, which also sends employee.updated) | The employee |
employee.archived | An employee is archived | The employee |
employee.deleted | An employee is deleted on the People page, or made a candidate in the People editor | { id, externalRefs } |
employee.bulk_changed | Employees were imported (file or AI import), changed or deleted in the data editor, or many changed at once | { resource: "employee" } |
Imports and the data editor don't send one event per employee: they send employee.bulk_changed, and employees deleted in the data editor appear only in GET /api/v1/deleted.
After employee.bulk_changed, re-read the list with updatedSince set to the event's occurredAt, and read GET /api/v1/deleted?resource=employee&since=… for removed employees.
Errors
| Status and code | Meaning |
|---|---|
403 forbidden | The key lacks the permission in the table above. |
404 not_found | No employee with that id in your workspace. |
409 conflict | The position is full, a duplicate person exists, or the external id is already linked to another employee. |
422 validation_failed | The body is invalid; details explains why. |
422 unresolved_reference | manager or currentPosition could not be found in your workspace. |
Example
curl -X PUT https://jadiroon.com/api/v1/employees/by-external/oracle-hcm/EMP-1042 \
-H "Authorization: Bearer $JADIROON_KEY" \
-H "Content-Type: application/json" \
-d '{
"firstName": "Sara",
"lastName": "Alharbi",
"email": "sara.alharbi@example.sa",
"employeeNumber": "1042",
"startDate": "2026-01-15",
"manager": { "externalSystem": "oracle-hcm", "externalId": "EMP-1001" },
"currentPosition": { "externalSystem": "oracle-hcm", "externalId": "POS-310" }
}'
The first call creates and links the employee and answers 201 Created; repeating it updates the same employee and answers 200 OK with the same body shape:
{
"id": "cmvk2a8d10007kn5c3e9h1xyz",
"status": "EMPLOYEE",
"firstName": "Sara",
"lastName": "Alharbi",
"email": "sara.alharbi@example.sa",
"phone": null,
"nationality": null,
"nationalId": null,
"gender": null,
"birthDate": null,
"yearsExperience": null,
"specialization": null,
"education": null,
"archivedAt": null,
"externalRefs": [{ "system": "oracle-hcm", "externalId": "EMP-1042" }],
"createdAt": "2026-10-22T15:02:11.204Z",
"updatedAt": "2026-10-22T15:02:11.204Z",
"employeeNumber": "1042",
"startDate": "2026-01-15T00:00:00.000Z",
"managerId": "cmvjx0h1t0003kn3o1b2c3def",
"currentPositionId": "cmvk1q2w30004kn8x7d1f0abc",
"managementLevel": null,
"govExperienceYears": null,
"civilServiceExperienceYears": null,
"entityExperienceYears": null
}