Skip to content

People: leave, contracts, portal

Employees rather than client contacts: leave balances and requests, employment periods and work schedules, and the login a client gets to look in.

59 endpoints across 3 groups. A permission written module.resource.action:own is scoped: :own covers rows that are yours, :any covers everyone’s, and :any satisfies a check for :own.

EndpointPermission
GET /leave/availabilityleave.availability.read
POST /leave/availabilityleave.availability.write
PATCH /leave/availability/{entry_id}leave.availability.write
DELETE /leave/availability/{entry_id}leave.availability.write
GET /leave/availability/daysleave.availability.read
POST /leave/availability/moveleave.availability.write
GET /leave/balanceleave.request.read
GET /leave/balance/groupsleave.request.read
GET /leave/contractsleave.request.read
POST /leave/contractsleave.profile.manage
PATCH /leave/contracts/{contract_id}leave.profile.manage
DELETE /leave/contracts/{contract_id}leave.profile.manage
GET /leave/entitlementsleave.entitlement.read
PUT /leave/entitlementsleave.entitlement.write
DELETE /leave/entitlementsleave.entitlement.write
POST /leave/entitlements/generateleave.entitlement.write
GET /leave/free-timeleave.request.read
POST /leave/free-time/withdrawleave.request.write
GET /leave/holidaysleave.request.read
POST /leave/holidaysleave.holiday.write
PATCH /leave/holidays/{holiday_id}leave.holiday.write
DELETE /leave/holidays/{holiday_id}leave.holiday.write
POST /leave/holidays/importleave.holiday.write
GET /leave/profileleave.request.read
GET /leave/profilesleave.profile.manage
PUT /leave/profiles/{user_id}leave.profile.manage
GET /leave/rateleave.rate.read
GET /leave/rate/{user_id}leave.rate.read
PUT /leave/rate/{user_id}leave.rate.write
GET /leave/ratesleave.rate.read
GET /leave/recurringleave.request.read
POST /leave/recurringleave.request.write
PATCH /leave/recurring/{recurring_id}leave.request.write
DELETE /leave/recurring/{recurring_id}leave.request.write
GET /leave/requestsleave.request.read
POST /leave/requestsleave.request.write
GET /leave/requests/{request_id}leave.request.read
PATCH /leave/requests/{request_id}leave.request.write
POST /leave/requests/{request_id}/cancelleave.request.write
POST /leave/requests/{request_id}/decideleave.request.approve
POST /leave/requests/previewleave.request.read
GET /leave/settingsleave.profile.manage
PUT /leave/settingsleave.profile.manage
GET /leave/summaryleave.request.read
GET /leave/teamleave.request.read
GET /leave/typesleave.request.read
POST /leave/typesleave.type.write
PATCH /leave/types/{type_id}leave.type.write
DELETE /leave/types/{type_id}leave.type.write
Parameters and schemas per endpoint

List Availability — The exception rows with an occurrence in the window — own, or anyone’s with :any.

Permission: leave.availability.read

Query parameters:

NameTypeMeaning
date_fromstring · required
date_tostring · required
user_idstring
all_usersboolean(default false)

Returns: 200 · AvailabilityRead[]

Create Availability

Permission: leave.availability.write

Request body: AvailabilityCreate

Returns: 201 · AvailabilityRead

PATCH /api/v1/leave/availability/{entry_id}

Section titled “PATCH /api/v1/leave/availability/{entry_id}”

Update Availability

Permission: leave.availability.write

Path parameters: entry_id

Request body: AvailabilityUpdate

Returns: 200 · AvailabilityRead

DELETE /api/v1/leave/availability/{entry_id}

Section titled “DELETE /api/v1/leave/availability/{entry_id}”

Delete Availability — Deletes the other half too when the row is a move — see the service.

Permission: leave.availability.write

Path parameters: entry_id

Returns: 204

Availability Days — The resolved week: the base schedule with every exception applied, day by day.

Permission: leave.availability.read

Query parameters:

NameTypeMeaning
date_fromstring · required
date_tostring · required
user_idstring
all_usersboolean(default false)

Returns: 200 · AvailabilityDay[]

Move Availability — Swap one day for another — two rows sharing a pair_id, written in one act.

Permission: leave.availability.write

Request body: AvailabilityMove

Returns: 201 · AvailabilityRead[]

Balances

Permission: leave.request.read

Query parameters:

NameTypeMeaning
yearinteger · required
user_idstring

Returns: 200 · LeaveBalance[]

Group Balances — The employee-facing combined balances (#265): one figure per balance group (statutory + extra-statutory vacation roll up into one “Vakantieverlof”), with the per-pot breakdown — accrual year, remaining, expiry — alongside for anyone who needs to see where hours went.

Permission: leave.request.read

Query parameters:

NameTypeMeaning
yearinteger · required
user_idstring
all_usersboolean(default false)

Returns: 200 · LeaveGroupBalance[]

List Contracts — A user’s employment history. Own for a member; anyone’s — or everyone’s, with all_users — for a manager (the Settings → Users roster).

Permission: leave.request.read

Query parameters:

NameTypeMeaning
user_idstring
all_usersboolean(default false)

Returns: 200 · EmploymentContractRead[]

Create Contract

Permission: leave.profile.manage

Request body: EmploymentContractCreate

Returns: 201 · EmploymentContractRead

PATCH /api/v1/leave/contracts/{contract_id}

Section titled “PATCH /api/v1/leave/contracts/{contract_id}”

Update Contract

Permission: leave.profile.manage

Path parameters: contract_id

Request body: EmploymentContractUpdate

Returns: 200 · EmploymentContractRead

DELETE /api/v1/leave/contracts/{contract_id}

Section titled “DELETE /api/v1/leave/contracts/{contract_id}”

Delete Contract

Permission: leave.profile.manage

Path parameters: contract_id

Returns: 204

List Entitlements — Own entitlements; managers see everyone’s when no user_id is given.

Permission: leave.entitlement.read

Query parameters:

NameTypeMeaning
yearinteger · required
user_idstring

Returns: 200 · LeaveEntitlementRead[]

Upsert Entitlement

Permission: leave.entitlement.write

Request body: LeaveEntitlementUpsert

Returns: 200 · LeaveEntitlementRead

Delete Entitlement — Drop a pot and let generation re-derive it — the revert behind “clear it to let it be derived again”. A current/next-year pot reappears with the derived figure in the same request; a past year’s simply goes (history is never backfilled).

Permission: leave.entitlement.write

Query parameters:

NameTypeMeaning
yearinteger · required
user_idstring · required
leave_type_idstring · required

Returns: 204

Generate Entitlements

Permission: leave.entitlement.write

Request body: EntitlementGenerate

Returns: 200 · GenerateResult

Free Time Overview — Everything the free-time card and the employment wizard need, in one call.

Permission: leave.request.read

Query parameters:

NameTypeMeaning
yearinteger · required
user_idstring

Returns: 200 · FreeTimeOverview

Withdraw Free Time — Take back free days the pot no longer covers, after a contract change reprorated it (#264).

Permission: leave.request.write

Request body: FreeTimeWithdraw

Returns: 200 · FreeTimeWithdrawResult

List Holidays — The org’s calendar. Any staff member: it drives the agenda and the timesheet.

Permission: leave.request.read

Query parameters:

NameTypeMeaning
yearinteger
date_fromstring
date_tostring
include_inactiveboolean(default false)

Returns: 200 · LeaveHolidayRead[]

Create Holiday

Permission: leave.holiday.write

Request body: LeaveHolidayCreate

Returns: 201 · LeaveHolidayRead

Update Holiday

Permission: leave.holiday.write

Path parameters: holiday_id

Request body: LeaveHolidayUpdate

Returns: 200 · LeaveHolidayRead

DELETE /api/v1/leave/holidays/{holiday_id}

Section titled “DELETE /api/v1/leave/holidays/{holiday_id}”

Delete Holiday

Permission: leave.holiday.write

Path parameters: holiday_id

Returns: 204

Import Holidays — Re-run the generator for a year. Manual and deactivated rows survive untouched.

Permission: leave.holiday.write

Request body: HolidayImport

Returns: 200 · HolidayImportResult

My Profile — The caller’s effective schedule — merged server-side, on purpose (#46).

Permission: leave.request.read

Returns: 200 · LeaveProfileRead

List Profiles — Contract hours + own schedule per user (managers). A null schedule follows the org’s.

Permission: leave.profile.manage

Returns: 200 · LeaveProfileSummary[]

Set Profile

Permission: leave.profile.manage

Path parameters: user_id

Request body: LeaveProfileUpdate

Returns: 200 · LeaveProfileSummary

My Rate — The caller’s own hourly rate (salary-adjacent — a member sees only their own).

Permission: leave.rate.read

Returns: 200 · LeaveRateRead

User Rate — One employee’s rate. Own on :own; anyone’s on :any.

Permission: leave.rate.read

Path parameters: user_id

Returns: 200 · LeaveRateRead

Set Rate — Set or clear an employee’s rate (admin). Attributed nowhere — the rate is current state.

Permission: leave.rate.write

Path parameters: user_id

Request body: LeaveRateUpdate

Returns: 200 · LeaveRateRead

List Rates — Every employee’s rate for the managers’ roster. Requires leave.rate.read:any.

Permission: leave.rate.read

Returns: 200 · LeaveRateRead[]

List Recurring — Rostered-free-day patterns: a member’s own; anyone’s/all on leave.profile.manage.

Permission: leave.request.read

Query parameters:

NameTypeMeaning
user_idstring

Returns: 200 · LeaveRecurringDayRead[]

Create Recurring — A manager plans any type for anyone; a member plans their own self-service types (requires_approval = false) — the service enforces the split.

Permission: leave.request.write

Request body: LeaveRecurringDayCreate

Returns: 201 · LeaveRecurringDaySaved

PATCH /api/v1/leave/recurring/{recurring_id}

Section titled “PATCH /api/v1/leave/recurring/{recurring_id}”

Update Recurring

Permission: leave.request.write

Path parameters: recurring_id

Request body: LeaveRecurringDayUpdate

Returns: 200 · LeaveRecurringDaySaved

DELETE /api/v1/leave/recurring/{recurring_id}

Section titled “DELETE /api/v1/leave/recurring/{recurring_id}”

Delete Recurring — Delete the pattern. By default the days it placed stay — they are real leave somebody planned around, and a rule being removed is no reason to wipe a calendar.

Permission: leave.request.write

Path parameters: recurring_id

Query parameters:

NameTypeMeaning
withdraw_daysboolean(default false)

Returns: 200 · LeaveRecurringDeleteResult

List Requests

Permission: leave.request.read

Query parameters:

NameTypeMeaning
limitinteger(default 50)
offsetinteger(default 0)
user_idstring
all_usersboolean(default false)
yearinteger
statusLeaveRequestStatus
sortstringemployee | start_date | end_date | hours | status, ’-’ desc

Returns: 200 · Page_LeaveRequestRead_

Create Request

Permission: leave.request.write

Request body: LeaveRequestCreate

Returns: 201 · LeaveRequestRead

Get Request

Permission: leave.request.read

Path parameters: request_id

Returns: 200 · LeaveRequestRead

Update Request

Permission: leave.request.write

Path parameters: request_id

Request body: LeaveRequestUpdate

Returns: 200 · LeaveRequestRead

POST /api/v1/leave/requests/{request_id}/cancel

Section titled “POST /api/v1/leave/requests/{request_id}/cancel”

Cancel Request

Permission: leave.request.write

Path parameters: request_id

Returns: 200 · LeaveRequestRead

POST /api/v1/leave/requests/{request_id}/decide

Section titled “POST /api/v1/leave/requests/{request_id}/decide”

Decide Request — Approve or reject a pending request (managers).

Permission: leave.request.approve

Path parameters: request_id

Request body: LeaveRequestDecision

Returns: 200 · LeaveRequestRead

Preview Request — What a span costs, before it is submitted — so the number shown is the number stored.

Permission: leave.request.read

Request body: LeaveRequestPreview

Returns: 200 · LeavePreviewResult

Get Settings — The org’s leave settings. An org that never saved a row gets the defaults.

Permission: leave.profile.manage

Returns: 200 · LeaveSettingsRead

Update Settings

Permission: leave.profile.manage

Request body: LeaveSettingsUpdate

Returns: 200 · LeaveSettingsRead

Summary

Permission: leave.request.read

Returns: 200 · LeaveSummary

Team

Permission: leave.request.read

Query parameters:

NameTypeMeaning
date_fromstring · required
date_tostring · required
user_idstring

Returns: 200 · TeamLeaveItem[]

List Types

Permission: leave.request.read

Query parameters:

NameTypeMeaning
include_inactiveboolean(default false)

Returns: 200 · LeaveTypeRead[]

Create Type

Permission: leave.type.write

Request body: LeaveTypeCreate

Returns: 201 · LeaveTypeRead

Update Type

Permission: leave.type.write

Path parameters: type_id

Request body: LeaveTypeUpdate

Returns: 200 · LeaveTypeRead

Delete Type

Permission: leave.type.write

Path parameters: type_id

Returns: 204

EndpointPermission
POST /hr/documentshr.document.manage
DELETE /hr/documents/{document_id}hr.document.manage
GET /hr/documents/{document_id}/filehr.dossier.read
GET /hr/dossierhr.dossier.read
Parameters and schemas per endpoint

Upload Document

Permission: hr.document.manage

Query parameters:

NameTypeMeaning
user_idstring · required
categorystring · required
titlestring(default “)
notestring(default “)

Request body: Body_upload_document_api_v1_hr_documents_post

Returns: 201 · HrDocumentRead

Delete Document

Permission: hr.document.manage

Path parameters: document_id

Returns: 204

GET /api/v1/hr/documents/{document_id}/file

Section titled “GET /api/v1/hr/documents/{document_id}/file”

Serve Document

Permission: hr.dossier.read

Path parameters: document_id

Returns: 200

Dossier

Permission: hr.dossier.read

Query parameters:

NameTypeMeaning
user_idstring

Returns: 200 · DossierRead

EndpointPermission
POST /portal/impersonation/stopDeliberately open
GET /portal/logins/{entity_type}/{subject_id}members.member.write
POST /portal/logins/{entity_type}/{subject_id}members.member.write
DELETE /portal/logins/{entity_type}/{subject_id}members.member.write
POST /portal/logins/{entity_type}/{subject_id}/impersonateportal.login.impersonate
POST /portal/logins/{entity_type}/{subject_id}/resendmembers.member.write
Parameters and schemas per endpoint

Stop Portal Impersonation

Permission: Deliberately open

Returns: 204

GET /api/v1/portal/logins/{entity_type}/{subject_id}

Section titled “GET /api/v1/portal/logins/{entity_type}/{subject_id}”

Portal Login State

Permission: members.member.write

Path parameters: entity_type, subject_id

Returns: 200 · PortalLoginState

POST /api/v1/portal/logins/{entity_type}/{subject_id}

Section titled “POST /api/v1/portal/logins/{entity_type}/{subject_id}”

Enable Portal Login — Invite this subject to the portal, or re-enable a login that was switched off.

Permission: members.member.write

Path parameters: entity_type, subject_id

Returns: 200 · PortalLoginState

DELETE /api/v1/portal/logins/{entity_type}/{subject_id}

Section titled “DELETE /api/v1/portal/logins/{entity_type}/{subject_id}”

Disable Portal Login

Permission: members.member.write

Path parameters: entity_type, subject_id

Returns: 200 · PortalLoginState

POST /api/v1/portal/logins/{entity_type}/{subject_id}/impersonate

Section titled “POST /api/v1/portal/logins/{entity_type}/{subject_id}/impersonate”

Impersonate Portal Login — Sign in as this subject’s portal login, time-boxed and on their own trail (#296).

Permission: portal.login.impersonate

Path parameters: entity_type, subject_id

Request body: PortalImpersonateRequest

Returns: 200 · PortalImpersonateResponse

POST /api/v1/portal/logins/{entity_type}/{subject_id}/resend

Section titled “POST /api/v1/portal/logins/{entity_type}/{subject_id}/resend”

Resend Portal Invite

Permission: members.member.write

Path parameters: entity_type, subject_id

Returns: 200 · PortalLoginState