Skip to content

Employees (v5)

The v5 Employees API is a modernized replacement for the v4 Users API. It provides cleaner semantics, true PATCH support, dedicated operation endpoints, and richer data includes (tags, employment history, work time arrangements).

Use v5 for new integrations. The v4 Users API remains available but will not receive new features.

Base URL: api/v5/integration/employees · Scope: ditioapiv3

Terminal window
# Test (default for all examples)
export DITIO_API_BASE="https://core-api.ditio.dev/core"
# Production: export DITIO_API_BASE="https://core-api.ditio.app/core"
Featurev4 Users APIv5 Employees API
IdentifieridentityId / companyProfileIdemployeeNumber (consistent across all endpoints)
PATCHPartial update on companyProfileIdTrue PATCH semantics — omitted fields unchanged, explicit null clears values
EmploymentMixed into user create/updateSeparate dedicated endpoints (create-employment, update-employment, end-employment)
TagsSimple key-value pairs on createFull tag management with date ranges, payroll tags, and diff-based updates
IncludesAll data returned by defaultOpt-in via ?include=tags,employment-history,work-time-arrangements
SearchBy profile ID or employee numberFree-text search across name, phone, email, employee number
Multi-companyManual per-company callsBuilt-in includeEmployeesFromSubsidiaries parameter
POST /api/v5/integration/employees

Creates a new employee profile with an initial employment. The profile and first employment are created together — you cannot create a profile without an employment.

Terminal window
curl -X POST "$DITIO_API_BASE/api/v5/integration/employees" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"employeeNumber": "1042",
"firstName": "Kari",
"lastName": "Nordmann",
"phone": "+4798765432",
"birthDate": "1990-05-15",
"email": "kari.nordmann@example.com",
"workTitle": "Maskinfører",
"employment": {
"startDate": "2026-03-01",
"department": "Anlegg",
"payroll": 1
}
}'

Response: 201 Created with the full employee object, including the created employment and its company context.

FieldTypeDescription
employeeNumberstringUnique within the company structure
firstNamestringFirst name
lastNamestringLast name
phonestringPhone number (used as login username)
birthDatedatetimeDate of birth
employmentobjectInitial employment (see below)
employment.startDatedatetimeEmployment start date
FieldTypeDescription
emailstringEmail address
addressstringHome address
workTitlestringJob title
carRegistrationNumberstringCompany car registration
closestRelativestringEmergency contact
personalInfostringAdditional personal info
workCardIdstringBuilder card / access card ID
workCardExpirationDatedatetimeCard expiration date
FieldTypeDefaultDescription
startDatedatetimerequiredEmployment start date
endDatedatetimenullEmployment end date (null = open-ended)
departmentstringnullDepartment name
mainProjectNumberstringnullDefault project number
payrollint0Payroll type: 0 = Disabled, 1 = Enabled, 2 = Variable
GET /api/v5/integration/employees/{employeeNumber}
ParameterTypeDefaultDescription
includeEmployeesFromSubsidiariesboolfalseSearch across subsidiary companies
includestringComma-separated: tags, work-time-arrangements, employment-history
Terminal window
curl "$DITIO_API_BASE/api/v5/integration/employees/1042?include=tags,employment-history" \
-H "Authorization: Bearer $TOKEN"

When employment-history is included, the response adds:

{
"employmentHistory": {
"current": {},
"upcoming": [],
"historical": []
}
}
GET /api/v5/integration/employees
ParameterTypeDefaultDescription
includeEmployeesFromSubsidiariesboolfalseInclude employees from subsidiary companies
includestringComma-separated: tags, work-time-arrangements, employment-history
employeeNumberstringFilter by employee number
GET /api/v5/integration/employees/search?query={query}

Free-text search across employee name, phone, email, and employee number. Returns a lightweight response with hasActiveEmployment per hit.

Terminal window
curl "$DITIO_API_BASE/api/v5/integration/employees/search?query=Kari" \
-H "Authorization: Bearer $TOKEN"
PUT /api/v5/integration/employees/{employeeNumber}

Replaces all profile fields (firstName, lastName, birthDate required). Employment changes should use the dedicated employment endpoints below.

PATCH /api/v5/integration/employees/{employeeNumber}

True PATCH semantics: only provided fields are updated, omitted fields remain unchanged, and an explicit null clears a value.

Terminal window
curl -X PATCH "$DITIO_API_BASE/api/v5/integration/employees/1042" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "workTitle": "Prosjektleder", "email": null }'

Patchable fields: firstName, lastName, email, phone, birthDate, address, workTitle, carRegistrationNumber, closestRelative, personalInfo.

DELETE /api/v5/integration/employees/{employeeNumber}

Returns 204 No Content.

GET /api/v5/integration/employees/{employeeNumber}/deletable
{
"isDeletable": false,
"validationErrors": [
"Employee has registered transactions",
"Employee has active check-ins"
]
}

Disabling prevents the employee from logging in. In a multi-company setup, this cascades to all companies and subcontractor relationships.

Terminal window
curl -X PATCH "$DITIO_API_BASE/api/v5/integration/employees/1042/disable" \
-H "Authorization: Bearer $TOKEN"
curl -X PATCH "$DITIO_API_BASE/api/v5/integration/employees/1042/enable" \
-H "Authorization: Bearer $TOKEN"

Both return the updated employee response.

PATCH /api/v5/integration/employees/{employeeNumber}/end-employment

Ends the current active employment. In a multi-company setup, also ends employments in all associated project companies and subcontractor relationships.

Terminal window
curl -X PATCH "$DITIO_API_BASE/api/v5/integration/employees/1042/end-employment" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "endDate": "2026-06-30" }'
POST /api/v5/integration/employees/{employeeNumber}/create-employment

Creates a new employment for an existing employee. If a current active employment exists, it is ended the day before the new employment starts.

Terminal window
curl -X POST "$DITIO_API_BASE/api/v5/integration/employees/1042/create-employment" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"startDate": "2026-09-01",
"department": "Maskinavdeling",
"mainProjectNumber": "P-2001",
"payroll": 1
}'
PATCH /api/v5/integration/employees/{employeeNumber}/update-employment

Partial update of the current active employment — only provided fields are updated.

PATCH /api/v5/integration/employees/{employeeNumber}/change-employee-number
Terminal window
curl -X PATCH "$DITIO_API_BASE/api/v5/integration/employees/1042/change-employee-number" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "newEmployeeNumber": "2042" }'

The new employee number must be unique within the company structure.

PATCH /api/v5/integration/employees/{employeeNumber}/change-phone-number

This is an identity-level change that affects all company profiles — the phone number is the login username.

Terminal window
curl -X PATCH "$DITIO_API_BASE/api/v5/integration/employees/1042/change-phone-number" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "newPhoneNumber": "+4791234567" }'
POST /api/v5/integration/employees/{employeeNumber}/enable-employee-in-project-company

Activates an employee in a specific project company with an optional user role.

FieldTypeRequiredDescription
projectCompanyIdstringYesThe project company ID
userGroupIdstringNoUser group/role ID (defaults to user)
POST /api/v5/integration/employees/{employeeNumber}/disable-employee-in-project-company

Body: { "projectCompanyId": "COMPANY_ID" }.

PUT /api/v5/integration/employees/{employeeNumber}/tags

Full replacement of the employee’s tag list. The API computes the diff:

  • Tags in the request but not existing → added
  • Tags existing but not in the request → removed
  • Tags with userTagId provided → updated (only dates can change)

Payroll tags (isPayrollTag = true) allow multiple assignments with non-overlapping date ranges. Regular tags allow only one assignment per tag.

Terminal window
curl -X PUT "$DITIO_API_BASE/api/v5/integration/employees/1042/tags" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '[
{
"tagName": "Safety Course",
"applicableFromDate": "2026-01-01",
"applicableToDate": null
}
]'
FieldTypeDescription
userTagIdstringFor updates: the existing assignment ID. For new tags: omit
tagIdstringThe tag definition ID. For updates: required. For create: optional (use tagName instead)
tagNamestringTag name. For create: use this OR tagId. For updates: ignored
applicableFromDatedatetimeStart date (required for payroll tags)
applicableToDatedatetimeEnd date (null = open-ended)

The response lists added, updated, removed, and currentTags.

All errors follow the standard format:

{
"message": "Validation failed",
"errors": [
{
"category": "UserInvalidInputError",
"code": "ValidationError",
"field": "Phone",
"message": "The Phone field is required."
}
]
}
CodeMeaning
200Success
201Created (POST endpoints)
204Success, no body (DELETE)
400Validation error — check the errors array
404Employee not found
import os
import requests
API_BASE = os.environ.get("DITIO_API_BASE", "https://core-api.ditio.dev/core")
headers = {"Authorization": f"Bearer {token}"}
def upsert_employee(hr_person):
"""Create the employee if missing, otherwise patch changed profile fields."""
number = hr_person["employee_number"]
lookup = requests.get(
f"{API_BASE}/api/v5/integration/employees/{number}", headers=headers
)
if lookup.status_code == 404:
payload = {
"employeeNumber": number,
"firstName": hr_person["first_name"],
"lastName": hr_person["last_name"],
"phone": hr_person["phone"],
"birthDate": hr_person["birth_date"],
"employment": {"startDate": hr_person["start_date"], "payroll": 1},
}
requests.post(
f"{API_BASE}/api/v5/integration/employees",
headers=headers, json=payload,
).raise_for_status()
else:
changes = {"workTitle": hr_person["title"], "email": hr_person["email"]}
requests.patch(
f"{API_BASE}/api/v5/integration/employees/{number}",
headers=headers, json=changes,
).raise_for_status()