PeopleDesk API

REST API for the PeopleDesk HR platform: employees, departments, absences, vacation balances and compensation. Version 1.4.0.

Authentication

Base URL https://hr-demo.vortner.dev. Every /v1 request carries an API key:

curl https://hr-demo.vortner.dev/v1/employees \
  -H "Authorization: Bearer $PEOPLEDESK_API_KEY"

Each company account has two keys. The production key works on the live records. The sandbox key reads the same records, but time-off requests it creates are kept apart from production and are not visible to the production key. Every authenticated response carries X-PeopleDesk-Environment: production or sandbox. A missing or wrong key gets 401 unauthorized. An API key sees the whole company account, so decide in your integration who may use it.

Rate limits

120 requests per minute per API key, counted in fixed one-minute windows. Every /v1 response carries:

X-RateLimit-Limit120
X-RateLimit-RemainingRequests left in the current window
X-RateLimit-ResetUnix time (seconds) when the window ends

Over the limit the API answers 429 rate_limited with Retry-After in seconds. /openapi.json and this page are not rate limited.

Pagination

GET /v1/employees and GET /v1/absences are paginated with page (from 1) and per_page (1 to 100, default 25; larger values get 400). Responses look like:

{
  "data": [ ... ],
  "meta": { "page": 1, "per_page": 25, "total": 22, "total_pages": 1 },
  "links": { "next": null, "prev": null }
}

Single resources come as {"data": {...}}. Direct reports and departments are short lists returned complete in data.

Errors

{ "error": { "code": "not_found", "message": "No employee with id emp_9999." } }
StatusCodes
400invalid_parameter, invalid_body
401unauthorized
404not_found
405method_not_allowed
409overlap, not_withdrawable
422invalid_dates, insufficient_balance, employee_inactive
429rate_limited

Data model

An employee belongs to one department and has at most one direct manager (manager_id); following manager_id upward gives the reporting line to the chief executive. A department has a head. An absence belongs to one employee and covers whole working days or one half day. Only vacation counts against the time-off balance. Compensation is one current record per employee.

Sensitive fields. Absence.reason is the employee's free-text comment and may contain health or family details. All of compensation is confidential pay data.

Employee

FieldTypeDescription
idstringEmployee id.
first_namestring
last_namestring
emailstring (email)Work email address.
job_titlestring
departmentstringDepartment name, as in Department.name.
manager_idstring | nullEmployee id of the direct manager; null for the chief executive.
locationstringOffice (Berlin, Hamburg, Munich) or Remote.
start_datestring (date)First working day.
statusactive | on_leave | onboarding | terminated
employment_typestring

Department

FieldTypeDescription
idstring
namestring
head_idstringEmployee id of the head of the department.
employee_countintegerEmployees in the department, including the head.

Absence

FieldTypeDescription
idstring
employee_idstringThe absent employee.
typevacation | sick | parental | other
statusapproved | pending | rejected
start_datestring (date)First day of the absence.
end_datestring (date)Last day of the absence (inclusive).
half_daybooleanTrue for a half-day absence on a single date.
daysnumberWorking days (Monday to Friday) the absence covers; 0.5 for a half day.
reasonstring | nullThe employee's free-text comment. Sensitive: may contain health or family details.
created_atstring (date-time)When the absence was entered or requested (UTC).

TimeOffBalance

FieldTypeDescription
employee_idstring
yearinteger
unitstringAll figures are working days.
entitlementnumberVacation days for the year.
takennumberApproved vacation already ended.
plannednumberApproved vacation still to come plus pending vacation requests.
remainingnumberentitlement - taken - planned.

Compensation

FieldTypeDescription
employee_idstring
base_salarynumberGross annual base salary in currency.
currencystringISO 4217 currency code.
pay_frequencystringHow the salary is paid out.
bonus_target_percentnumberTarget bonus as a percentage of base salary.
effective_datestring (date)Date the current figures took effect.

Endpoints

GET /openapi.json

Get this API description

Returns this OpenAPI 3.1 document. No API key is needed and the request does not count toward the rate limit.

GET /v1/employees

List employees

Returns the employees of the company account, ordered by employee id. Filters combine with AND. Former employees stay in the directory with status terminated; filter by status to leave them out. Use email to find the employee record that belongs to a work email address.

ParameterInRequiredTypeDescription
pagequerynointegerPage number, starting at 1.
per_pagequerynointegerItems per page, at most 100.
departmentquerynostringOnly employees of this department, given as its id (dep_sales) or its exact name (Sales, case-insensitive).
manager_idquerynostringOnly employees whose direct manager is this employee id.
statusquerynoactive | on_leave | onboarding | terminatedOnly employees with this employment status.
emailquerynostring (email)Only the employee with this work email address (exact match, case-insensitive).

GET /v1/employees/{id}

Get an employee

Returns one employee by id.

ParameterInRequiredTypeDescription
idpathyesstringEmployee id.

GET /v1/employees/{id}/direct-reports

List an employee's direct reports

Returns the employees whose direct manager is this employee (one level down the reporting line, not the whole subtree). The list is complete and not paginated; it is empty for employees who manage nobody.

ParameterInRequiredTypeDescription
idpathyesstringEmployee id.

GET /v1/employees/{id}/time-off-balance

Get an employee's vacation balance

Returns the vacation balance of one employee for a calendar year, in working days. taken counts approved vacation that has already ended; planned counts approved vacation still to come and pending vacation requests; remaining is entitlement - taken - planned. Sick, parental and other leave do not reduce the balance.

ParameterInRequiredTypeDescription
idpathyesstringEmployee id.
yearquerynointegerCalendar year. Defaults to the current year.

GET /v1/departments

List departments

Returns every department with its head and its number of employees. The list is complete and not paginated.

GET /v1/absences

List absences in a date range

Returns the absences that overlap the window from..to (both inclusive, at most 366 days), ordered by start date. An absence that starts before from or ends after to is included when any of its days fall in the window. Pending and rejected requests are included; filter by status for approved absences only. reason is the employee's own comment and may contain health or family details.

ParameterInRequiredTypeDescription
fromqueryyesstring (date)First day of the window (YYYY-MM-DD).
toqueryyesstring (date)Last day of the window (YYYY-MM-DD), on or after from.
employee_idquerynostringOnly absences of this employee.
typequerynovacation | sick | parental | otherOnly absences of this type.
statusquerynoapproved | pending | rejectedOnly absences with this status.
pagequerynointegerPage number, starting at 1.
per_pagequerynointegerItems per page, at most 100.

POST /v1/absences

Request time off

Creates a time-off request for an employee. The request starts as pending until a manager or HR decides it in PeopleDesk. The period must start today or later, lie within one calendar year and at most one year ahead, contain at least one working day, and not overlap another pending or approved absence of the same employee. Vacation requests must fit the remaining vacation balance. days is computed in working days (Monday to Friday).

Body (JSON): employee_id, type, start_date, end_date required; half_day, reason optional.

DELETE /v1/absences/{id}

Withdraw a pending time-off request

Withdraws a time-off request that is still pending and was created through the API with the same key. Absences entered in PeopleDesk itself and requests that have already been decided cannot be withdrawn here (409 not_withdrawable); HR changes those in PeopleDesk.

ParameterInRequiredTypeDescription
idpathyesstringAbsence id.

GET /v1/compensation

Get an employee's compensation

Returns the current compensation of one employee: annual base salary, currency, pay frequency, bonus target and the date the current figures took effect. This is confidential pay data.

ParameterInRequiredTypeDescription
employee_idqueryyesstringEmployee id.