Download OpenAPI specification:
HRM Norway Employee Core management service API.
All endpoints require Bearer token authentication.
To integrate with Employee API you have to register on Visma Developer Portal and request access to the API along with the required scopes.
Authentication uses OAuth tokens from Visma Connect. Authorization is done on tenant level, so one OAuth token is needed per tenant.
| Entity | Timeline | Description |
|---|---|---|
| Employee | - | Core employee record |
| ├── additionalAccounts[] | flexible | Secondary bank accounts for payments |
| ├── carLinks[] | flexible | Company car links |
| ├── children[] | none | Employee's children with period tracking |
| ├── creditorClaims[] | flexible | Wage garnishments and deductions |
| ├── pensionLinks[] | flexible | Pension provider links |
| ├── personalInformation | singleton | Personal details (name, address, contact info) — 1:1 per employee |
| ├── sicknessAndAbsence | none | Chronically ill periods only (see position-level for prepaid/redundancy) |
| ├── taxAndContributionRules[] | flexible | Special tax and contribution rules |
| ├── taxInformation[] | strict | Tax card and withholding settings |
| ├── unionLinks[] | flexible | Union memberships |
| └── positions[] | flexible | Employment positions and job assignments |
| ├── costUnitLinks[] | flexible | Cost center allocations |
| ├── salaryInformation[] | strict | Salary, hourly rates, and pay details |
| ├── sicknessAndAbsence | none | Prepaid sickness, other absence, and redundancy periods |
| ├── taxUnitLinks[] | strict | Tax unit assignments for A-melding reporting |
| └── workArrangements[] | strict | Working hours and schedule arrangements |
Use the embed query parameter to include related entities in responses.
For Employee endpoints:
additionalAccounts - Secondary bank accounts (Tilleggskontoer)carLinks - Company car links (Firmabil)children - Employee's children (Barn)creditorClaims - Wage garnishments (Utleggstrekk)pensionLinks - Pension provider links (Pensjonsleverandører)personalInformation - Personal details (Personopplysninger)sicknessAndAbsence - Sickness and absence configuration (Sykdom og fravær)taxAndContributionRules - Special tax rules (Skatte- og avgiftsregler)taxInformation - Tax settings history (Skatteopplysninger)unionLinks - Union memberships (Fagforeningsmedlemskap)positions - Employment positions (Stillinger)For Position endpoints:
costUnitLinks - Cost allocations (Kostnadsfordeling)salaryInformation - Salary details (Lønnsinformasjon)taxUnitLinks - Tax unit assignments for A-melding (Underenheter)workArrangements - Work arrangement (Arbeidstidsordning)Example: GET /employees/{id}?embed=positions,personalInformation
Example: GET /employees/{id}/positions/{positionId}?embed=salaryInformation,workArrangements
The root aggregate entity representing an employee within an organization. An employee holds
non-timelined core fields (identity, draft status, notes) and embeds settings objects
(contactDetails, payrollSettings, sicknessAndAbsence, linkedUserData). It serves as the
parent for all timeline-based sub-entities such as personal information, positions, tax
information, and more.
An employee is always created together with at least one position via the combined
POST /employees/with-positions endpoint.
| Property | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes (read-only) | Unique employee identifier. Can be client-provided on create, otherwise server-generated. |
number |
string | No | Employee number (Ansattnummer). Max 12 characters, unique within the organization. |
tenantId |
string | (read-only) | Organization tenant identifier. Derived from authentication token. |
isDraft |
boolean | No | Draft employees have relaxed validation and are excluded from payroll. Cannot revert to true. |
notes |
string | No | Free-text administrator notes. Must not contain personal or sensitive data. |
mergedCompanyEmployeeStartDate |
date | No | Original start date when employee transferred from a merged company. |
etag |
string | (read-only) | Opaque version token for optimistic concurrency. Must be included in PATCH requests. |
updatedAt |
datetime | (read-only) | Timestamp of last modification. |
The following objects are part of the Employee record and are read/written inline via the Employee PATCH endpoint. Each has its own documentation page.
| Object | Description |
|---|---|
contactDetails |
Address, phone numbers, email addresses, emergency contacts |
emergencyContacts |
Emergency contact persons (name, phone, email, primary flag) |
payrollSettings |
Bank account, payment method, payslip preferences |
linkedUserData |
Read-only user account data from Visma Connect |
sicknessAndAbsence |
Employee-level chronically ill periods |
Timeline-based entities managed through dedicated endpoints under /employees/{employeeId}/....
Can be embedded in GET responses using the ?embed query parameter (e.g.
GET /employees/{id}?embed=positions,personalInformation).
| Collection | Timeline | Description |
|---|---|---|
personalInformation |
None | Name, national ID, gender, date of birth |
positions |
Flexible | Employment positions / job roles |
additionalAccounts |
Flexible | Secondary bank accounts for partial salary payments |
carLinks |
Flexible | Company vehicle assignments |
children |
None | Children (affects sick leave entitlements) |
creditorClaims |
Flexible | Wage garnishments and creditor deductions |
pensionLinks |
Flexible | Pension provider assignments |
taxAndContributionRules |
Flexible | Special tax rules (nettlonn, sjofolk, Svalbard) |
taxInformation |
Strict | Tax cards and withholding settings |
unionLinks |
Flexible | Union memberships and insurance |
Key Validation Rules
POST /employees/with-positions endpoint. This rule does not apply for Draft Employees.number, when provided, must be unique within the organization and is immutable after creation
(except for draft employees).isDraft = true) can be hard-deleted. Non-draft employees are terminated
by ending their positions.isDraft cannot be changed from false back to true.etag must be included in every PATCH request and must match the server's current version.countryCode is required.paymentType determines which bank fields are required/prohibited.idUnique identifier for the employee record. When omitted on create, the server generates a UUID.
Supplying a duplicate UUID returns 409 Conflict.
Note: This is subject for change - Client-provided IDs are useful for idempotent creation (retry-safe), data migration, and offline-first architectures. This will be supported after EmpMan monolith is discontinued.
numberHuman-readable employee number. Max 12 characters. Must be unique within the organization. If not provided on create, the system assigns the next available number.
Validation
isDraftfalse)Draft mode flag. Draft employees have relaxed validation (lookup validation like managerId is
skipped), are excluded from payroll runs, and are excluded from A-melding reporting. Draft
employees can be hard-deleted via the API; non-draft employees can only be terminated by ending
their positions.
Validation
false to true. The transition is one-way.notesFree-text administrator notes about the employee. Should not contain personal or sensitive data (advisory — not system-enforced).
mergedCompanyEmployeeStartDateYYYY-MM-DD)Original employment start date from a merged company. Only relevant when the employee was transferred from a merged/acquired company and seniority calculations require the true start date.
etagOpaque version identifier for optimistic concurrency control. Returned in every GET response and
must be echoed back in PATCH requests. If the value does not match the server's current version,
the request returns 409 Conflict.
updatedAtTimestamp of the last modification to the employee record or any embedded object. Set by the service on every write.
| Property | Type | Required | Description |
|---|---|---|---|
address1 |
string | No | Street address (Gateadresse). Max 200 characters. |
postalLocation |
string | No | Postal location (Poststed). Max 200 characters. |
postalCode |
string | No | Postal code (Postnummer). For Norwegian addresses, must be a valid 4-digit code. |
countryCode |
string | Conditional | Country code, ISO 3166-1 alpha-2 (Landkode). Required when any address field is provided. |
homePhone |
string | No | Private phone number (Hjemmetelefon). 8–16 characters. |
workPhone |
string | No | Work phone number (Jobbtelefon). 8–16 characters. |
homeEmail |
string | No | Personal email address (Privat e-post). Max 135 characters. Must be a valid email format. |
workEmail |
string | No | Work email address (Jobb e-post). Max 135 characters. Must be a valid email format. |
emergencyContacts |
array | No | Array of emergency contact persons (Nødkontakter). See EmergencyContacts. |
For more information refer to Contact Details
| Property | Type | Required | Description |
|---|---|---|---|
firstName |
string | Yes | Emergency contact's first name. |
lastName |
string | Yes | Emergency contact's last name. |
mainContact |
boolean | No | Whether this is the primary emergency contact. |
phoneNumber |
string | No | Contact phone number. null when not provided. |
email |
string | No | Contact email address. Must be a valid email. null allowed. |
For more information refer to emergencyContacts
| Property | Type | Required | Description |
|---|---|---|---|
payslipOnPaper |
boolean | No | Generate a paper payslip in addition to the electronic one. Default: false. |
payslipLanguage |
enum | No | Payslip language: norwegian (default) or english. |
paymentType |
enum | Yes | Salary payment method: bank or cash. |
norwegianBankAccount |
string | Conditional | Norwegian bank account number. 11 digits with MOD11 check digit. Required when paymentType = bank and internationalBank is not provided. |
internationalBank |
object | Conditional | International bank account details (IBAN, SWIFT, country, remittance country). Required when paymentType = bank and payment is to a foreign bank account. |
internationalBank.iban |
string | Yes | IBAN for international transfers. Length and format depend on the country (e.g. Norwegian IBAN: NO + 2 check digits + 11-digit account number, 15 characters total). |
internationalBank.swift |
string | Yes | BIC/SWIFT code identifying the bank. 8 or 11 characters (e.g. DNBANOKKXXX). |
internationalBank.country |
string | Yes | Country where the bank is located. ISO 3166-1 alpha-2 code. |
internationalBank.remittanceCountry |
string | Yes | Remittance destination country. ISO 3166-1 alpha-2 code. May differ from country. |
retrieveTaxCardOnWageRun |
boolean | No | When true, the tax card is fetched from Skatteetaten at the start of each wage run. Default: true. |
lastTaxCardRetrieveDate |
date | No (read-only) | Date the tax card was last retrieved from Skatteetaten. Managed by the service. |
For more information refer to payrollSettings
| Property | Type | Required | Description |
|---|---|---|---|
firstName |
string | No (read-only) | User account first name from Visma Connect. |
lastName |
string | No (read-only) | User account last name from Visma Connect. |
email |
string (email) | No (read-only) | User account login email from Visma Connect. |
status |
string | No (read-only) | User account status (e.g. active, pending, inactive, suspended). |
odpUserId |
string | No (read-only) | Visma Connect (ODP) user account identifier. Set once the account has been successfully created. |
For more information refer to linkedUserData
| Property | Type | Required | Description |
|---|---|---|---|
chronicallyIllPeriods |
array | No | Periods when the employee has chronic illness status. See period shape below. |
chronicallyIllPeriods[].id |
UUID | Yes (read-only) | Unique period identifier. |
chronicallyIllPeriods[].from |
date | Yes | Period effective from date. |
chronicallyIllPeriods[].to |
date | No | Period effective until date. null means ongoing. |
lastModified |
datetime | Yes (read-only) | Timestamp of the most recent modification. null when no periods exist. |
For more information refer to sicknessAndAbsence
| Event | Trigger | Consumers |
|---|---|---|
employee.created |
New employee registered (with initial position) | Payroll, A-melding, Reporting |
employee.updated |
Employee root fields modified (contactDetails, payrollSettings, etc.) | Payroll, A-melding |
employee.deleted |
Draft employee hard-deleted | Payroll |
Creates a new employee with initial positions in a single atomic transaction.
Draft Mode:
employee.isDraft to true to create a draft employee with relaxed validation.Response: Returns the created Employee with positions embedded in the response.
| tenantId required | string Tenant identifier |
required | object (Employee) The employee to create. The |
Array of objects (Position) Default: [] Initial positions to create for the employee. Optional - can be empty or omitted. Each position will be validated according to the existing Position schema rules. |
{- "employee": {
- "number": "string",
- "isDraft": true,
- "notes": "string",
- "mergedCompanyEmployeeStartDate": "2019-08-24",
- "contactDetails": {
- "address1": "string",
- "postalLocation": "string",
- "postalCode": "string",
- "countryCode": "st",
- "homePhone": "stringst",
- "workPhone": "stringst",
- "homeEmail": "user@example.com",
- "workEmail": "user@example.com",
- "emergencyContacts": [
- {
- "firstName": "string",
- "lastName": "string",
- "mainContact": true,
- "phoneNumber": "string",
- "email": "user@example.com"
}
]
}, - "payrollSettings": {
- "printPayslip": true,
- "payslipInEnglish": true,
- "paymentType": "bank",
- "internationalBankAccount": true,
- "localBankAccount": "string",
- "internationalBankSwift": "string",
- "internationalIban": "string",
- "internationalBankCountry": "string",
- "internationalRemittanceCountry": "string",
- "retrieveTaxCardOnWageRun": true,
- "lastTaxCardRetrieveDate": "2019-08-24"
}, - "linkedUserData": {
- "firstName": "string",
- "lastName": "string",
- "email": "user@example.com",
- "status": "string",
- "odpUserId": "string"
}, - "sicknessAndAbsence": {
- "chronicallyIllPeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24"
}
]
}, - "etag": "1"
}, - "positions": [ ]
}{- "number": "string",
- "tenantId": "string",
- "isDraft": true,
- "notes": "string",
- "mergedCompanyEmployeeStartDate": "2019-08-24",
- "contactDetails": {
- "address1": "string",
- "postalLocation": "string",
- "postalCode": "string",
- "countryCode": "st",
- "homePhone": "stringst",
- "workPhone": "stringst",
- "homeEmail": "user@example.com",
- "workEmail": "user@example.com",
- "emergencyContacts": [
- {
- "firstName": "string",
- "lastName": "string",
- "mainContact": true,
- "phoneNumber": "string",
- "email": "user@example.com"
}
]
}, - "payrollSettings": {
- "printPayslip": true,
- "payslipInEnglish": true,
- "paymentType": "bank",
- "internationalBankAccount": true,
- "localBankAccount": "string",
- "internationalBankSwift": "string",
- "internationalIban": "string",
- "internationalBankCountry": "string",
- "internationalRemittanceCountry": "string",
- "retrieveTaxCardOnWageRun": true,
- "lastTaxCardRetrieveDate": "2019-08-24"
}, - "linkedUserData": {
- "firstName": "string",
- "lastName": "string",
- "email": "user@example.com",
- "status": "string",
- "odpUserId": "string"
}, - "sicknessAndAbsence": {
- "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "lastModified": "2019-08-24T14:15:22Z"
}, - "positions": [
- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "positionNumber": 0,
- "positionEndReason": "EmployeeResigned",
- "managerId": "b2c2c359-55f3-4680-a660-901475c7a693",
- "appointmentType": "Permanent",
- "employmentType": "Ordinary",
- "maritimeWorker": {
- "shipRegister": "InternationalShipRegister",
- "vesselType": "CruiseShip",
- "shippingArea": "Domestic"
}, - "tagLinks": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "salaryInformation": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "workArrangements": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "personalInformation": {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "nationalId": "string",
- "dNumber": "string",
- "internationalId": {
- "type": "Pass",
- "value": "string",
- "countryCode": "string"
}, - "gender": "Female",
- "dateOfBirth": "2019-08-24",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}, - "children": [
- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "birthYear": "2019-08-24",
- "soleCustodyPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "legacyIds": [
- {
- "name": "LegacyEmployeePublicId",
- "value": "a860a344-d7b2-406e-828e-8d442f23f344"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}Creates an employee and all of its child entities atomically in a single transaction.
Draft Mode:
employee.isDraft to true to skip all validation and save the record as-is.Not included: taxUnitLinks and costUnitLinks (position-level entities) are not part of this
endpoint. Create them separately after the employee is created.
Response: Returns the created Employee root only. Use the embed query parameter on GET to retrieve nested entities.
| tenantId required | string Tenant identifier |
required | object (Employee) The employee root. Set isDraft=true to skip FluentValidation and manager ID lookup. |
Array of objects (Position) Default: [] Positions to create. Each may include | |
object or null | |
Array of objects (TaxInformationCreate) Default: [] | |
Array of objects (ChildCreate) Default: [] | |
Array of objects (UnionLinkCreate) Default: [] | |
Array of objects (CarLinkCreate) Default: [] | |
Array of objects (CreditorClaimCreate) Default: [] | |
Array of objects (TaxAndContributionRuleCreate) Default: [] | |
Array of objects (PensionLinkCreate) Default: [] | |
Array of objects (AdditionalAccountCreate) Default: [] |
{- "employee": {
- "number": "string",
- "isDraft": true,
- "notes": "string",
- "mergedCompanyEmployeeStartDate": "2019-08-24",
- "contactDetails": {
- "address1": "string",
- "postalLocation": "string",
- "postalCode": "string",
- "countryCode": "st",
- "homePhone": "stringst",
- "workPhone": "stringst",
- "homeEmail": "user@example.com",
- "workEmail": "user@example.com",
- "emergencyContacts": [
- {
- "firstName": "string",
- "lastName": "string",
- "mainContact": true,
- "phoneNumber": "string",
- "email": "user@example.com"
}
]
}, - "payrollSettings": {
- "printPayslip": true,
- "payslipInEnglish": true,
- "paymentType": "bank",
- "internationalBankAccount": true,
- "localBankAccount": "string",
- "internationalBankSwift": "string",
- "internationalIban": "string",
- "internationalBankCountry": "string",
- "internationalRemittanceCountry": "string",
- "retrieveTaxCardOnWageRun": true,
- "lastTaxCardRetrieveDate": "2019-08-24"
}, - "linkedUserData": {
- "firstName": "string",
- "lastName": "string",
- "email": "user@example.com",
- "status": "string",
- "odpUserId": "string"
}, - "sicknessAndAbsence": {
- "chronicallyIllPeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24"
}
]
}, - "etag": "1"
}, - "positions": [ ],
- "personalInformation": {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "firstName": "string",
- "lastName": "string",
- "nationalId": "string",
- "dNumber": "string",
- "internationalId": {
- "type": "Pass",
- "value": "string",
- "countryCode": "string"
}, - "gender": "Female",
- "dateOfBirth": "2019-08-24"
}, - "taxInformation": [ ],
- "children": [ ],
- "unionLinks": [ ],
- "carLinks": [ ],
- "creditorClaims": [ ],
- "taxAndContributionRules": [ ],
- "pensionLinks": [ ],
- "additionalAccounts": [ ]
}{- "number": "string",
- "tenantId": "string",
- "isDraft": true,
- "notes": "string",
- "mergedCompanyEmployeeStartDate": "2019-08-24",
- "contactDetails": {
- "address1": "string",
- "postalLocation": "string",
- "postalCode": "string",
- "countryCode": "st",
- "homePhone": "stringst",
- "workPhone": "stringst",
- "homeEmail": "user@example.com",
- "workEmail": "user@example.com",
- "emergencyContacts": [
- {
- "firstName": "string",
- "lastName": "string",
- "mainContact": true,
- "phoneNumber": "string",
- "email": "user@example.com"
}
]
}, - "payrollSettings": {
- "printPayslip": true,
- "payslipInEnglish": true,
- "paymentType": "bank",
- "internationalBankAccount": true,
- "localBankAccount": "string",
- "internationalBankSwift": "string",
- "internationalIban": "string",
- "internationalBankCountry": "string",
- "internationalRemittanceCountry": "string",
- "retrieveTaxCardOnWageRun": true,
- "lastTaxCardRetrieveDate": "2019-08-24"
}, - "linkedUserData": {
- "firstName": "string",
- "lastName": "string",
- "email": "user@example.com",
- "status": "string",
- "odpUserId": "string"
}, - "sicknessAndAbsence": {
- "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "lastModified": "2019-08-24T14:15:22Z"
}, - "positions": [
- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "positionNumber": 0,
- "positionEndReason": "EmployeeResigned",
- "managerId": "b2c2c359-55f3-4680-a660-901475c7a693",
- "appointmentType": "Permanent",
- "employmentType": "Ordinary",
- "maritimeWorker": {
- "shipRegister": "InternationalShipRegister",
- "vesselType": "CruiseShip",
- "shippingArea": "Domestic"
}, - "tagLinks": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "salaryInformation": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "workArrangements": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "personalInformation": {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "nationalId": "string",
- "dNumber": "string",
- "internationalId": {
- "type": "Pass",
- "value": "string",
- "countryCode": "string"
}, - "gender": "Female",
- "dateOfBirth": "2019-08-24",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}, - "children": [
- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "birthYear": "2019-08-24",
- "soleCustodyPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "legacyIds": [
- {
- "name": "LegacyEmployeePublicId",
- "value": "a860a344-d7b2-406e-828e-8d442f23f344"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}| tenantId required | string Tenant identifier |
| asOfDate | string <date> Filter timeline entities active as of this date |
| embed | string Comma-separated list of related entities to embed in response. For Employee: positions, personalInformation, taxInformation, children, unionLinks, carLinks, creditorClaims, taxAndContributionRules, pensionLinks, additionalAccounts Example: ?embed=positions,personalInformation |
| includeLegacyIds | boolean Default: false When true, requests that legacy system identifiers be included in the response.
Note: Example: ?includeLegacyIds=true |
| pageSize | integer [ 1 .. 1000 ] Parameter indicates the number of results that the client would like to see in the response. |
| x-cursor | string or null Pagination token used to query for the next part of a list. |
[- {
- "number": "string",
- "tenantId": "string",
- "isDraft": true,
- "notes": "string",
- "mergedCompanyEmployeeStartDate": "2019-08-24",
- "contactDetails": {
- "address1": "string",
- "postalLocation": "string",
- "postalCode": "string",
- "countryCode": "st",
- "homePhone": "stringst",
- "workPhone": "stringst",
- "homeEmail": "user@example.com",
- "workEmail": "user@example.com",
- "emergencyContacts": [
- {
- "firstName": "string",
- "lastName": "string",
- "mainContact": true,
- "phoneNumber": "string",
- "email": "user@example.com"
}
]
}, - "payrollSettings": {
- "printPayslip": true,
- "payslipInEnglish": true,
- "paymentType": "bank",
- "internationalBankAccount": true,
- "localBankAccount": "string",
- "internationalBankSwift": "string",
- "internationalIban": "string",
- "internationalBankCountry": "string",
- "internationalRemittanceCountry": "string",
- "retrieveTaxCardOnWageRun": true,
- "lastTaxCardRetrieveDate": "2019-08-24"
}, - "linkedUserData": {
- "firstName": "string",
- "lastName": "string",
- "email": "user@example.com",
- "status": "string",
- "odpUserId": "string"
}, - "sicknessAndAbsence": {
- "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "lastModified": "2019-08-24T14:15:22Z"
}, - "positions": [
- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "positionNumber": 0,
- "positionEndReason": "EmployeeResigned",
- "managerId": "b2c2c359-55f3-4680-a660-901475c7a693",
- "appointmentType": "Permanent",
- "employmentType": "Ordinary",
- "maritimeWorker": {
- "shipRegister": "InternationalShipRegister",
- "vesselType": "CruiseShip",
- "shippingArea": "Domestic"
}, - "tagLinks": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "salaryInformation": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "workArrangements": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "personalInformation": {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "nationalId": "string",
- "dNumber": "string",
- "internationalId": {
- "type": "Pass",
- "value": "string",
- "countryCode": "string"
}, - "gender": "Female",
- "dateOfBirth": "2019-08-24",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}, - "children": [
- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "birthYear": "2019-08-24",
- "soleCustodyPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "legacyIds": [
- {
- "name": "LegacyEmployeePublicId",
- "value": "a860a344-d7b2-406e-828e-8d442f23f344"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}
]| tenantId required | string Tenant identifier |
| id | string <uuid> Optional client-provided identifier. If omitted, a server-generated UUID is assigned. If the ID already exists, a 409 Conflict is returned. |
| number | string or null (number) Employee number (Ansattnummer) - company-assigned identifier Monolith notes: Field "_Employee ID" (00000000-0000-4002-0101-000000000000). |
| isDraft | boolean Default: false Draft employees are not included in payroll runs |
| notes | string or null (notes) Free-text notes about the employee Monolith notes: Field "Notes" (c911e43b-1856-416a-a7a2-88e3e9639226). |
| mergedCompanyEmployeeStartDate | string or null <date> (mergedCompanyEmployeeStartDate) Original start date when employee transferred from merged company Monolith notes: Field "Employee start date in merged company" (0c036557-11a2-4d23-b059-c6b2ce530d4f). |
object (ContactDetails) | |
object (PayrollSettings) Payroll and payment settings (Lønnsinnstillinger). | |
object (LinkedUserData) Link to user account in identity system | |
object (SicknessAndAbsence) Employee-level sickness and absence configuration (chronicallyIllPeriods only). Use asOfDate query parameter to filter to periods active on a specific date. PATCH semantics: Omitting a property from a PATCH request preserves existing periods
unchanged. Providing an empty array ( Breaking change: prepaidSicknessPeriods, prepaidOtherAbsencePeriods, and redundancyPeriods have been moved to the position-level endpoint (positions/{positionId}/sickness-and-absence). Sending those fields here will return 400. |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "number": "string",
- "isDraft": false,
- "notes": "string",
- "mergedCompanyEmployeeStartDate": "2019-08-24",
- "contactDetails": {
- "address1": "string",
- "postalLocation": "string",
- "postalCode": "string",
- "countryCode": "st",
- "homePhone": "stringst",
- "workPhone": "stringst",
- "homeEmail": "user@example.com",
- "workEmail": "user@example.com",
- "emergencyContacts": [
- {
- "firstName": "string",
- "lastName": "string",
- "mainContact": true,
- "phoneNumber": "string",
- "email": "user@example.com"
}
]
}, - "payrollSettings": {
- "printPayslip": true,
- "payslipInEnglish": true,
- "paymentType": "bank",
- "internationalBankAccount": true,
- "localBankAccount": "string",
- "internationalBankSwift": "string",
- "internationalIban": "string",
- "internationalBankCountry": "string",
- "internationalRemittanceCountry": "string",
- "retrieveTaxCardOnWageRun": true,
- "lastTaxCardRetrieveDate": "2019-08-24"
}, - "linkedUserData": {
- "firstName": "string",
- "lastName": "string",
- "email": "user@example.com",
- "status": "string",
- "odpUserId": "string"
}, - "sicknessAndAbsence": {
- "chronicallyIllPeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24"
}
]
}
}{- "number": "string",
- "tenantId": "string",
- "isDraft": true,
- "notes": "string",
- "mergedCompanyEmployeeStartDate": "2019-08-24",
- "contactDetails": {
- "address1": "string",
- "postalLocation": "string",
- "postalCode": "string",
- "countryCode": "st",
- "homePhone": "stringst",
- "workPhone": "stringst",
- "homeEmail": "user@example.com",
- "workEmail": "user@example.com",
- "emergencyContacts": [
- {
- "firstName": "string",
- "lastName": "string",
- "mainContact": true,
- "phoneNumber": "string",
- "email": "user@example.com"
}
]
}, - "payrollSettings": {
- "printPayslip": true,
- "payslipInEnglish": true,
- "paymentType": "bank",
- "internationalBankAccount": true,
- "localBankAccount": "string",
- "internationalBankSwift": "string",
- "internationalIban": "string",
- "internationalBankCountry": "string",
- "internationalRemittanceCountry": "string",
- "retrieveTaxCardOnWageRun": true,
- "lastTaxCardRetrieveDate": "2019-08-24"
}, - "linkedUserData": {
- "firstName": "string",
- "lastName": "string",
- "email": "user@example.com",
- "status": "string",
- "odpUserId": "string"
}, - "sicknessAndAbsence": {
- "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "lastModified": "2019-08-24T14:15:22Z"
}, - "positions": [
- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "positionNumber": 0,
- "positionEndReason": "EmployeeResigned",
- "managerId": "b2c2c359-55f3-4680-a660-901475c7a693",
- "appointmentType": "Permanent",
- "employmentType": "Ordinary",
- "maritimeWorker": {
- "shipRegister": "InternationalShipRegister",
- "vesselType": "CruiseShip",
- "shippingArea": "Domestic"
}, - "tagLinks": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "salaryInformation": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "workArrangements": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "personalInformation": {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "nationalId": "string",
- "dNumber": "string",
- "internationalId": {
- "type": "Pass",
- "value": "string",
- "countryCode": "string"
}, - "gender": "Female",
- "dateOfBirth": "2019-08-24",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}, - "children": [
- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "birthYear": "2019-08-24",
- "soleCustodyPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "legacyIds": [
- {
- "name": "LegacyEmployeePublicId",
- "value": "a860a344-d7b2-406e-828e-8d442f23f344"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| asOfDate | string <date> Filter timeline entities active as of this date |
| embed | string Comma-separated list of related entities to embed in response. For Employee: positions, personalInformation, taxInformation, children, unionLinks, carLinks, creditorClaims, taxAndContributionRules, pensionLinks, additionalAccounts Example: ?embed=positions,personalInformation |
| includeLegacyIds | boolean Default: false When true, requests that legacy system identifiers be included in the response.
Note: Example: ?includeLegacyIds=true |
{- "number": "string",
- "tenantId": "string",
- "isDraft": true,
- "notes": "string",
- "mergedCompanyEmployeeStartDate": "2019-08-24",
- "contactDetails": {
- "address1": "string",
- "postalLocation": "string",
- "postalCode": "string",
- "countryCode": "st",
- "homePhone": "stringst",
- "workPhone": "stringst",
- "homeEmail": "user@example.com",
- "workEmail": "user@example.com",
- "emergencyContacts": [
- {
- "firstName": "string",
- "lastName": "string",
- "mainContact": true,
- "phoneNumber": "string",
- "email": "user@example.com"
}
]
}, - "payrollSettings": {
- "printPayslip": true,
- "payslipInEnglish": true,
- "paymentType": "bank",
- "internationalBankAccount": true,
- "localBankAccount": "string",
- "internationalBankSwift": "string",
- "internationalIban": "string",
- "internationalBankCountry": "string",
- "internationalRemittanceCountry": "string",
- "retrieveTaxCardOnWageRun": true,
- "lastTaxCardRetrieveDate": "2019-08-24"
}, - "linkedUserData": {
- "firstName": "string",
- "lastName": "string",
- "email": "user@example.com",
- "status": "string",
- "odpUserId": "string"
}, - "sicknessAndAbsence": {
- "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "lastModified": "2019-08-24T14:15:22Z"
}, - "positions": [
- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "positionNumber": 0,
- "positionEndReason": "EmployeeResigned",
- "managerId": "b2c2c359-55f3-4680-a660-901475c7a693",
- "appointmentType": "Permanent",
- "employmentType": "Ordinary",
- "maritimeWorker": {
- "shipRegister": "InternationalShipRegister",
- "vesselType": "CruiseShip",
- "shippingArea": "Domestic"
}, - "tagLinks": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "salaryInformation": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "workArrangements": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "personalInformation": {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "nationalId": "string",
- "dNumber": "string",
- "internationalId": {
- "type": "Pass",
- "value": "string",
- "countryCode": "string"
}, - "gender": "Female",
- "dateOfBirth": "2019-08-24",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}, - "children": [
- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "birthYear": "2019-08-24",
- "soleCustodyPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "legacyIds": [
- {
- "name": "LegacyEmployeePublicId",
- "value": "a860a344-d7b2-406e-828e-8d442f23f344"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| etag required | string Opaque version identifier for optimistic concurrency control. |
| number | string Employee number (Ansattnummer) - company-assigned identifier |
| isDraft | boolean Draft employees are not included in payroll runs |
| notes | string Free-text notes about the employee |
| mergedCompanyEmployeeStartDate | string <date> Original start date when employee transferred from merged company |
object (ContactDetails) | |
object (PayrollSettings) Payroll and payment settings (Lønnsinnstillinger). | |
object (LinkedUserData) Link to user account in identity system | |
object (SicknessAndAbsence) Employee-level sickness and absence configuration (chronicallyIllPeriods only). Use asOfDate query parameter to filter to periods active on a specific date. PATCH semantics: Omitting a property from a PATCH request preserves existing periods
unchanged. Providing an empty array ( Breaking change: prepaidSicknessPeriods, prepaidOtherAbsencePeriods, and redundancyPeriods have been moved to the position-level endpoint (positions/{positionId}/sickness-and-absence). Sending those fields here will return 400. |
{- "etag": "1",
- "number": "string",
- "isDraft": true,
- "notes": "string",
- "mergedCompanyEmployeeStartDate": "2019-08-24",
- "contactDetails": {
- "address1": "string",
- "postalLocation": "string",
- "postalCode": "string",
- "countryCode": "st",
- "homePhone": "stringst",
- "workPhone": "stringst",
- "homeEmail": "user@example.com",
- "workEmail": "user@example.com",
- "emergencyContacts": [
- {
- "firstName": "string",
- "lastName": "string",
- "mainContact": true,
- "phoneNumber": "string",
- "email": "user@example.com"
}
]
}, - "payrollSettings": {
- "printPayslip": true,
- "payslipInEnglish": true,
- "paymentType": "bank",
- "internationalBankAccount": true,
- "localBankAccount": "string",
- "internationalBankSwift": "string",
- "internationalIban": "string",
- "internationalBankCountry": "string",
- "internationalRemittanceCountry": "string",
- "retrieveTaxCardOnWageRun": true,
- "lastTaxCardRetrieveDate": "2019-08-24"
}, - "linkedUserData": {
- "firstName": "string",
- "lastName": "string",
- "email": "user@example.com",
- "status": "string",
- "odpUserId": "string"
}, - "sicknessAndAbsence": {
- "chronicallyIllPeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24"
}
]
}
}{- "number": "string",
- "tenantId": "string",
- "isDraft": true,
- "notes": "string",
- "mergedCompanyEmployeeStartDate": "2019-08-24",
- "contactDetails": {
- "address1": "string",
- "postalLocation": "string",
- "postalCode": "string",
- "countryCode": "st",
- "homePhone": "stringst",
- "workPhone": "stringst",
- "homeEmail": "user@example.com",
- "workEmail": "user@example.com",
- "emergencyContacts": [
- {
- "firstName": "string",
- "lastName": "string",
- "mainContact": true,
- "phoneNumber": "string",
- "email": "user@example.com"
}
]
}, - "payrollSettings": {
- "printPayslip": true,
- "payslipInEnglish": true,
- "paymentType": "bank",
- "internationalBankAccount": true,
- "localBankAccount": "string",
- "internationalBankSwift": "string",
- "internationalIban": "string",
- "internationalBankCountry": "string",
- "internationalRemittanceCountry": "string",
- "retrieveTaxCardOnWageRun": true,
- "lastTaxCardRetrieveDate": "2019-08-24"
}, - "linkedUserData": {
- "firstName": "string",
- "lastName": "string",
- "email": "user@example.com",
- "status": "string",
- "odpUserId": "string"
}, - "sicknessAndAbsence": {
- "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "lastModified": "2019-08-24T14:15:22Z"
}, - "positions": [
- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "positionNumber": 0,
- "positionEndReason": "EmployeeResigned",
- "managerId": "b2c2c359-55f3-4680-a660-901475c7a693",
- "appointmentType": "Permanent",
- "employmentType": "Ordinary",
- "maritimeWorker": {
- "shipRegister": "InternationalShipRegister",
- "vesselType": "CruiseShip",
- "shippingArea": "Domestic"
}, - "tagLinks": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "salaryInformation": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "workArrangements": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "personalInformation": {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "nationalId": "string",
- "dNumber": "string",
- "internationalId": {
- "type": "Pass",
- "value": "string",
- "countryCode": "string"
}, - "gender": "Female",
- "dateOfBirth": "2019-08-24",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}, - "children": [
- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "birthYear": "2019-08-24",
- "soleCustodyPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "legacyIds": [
- {
- "name": "LegacyEmployeePublicId",
- "value": "a860a344-d7b2-406e-828e-8d442f23f344"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}Secondary bank accounts for splitting an employee's salary payment across multiple destinations. Each account specifies how much to transfer per payroll period and to which Norwegian bank account.
Only Norwegian bank accounts (norwegianBank payment type) are supported. Changes take effect for
future payments only — there is no retroactive recalculation.
Timeline type: Flexible — gaps and overlaps allowed. Max 10 overlapping additional accounts per employee.
| Property | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes (read-only) | Unique additional-account identifier. |
employeeId |
UUID | (read-only) | Employee this account belongs to. |
from |
date | Yes | Account effective from date. |
to |
date | No | Allocation effective until date. null means ongoing. |
bankAccountNumber |
string | Yes | Norwegian bank account number (11 digits, MOD11 check). |
bankHolderName |
string | No | Account holder name. Max 70 characters. |
amount |
string | One-of | Fixed amount per payroll period. Exactly one of amount or payCodeId must be provided. |
payCodeId |
UUID | One-of | Reference to a pay code. Exactly one of amount or payCodeId must be provided. |
description |
string | No | Free-text description of the account purpose. |
updatedAt |
datetime | (read-only) | Timestamp of last modification. |
The monolith persists an internal
deductionMethodenum (amountorpaycode) for legacy UI reasons. The Employee Core Service does not expose this field — it is inferred from whichever ofamountorpayCodeIdis provided on write.Amount calculation, payment ordering, and sequence-number assignment (range 61–70) are performed by the payroll system, not this service. This service stores the accounts and enforces validation only.
Key Validation Rules
bankAccountNumber must be an 11-digit Norwegian account number with a valid MOD11 check digit.amount or payCodeId must be supplied — never both, never neither.to, when provided, must be on or after from.to) or
deleted. To change values, end the existing account and create a new one.idUnique identifier for the additional account record. Generated by the service on create; never supplied by clients.
fromYYYY-MM-DD)Date the additional account becomes effective. Future dates are allowed.
toYYYY-MM-DD)Date the additional account ends. Required when creating; null on read indicates no set end date.
bankAccountNumberNorwegian bank account number. 11-digit numeric string where the first 4 digits are the bank
office code and the 11th digit is a MOD11 check digit. Stored without spaces; typical display
format is 1234 56 78901.
bankHolderNameName of the person or entity owning the receiving account (Kontoinnehaver).
Validation
amountamount or payCodeId must be providedFixed amount transferred to this account each payroll period. Use this field when the employee wants a constant amount (e.g. monthly savings, rent).
When amount is provided, the monolith internally records the deduction method as amount.
Validation
payCodeId is absent.payCodeId.payCodeIdamount or payCodeId must be providedReference to a paycode from the Payroll API whose output determines the transfer amount each payroll period. Use this field when the amount is variable and should follow a specific pay code.
When payCodeId is provided, the monolith internally records the deduction method as paycode.
Validation
amount is absent.amount.PaymentRule type.from/to must lie within the pay code's valid period.descriptionFree-text description of the account's purpose (e.g. "Monthly savings", "Rent payment"). Useful on payslips and for historical reference.
updatedAtTimestamp of the last modification to the record. Set by the service on every write.
Example: Create Additional Account
Fixed-amount deduction (monthly savings):
POST /tenants/{tenantId}/employees/{employeeId}/additional-accounts
Authorization: Bearer <token>
Content-Type: application/json
{
"from": "2026-05-01",
"to": "2026-12-31",
"bankAccountNumber": "12345678903",
"bankHolderName": "Ola Nordmann",
"amount": "5000.00",
"description": "Monthly savings"
}
Pay-code-driven deduction (amount determined by a pay code):
{
"from": "2026-05-01",
"to": "2026-12-31",
"bankAccountNumber": "12345678903",
"payCodeId": "550e8400-e29b-41d4-a716-446655440000",
"description": "Travel allowance"
}
A successful request returns 201 Created with the full AdditionalAccount resource, including
the server-generated id and updatedAt.
| Event | Trigger | Consumers |
|---|---|---|
additionalAccount.created |
New additional account registered | Payroll |
additionalAccount.updated |
Existing account modified (e.g. to date set) |
Payroll |
additionalAccount.deleted |
Additional account removed | Payroll |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| asOfDate | string <date> Filter timeline entities active as of this date |
| pageSize | integer [ 1 .. 1000 ] Parameter indicates the number of results that the client would like to see in the response. |
| x-cursor | string or null Pagination token used to query for the next part of a list. |
[- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "bankHolderName": "string",
- "bankAccountNumber": "string",
- "deductionMethod": "paycode",
- "deductionAmount": "string",
- "deductionPayCodeId": "c98152e9-3278-41b5-8ccc-b434820bcf47",
- "description": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
]| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| id | string <uuid> Optional client-provided identifier. If omitted, a server-generated UUID is assigned. If the ID already exists, a 409 Conflict is returned. |
| bankHolderName | string or null (bankHolderName) Account holder name Monolith notes: Field "Bankholder name" (227f152c-3cf0-46dc-8099-f33a8511ed90). |
| bankAccountNumber required | string or null (bankAccountNumber) Bank account number Monolith notes: Field "Bank account number" (5c7e8234-cd7c-4e3f-b64d-6dba4ac3a239). |
| deductionMethod required | string or null (paymentDeductionMethod) Enum: "paycode" "amount" How to determine payment amount:
Monolith notes: Field "Deduction method" (103dca57-eacb-439d-9349-52075b626941). |
| deductionAmount | string (deductionAmount) Fixed amount when method is 'amount' Monolith notes: Field "Amount" (6c3fb0d6-5193-4ba0-872f-b4dcb082d6f1). |
| deductionPayCodeId | string or null <uuid> (deductionPayCodeId) Pay code reference when method is 'paycode' Monolith notes: Field "Paycode" (663c3975-4422-4929-9d9d-d2f33840bc26). |
| description | string or null (accountDescription) Purpose description (e.g., savings, rent payment) Monolith notes: Field "Description" (989e8ef6-c262-4ff1-8bc8-835f33339b4e). |
| from required | string <date> Effective-from date |
| to required | string or null <date> Effective-until date |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "bankHolderName": "string",
- "bankAccountNumber": "string",
- "deductionMethod": "paycode",
- "deductionAmount": "string",
- "deductionPayCodeId": "c98152e9-3278-41b5-8ccc-b434820bcf47",
- "description": "string",
- "from": "2019-08-24",
- "to": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "bankHolderName": "string",
- "bankAccountNumber": "string",
- "deductionMethod": "paycode",
- "deductionAmount": "string",
- "deductionPayCodeId": "c98152e9-3278-41b5-8ccc-b434820bcf47",
- "description": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| additionalAccountId required | string <uuid> Additional account unique identifier |
{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "bankHolderName": "string",
- "bankAccountNumber": "string",
- "deductionMethod": "paycode",
- "deductionAmount": "string",
- "deductionPayCodeId": "c98152e9-3278-41b5-8ccc-b434820bcf47",
- "description": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| additionalAccountId required | string <uuid> Additional account unique identifier |
| bankHolderName | string or null (bankHolderName) Account holder name Monolith notes: Field "Bankholder name" (227f152c-3cf0-46dc-8099-f33a8511ed90). |
| bankAccountNumber | string or null (bankAccountNumber) Bank account number Monolith notes: Field "Bank account number" (5c7e8234-cd7c-4e3f-b64d-6dba4ac3a239). |
| deductionMethod | string or null (paymentDeductionMethod) Enum: "paycode" "amount" How to determine payment amount:
Monolith notes: Field "Deduction method" (103dca57-eacb-439d-9349-52075b626941). |
| deductionAmount | string (deductionAmount) Fixed amount when method is 'amount' Monolith notes: Field "Amount" (6c3fb0d6-5193-4ba0-872f-b4dcb082d6f1). |
| deductionPayCodeId | string or null <uuid> (deductionPayCodeId) Pay code reference when method is 'paycode' Monolith notes: Field "Paycode" (663c3975-4422-4929-9d9d-d2f33840bc26). |
| description | string or null (accountDescription) Purpose description (e.g., savings, rent payment) Monolith notes: Field "Description" (989e8ef6-c262-4ff1-8bc8-835f33339b4e). |
| etag required | string Opaque version identifier for optimistic concurrency control. Must be included in PATCH request body. |
| from required | string <date> Effective-from date |
| to | string or null <date> Effective-until date |
{- "bankHolderName": "string",
- "bankAccountNumber": "string",
- "deductionMethod": "paycode",
- "deductionAmount": "string",
- "deductionPayCodeId": "c98152e9-3278-41b5-8ccc-b434820bcf47",
- "description": "string",
- "etag": "1",
- "from": "2019-08-24",
- "to": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "bankHolderName": "string",
- "bankAccountNumber": "string",
- "deductionMethod": "paycode",
- "deductionAmount": "string",
- "deductionPayCodeId": "c98152e9-3278-41b5-8ccc-b434820bcf47",
- "description": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| additionalAccountId required | string <uuid> Additional account unique identifier |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}Links a company car to an employee and captures parameters used by payroll to compute the taxable benefit (naturalytelse / firmabil).
Car master data (registration, make/model, list price, electric flag, etc.) lives in the Org API and is out of scope here — this entity only stores the assignment link and calculation parameters.
Timeline type: Flexible — gaps and overlaps allowed, to may be open-ended.
| Property | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes (read-only) | Unique assignment identifier. |
carId |
string | Yes | Reference to the company car in the Org API. |
from |
date | Yes | Assignment start date. |
to |
date | No | Assignment end date. null means ongoing. |
calculationMethod |
enum | Yes | How payroll calculates the taxable benefit: listprice or kilometers. |
mileage |
integer | Conditional | Annual private-use mileage in km. Required when calculationMethod is kilometers; optional otherwise. Max 999999. |
listPrice |
integer | Conditional | List price of the car. Required when calculationMethod is listprice; optional otherwise. Max 999999. |
updatedAt |
datetime | Yes (read-only) | Timestamp of last modification. |
| Value | Norwegian | When to use |
|---|---|---|
listprice |
Listeprismetoden | Standard method — benefit is a percentage of the car's list price. mileage not required. |
kilometers |
Kilometermetoden | Benefit based on private km driven. mileage is required. |
Benefit amount calculation and A-melding reporting are performed by the payroll system, not this service. This service only stores the assignment.
Key Validation Rules
carId must reference an active car in the Org API.CarPool = "Yes" in
Org API), which may be assigned concurrently.to, when provided, must be on or after from.idUnique identifier for the car assignment record. Generated by the service on create; never supplied by clients.
carIdForeign key to a company car defined in the Org API. The referenced car must exist and be active
for the entire assignment period. Non-pool cars can only be linked to one employee at a time; pool
cars (CarPool = "Yes" in Org API) may be shared across employees concurrently.
Validation
carId across employees, unless the car
is flagged as a pool car.fromYYYY-MM-DD)Date the assignment starts. Must fall within both the car's active period in the Org API and the employee's position/contract period. Future dates are allowed.
toYYYY-MM-DD)Date the assignment ends. null (or omitted) means the assignment is ongoing. When provided, must
be on or after from and within the car's and employee's active periods. Setting to is the
standard way to close an open-ended assignment.
calculationMethodlistprice | kilometersTells payroll how to compute the taxable benefit:
listprice (Listeprismetoden) — standard method; benefit is a percentage of the car's list
price. mileage is not required.kilometers (Kilometermetoden) — benefit is based on private kilometres driven. mileage must
be provided.The actual benefit amount is computed by the payroll system, not by this service.
mileagecalculationMethod is kilometers, optional otherwiseAnnual private-use mileage. Must be a positive integer, maximum 999999. Ignored by payroll when
calculationMethod is listprice, but may still be stored for reference.
listPricecalculationMethod is listPrice, optional otherwiseList price of the car (Listepris) used as the basis for the taxable benefit when
calculationMethod is listPrice. Must be a positive integer, maximum 999999. Ignored by
payroll when calculationMethod is kilometers, but may still be stored for reference.
updatedAtTimestamp of the last modification to the record. Set by the service on every write.
Example: Create Car Link
POST /tenants/{tenantId}/employees/{employeeId}/car-links
Authorization: Bearer <token>
Content-Type: application/json
{
"carId": "a3f1c2d4-5e6b-7a8c-9d0e-1f2a3b4c5d6e",
"from": "2026-05-01",
"calculationMethod": "kilometers",
"mileage": 15000
}
A successful request returns 201 Created with the full CarLink resource, including the
server-generated id and updatedAt.
| Event | Trigger | Consumers |
|---|---|---|
carLink.created |
New assignment registered | Payroll |
carLink.updated |
Existing assignment modified (e.g. to date set) |
Payroll |
carLink.deleted |
Assignment removed | Payroll |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| asOfDate | string <date> Filter timeline entities active as of this date |
| pageSize | integer [ 1 .. 1000 ] Parameter indicates the number of results that the client would like to see in the response. |
| x-cursor | string or null Pagination token used to query for the next part of a list. |
[- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "carId": "string",
- "mileagePeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "carLinkId": "f23a2e89-4897-4609-8fe9-28ba3a1ab7c4",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "mileage": 0,
- "calculationMethod": "kilometers",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
]| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| id | string <uuid> Optional client-provided identifier. If omitted, a server-generated UUID is assigned. If the ID already exists, a 409 Conflict is returned. |
| carId | string or null (carId) Reference to company car (carID) Monolith notes: Field "CarLinksLookup" (2e960c43-041a-4041-9b25-f6c5174f7d25). |
Array of objects (CarLinkPeriod) Mileage and calculation method periods for this car link | |
| from required | string <date> Effective-from date |
| to | string or null <date> Effective-until date |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "carId": "string",
- "mileagePeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24",
- "mileage": 0,
- "calculationMethod": "kilometers"
}
], - "from": "2019-08-24",
- "to": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "carId": "string",
- "mileagePeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "carLinkId": "f23a2e89-4897-4609-8fe9-28ba3a1ab7c4",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "mileage": 0,
- "calculationMethod": "kilometers",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| carLinkId required | string <uuid> Car link unique identifier |
{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "carId": "string",
- "mileagePeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "carLinkId": "f23a2e89-4897-4609-8fe9-28ba3a1ab7c4",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "mileage": 0,
- "calculationMethod": "kilometers",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| carLinkId required | string <uuid> Car link unique identifier |
| carId | string or null (carId) Reference to company car (carID) Monolith notes: Field "CarLinksLookup" (2e960c43-041a-4041-9b25-f6c5174f7d25). |
Array of objects (CarLinkPeriod) Mileage and calculation method periods for this car link | |
| etag required | string Opaque version identifier for optimistic concurrency control. Must be included in PATCH request body. |
| from required | string <date> Effective-from date |
| to | string or null <date> Effective-until date |
{- "carId": "string",
- "mileagePeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24",
- "mileage": 0,
- "calculationMethod": "kilometers"
}
], - "etag": "1",
- "from": "2019-08-24",
- "to": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "carId": "string",
- "mileagePeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "carLinkId": "f23a2e89-4897-4609-8fe9-28ba3a1ab7c4",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "mileage": 0,
- "calculationMethod": "kilometers",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| carLinkId required | string <uuid> Car link unique identifier |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}Stores information about an employee's children (Barn), including periods for sole custody and chronic illness that directly affect sick leave entitlements under Norwegian labour law.
Children were separated from the legacy relatives entity into their own dedicated sub-entity.
This reflects their distinct business purpose: children carry sole custody and chronically ill
period data that directly affects sick leave rights, while relatives serve a broader family contact
role.
Timeline type: None (entity-level) — each child is a simple collection
item. Two sub-timeline period arrays (soleCustodyPeriods and chronicallyIllPeriods) track
date-bounded periods.
| Property | Type | Required | Description |
|---|---|---|---|
employeeId |
UUID | (read-only) | Employee this child belongs to. |
firstName |
string | Yes | First name (Fornavn). |
lastName |
string | Yes | Last name (Etternavn). |
birthYear |
date | Yes | Date of birth of the child (Fødselsdato). |
soleCustodyPeriods |
array of { from, to } |
No | Date periods of sole custody (Aleneomsorg). Managed via PATCH on the child object. |
chronicallyIllPeriods |
array of { from, to } |
No | Date periods of chronic illness (Kronisk syk). Managed via PATCH on the child object. |
updatedAt |
datetime | (read-only) | Timestamp of last modification. |
Each entry within soleCustodyPeriods and chronicallyIllPeriods is a simple date range with two properties:
| Property | Type | Required | Description |
|---|---|---|---|
from |
date | Yes | Period start date (inclusive). |
to |
date | No | Period end date (inclusive). null or omitted means ongoing. |
Key Validation Rules
firstName and lastName are required and must not be empty.birthYear is required and must not be a future date.to, when provided, must be on or after from.from year must not precede the child's birthYear.idUnique identifier for the child record. Generated by the service on create; never supplied by
clients. Clients may optionally provide a UUID on create — if the ID already exists, a
409 Conflict is returned.
firstNameFirst name of the child (Fornavn). Required on create and must not be empty or whitespace-only.
lastNameLast name of the child (Etternavn). Required on create and must not be empty or whitespace-only.
birthYearYYYY-MM-DD)Date of birth of the child (Fødselsdato). The date of birth is used to determine age-based sick leave entitlements (e.g. under 12, under 18 for chronically ill).
soleCustodyPeriods{ from, to } date periodsArray of date periods indicating when the employee has sole custody of this child. Each entry has
a from (required) and to (optional, null = ongoing) date. The existence of a period implies
sole custody during that timespan, which doubles the employee's sick leave entitlement.
These periods are not a separate resource — there is no dedicated endpoint for them. To add,
modify, or remove sole custody periods, PATCH the child object and include the full replacement
array in soleCustodyPeriods. Omitting the property from the PATCH preserves existing periods.
Providing an empty array ([]) clears all periods.
Validation
from is required and must be a valid date between 1910-04-15 and 2089-09-17.to, if provided, must be on or after from and between 1910-04-15 and
2089-09-17.from must not precede the child's birthYear.chronicallyIllPeriods{ from, to } date periodsArray of date periods indicating when the child is chronically ill. Each entry has a from
(required) and to (optional, null = ongoing) date. The existence of a period grants additional
sick leave days and extends the age limit to 18 years.
These periods are not a separate resource — there is no dedicated endpoint for them. To add,
modify, or remove chronically ill periods, PATCH the child object and include the full replacement
array in chronicallyIllPeriods. Omitting the property from the PATCH preserves existing periods.
Providing an empty array ([]) clears all periods.
Validation
updatedAtTimestamp of the last modification to the record. Set by the service on every write.
Benefit amount calculation and sick leave quota are performed by the payroll system, not this service. This service only stores the child data and periods.
Example: Create Child
POST /tenants/{tenantId}/employees/{employeeId}/children
Authorization: Bearer <token>
Content-Type: application/json
{
"firstName": "Emma",
"lastName": "Nordmann",
"birthYear": "2018-06-15",
"soleCustodyPeriods": [],
"chronicallyIllPeriods": []
}
For a child with sole custody and chronic illness, include period entries:
{
"firstName": "Lars",
"lastName": "Nordmann",
"birthYear": "2015-03-22",
"soleCustodyPeriods": [{ "from": "2023-06-01" }],
"chronicallyIllPeriods": [{ "from": "2020-01-01" }]
}
A successful request returns 201 Created with the full Child resource, including the
server-generated id and updatedAt.
| Event | Trigger | Consumers |
|---|---|---|
child.created |
New child registered | Payroll |
child.updated |
Child data modified (including soleCustodyPeriods/chronicallyIllPeriods) | Payroll |
child.deleted |
Child removed | Payroll |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| pageSize | integer [ 1 .. 1000 ] Parameter indicates the number of results that the client would like to see in the response. |
| x-cursor | string or null Pagination token used to query for the next part of a list. |
[- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "birthYear": "2019-08-24",
- "soleCustodyPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}
]| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| id | string <uuid> Optional client-provided identifier. If omitted, a server-generated UUID is assigned. If the ID already exists, a 409 Conflict is returned. |
| firstName required | string or null (firstName-2) First name (Fornavn) Monolith notes: Field "First name" (8760f996-ac90-4823-9c5e-e4248a61e47f). |
| lastName required | string or null (lastName-2) Last name (Etternavn) Monolith notes: Field "Last name" (9a14b378-9703-444f-a287-664b654716bf). |
| birthYear required | string <date> Date of birth of the child (Fødselsdato) Monolith notes: Field "Date of birth" (9fc9af3a-38d5-4f07-8ddc-ea1e0fdadef2). |
Array of objects (ChildPeriod) Periods of sole custody (Aleneomsorg) | |
Array of objects (ChildPeriod) Periods of chronic illness (Kronisk syk) |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "firstName": "string",
- "lastName": "string",
- "birthYear": "2019-08-24",
- "soleCustodyPeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "chronicallyIllPeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24"
}
]
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "birthYear": "2019-08-24",
- "soleCustodyPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| childId required | string <uuid> Child unique identifier |
{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "birthYear": "2019-08-24",
- "soleCustodyPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| childId required | string <uuid> Child unique identifier |
| firstName | string or null (firstName-2) First name (Fornavn) Monolith notes: Field "First name" (8760f996-ac90-4823-9c5e-e4248a61e47f). |
| lastName | string or null (lastName-2) Last name (Etternavn) Monolith notes: Field "Last name" (9a14b378-9703-444f-a287-664b654716bf). |
| birthYear | string or null <date> (birthYear) Date of birth of the child (Fødselsdato) Monolith notes: Field "Date of birth" (9fc9af3a-38d5-4f07-8ddc-ea1e0fdadef2). |
Array of objects (ChildPeriod) Periods of sole custody (Aleneomsorg) - affects sick leave rights Monolith notes: Field "Sole custody" (1ea5f79b-567a-4ac5-bbc9-71d4e5b92fd8). | |
Array of objects (ChildPeriod) Periods of chronic illness (Kronisk syk) - affects sick leave rights Monolith notes: Field "Chronically, long-term ill or disabled child" (81d238b7-b65c-4e4f-8514-3c8f5c92f888). | |
| etag required | string Opaque version identifier for optimistic concurrency control. Must be included in PATCH request body. |
{- "firstName": "string",
- "lastName": "string",
- "birthYear": "2019-08-24",
- "soleCustodyPeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "chronicallyIllPeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "etag": "1"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "birthYear": "2019-08-24",
- "soleCustodyPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "childId": "da54978f-5a21-4efd-948e-3959f61b037a",
- "periodType": "SoleCustody",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| childId required | string <uuid> Child unique identifier |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}Non-timelined contact information embedded in the Employee entity. Contains address, phone numbers, and email addresses.
In the legacy system, phones and emails were stored as typed arrays; in the new service they are flattened into named fields for simplicity.
Entity type: Embedded object (no timeline) — updated via the Employee PATCH endpoint.
| Property | Type | Required | Description |
|---|---|---|---|
address1 |
string | No | Street address (Gateadresse). Max 200 characters. |
postalLocation |
string | No | Postal location (Poststed). Max 200 characters. |
postalCode |
string | No | Postal code (Postnummer). For Norwegian addresses, must be a valid 4-digit code. |
countryCode |
string | Conditional | Country code, ISO 3166-1 alpha-2 (Landkode). Required when any address field is provided. |
homePhone |
string | No | Private phone number (Hjemmetelefon). 8–16 characters. |
workPhone |
string | No | Work phone number (Jobbtelefon). 8–16 characters. |
homeEmail |
string | No | Personal email address (Privat e-post). Max 135 characters. Must be a valid email format. |
workEmail |
string | No | Work email address (Jobb e-post). Max 135 characters. Must be a valid email format. |
emergencyContacts |
array | No | Array of emergency contact persons (Nødkontakter). See EmergencyContacts. |
Key Validation Rules
address1, postalLocation, postalCode) is provided, countryCode
is required.countryCode = NO), postalCode must be a valid 4-digit postal code.address1Street address line. Max 200 characters. Named address1 to allow for a future address2 field —
a single address line is not sufficient for many Norwegian addresses.
In the legacy system this was called
streetName, which was misleading because it holds the full street address including house number (there is no separate house number field).
postalLocationPostal location name. Max 200 characters. Most Norwegian postal locations are not cities, so
postalLocation is more accurate than the legacy cityName.
Note: When countryCode is NO, the legacy system auto-populated this field from a reference
table based on the postal code.
postalCodePostal code. For Norwegian addresses (countryCode = NO), must be a valid 4-digit Norwegian
postal code.
countryCodeaddress1, postalLocation,
postalCode) is provided.Validation
homePhonePrivate phone number. Must be 8–16 characters. Must be unique across the employee's phone numbers
(no duplicate with workPhone).
Norwegian phone numbers are 8 digits. International format: +47 followed by 8 digits.
workPhoneWork phone number. Must be 8–16 characters. Must be unique across the employee's phone numbers
(no duplicate with homePhone).
Renamed from legacy
businessPhone— shorter, same meaning, and avoids common misspellings.
homeEmailPersonal email address. Max 135 characters. Must be a valid email format. Must be unique across the employee's email addresses (case-insensitive domain comparison).
workEmailWork email address. Max 135 characters. Must be a valid email format. Must be unique across the employee's email addresses.
Renamed from legacy
businessEmail— shorter, same meaning.
Emergency contacts are stored as an array within contactDetails. In the legacy system, emergency
contacts and children were in the same relatives list; in the new service they are separated —
children are managed in the Children entity.
| Property | Type | Required | Description |
|---|---|---|---|
firstName |
string | Yes | Emergency contact's first name (Fornavn). |
lastName |
string | Yes | Emergency contact's last name (Etternavn). |
mainContact |
boolean | No | Whether this is the primary emergency contact (Hovedkontakt). |
phoneNumber |
string | No | Contact phone number (Telefonnummer). |
email |
string | No | Contact email address (E-post). |
Example: Create Employee with Contact Details
Contact details are embedded in the Employee entity. Supply them in the contactDetails object
when creating an employee:
POST /tenants/{tenantId}/employees/with-positions
Authorization: Bearer <token>
Content-Type: application/json
{
"employee": {
"number": "1001",
"isDraft": false,
"contactDetails": {
"address1": "Storgata 1",
"postalLocation": "Oslo",
"postalCode": "0155",
"countryCode": "NO",
"homePhone": "+4712345678",
"workPhone": "+4787654321",
"homeEmail": "ola.nordmann@example.com",
"workEmail": "ola.nordmann@company.no",
"emergencyContacts": [
{
"firstName": "Kari",
"lastName": "Nordmann",
"mainContact": true,
"phoneNumber": "+4798765432",
"email": "kari.nordmann@example.com"
}
]
}
},
"positions": [
{
"from": "2026-05-01",
"jobId": "b2c3d4e5-6f7a-8b9c-0d1e-2f3a4b5c6d7e"
}
]
}
A successful request returns 201 Created with the full Employee resource, including the
server-generated id and updatedAt.
Wage deductions ordered by enforcement authorities. Employers are legally obligated to deduct and remit these amounts from the employee's salary. Each claim represents a single claim order with defined period and deduction parameters.
Creditor master data (name, account number, etc.) lives in the Org API and is out of scope here — this entity only stores the claim link and deduction parameters.
Timeline type: Flexible — gaps and overlaps allowed, to may be
open-ended. Multiple concurrent claims are permitted (max 10 per type).
| Property | Type | Required | Description |
|---|---|---|---|
id |
UUID | (read-only) | Unique claim identifier. |
employeeId |
UUID | (read-only) | Employee this claim belongs to. |
type |
enum | Yes | Claim type determining creditor, validation rules, and A-melding reporting. See Claim Types. |
creditorId |
string | Yes | Foreign key to a creditor in the Org API. System-defined for most types; user-selectable for userDefined. |
from |
date | Yes | Deduction start date. |
to |
date | No | Deduction end date. null means ongoing. |
startAmount |
string | Conditional | Original total debt amount. Optional for legalOffence, tax, governmentClaim, userDefined; prohibited otherwise. |
amount |
string | One-of | Fixed deduction per pay period. Exactly one of amount or percentage must be provided (except childSupport: amount-only). |
percentage |
string | One-of | Percentage of tax basis. Exactly one of amount or percentage must be provided. |
incomeYear |
integer | Conditional | Income/tax year. Optional when type is tax; prohibited otherwise. |
kidNumber |
string | Conditional | Norwegian payment reference number (KID-nummer). Mandatory when type is coordinated; optional otherwise. |
description |
string | Conditional | Free-text description. Prohibited when type is coordinated; optional otherwise. |
priority |
integer | (read-only) | Deduction priority order among concurrent claims. Lower values are deducted first. System-calculated. |
etag |
string | (read-only) | Opaque version identifier for optimistic concurrency. Must be included in PATCH request body. |
updatedAt |
datetime | (read-only) | Timestamp of last modification. |
The legacy monolith exposes a
deductionMethodenum (amountorpercentage). The Employee Core Service does not expose this field — it is inferred from whichever ofamountorpercentageis provided on write, following the same pattern as Additional Accounts.Sequence number assignment, protected income enforcement, and actual deduction calculations are performed by the payroll system, not this service. This service stores the claims — including deduction priority — and enforces validation only.
Key Validation Rules
creditorId must reference a valid creditor in the Org API, matching the system-defined ID for
the given type.amount or percentage must be provided — never both, never neither.type is childSupport, only amount is allowed (percentage-based deductions are
prohibited).coordinated claim must be the only active creditor claim for the employee during its
active period (no overlapping claims of any type).to, when provided, must be on or after from.type per employee.to) and create a new one.idUnique identifier for the creditor claim record. Generated by the service on create; never supplied by clients.
typechildSupport | legalOffence | governmentClaim | tax | coordinated | userDefinedDetermines the kind of garnishment, which creditor is valid, and how the claim is reported. See
Claim Types table above.
The type field determines:
creditorId is valid (system-defined types have a fixed creditor; userDefined references
a user-created creditor in the Org API)| Value | Description | Creditor ID in Monolith |
|---|---|---|
childSupport |
Child support payments | 2/0 (system-defined) |
legalOffence |
Compensation for legal offence | 3/0 (system-defined) |
governmentClaim |
Claims from state-owned company | 4/0 (system-defined) |
tax |
Unpaid tax debt | 8/0 (system-defined) |
coordinated |
Coordinated attachment of earnings | 10/0 (system-defined) |
userDefined |
Other legal deductions | User-defined (Org API) |
Validation
When a coordinated claim is active:
kidNumber field is mandatorydescription field is prohibitedcreditorIdForeign key to a creditor defined in the Org API. For system-defined claim types (childSupport,
legalOffence, governmentClaim, tax, coordinated), a fixed creditor ID is mandated (see Claim
Types table). For userDefined, this must reference a valid user-created creditor in the Org API.
fromYYYY-MM-DD)Date the deduction starts. Future dates are allowed.
toYYYY-MM-DD)Date the deduction ends. null (or omitted) means the claim is ongoing. Setting to is the
standard way to end an active claim.
startAmountlegalOffence, tax, governmentClaim, userDefined;
prohibited for childSupport and coordinatedOriginal total debt amount. Informational only — the actual deduction is governed by amount or
percentage.
amountamount or percentage must be providedFixed deduction amount per pay period. When provided, the backend infers the deduction method (in
EmpMan monolith) as amount.
For childSupport, only amount is allowed (percentage is prohibited).
Validation
percentage is absent.percentage.percentageamount or percentage must be providedPercentage of tax basis to deduct each period. When provided, the backend infers the deduction
method as percentage.
Validation
amount is absent.amount.incomeYeartype is tax; prohibited otherwiseThe income/tax year the claim relates to.
Validation
type is tax.1900 and 9999.kidNumbertype is coordinated; optional otherwiseNorwegian payment reference number (KID-nummer — KundeIDentifikasjonsnummer). This is a structured payment reference following Norwegian banking standards, used by banks and creditors to identify the payment. It is a specific financial routing identifier.
Validation
type is coordinated.descriptiontype is coordinated; optional otherwiseFree-text description of the claim (e.g., "Unpaid tax 2023", "Credit card debt collection").
Validation
type is coordinated.priorityDeduction priority order among concurrent claims for the same employee. Lower values indicate higher priority (deducted first). When multiple active claims exist, the payroll system processes deductions in ascending priority order, respecting the protected income limit (livsoppholdssats).
Conventional priority ordering follows Norwegian enforcement authority guidelines:
| Priority | Claim Type | Norwegian Term | Sequence Range |
|---|---|---|---|
| 1st | Coordinated | Samordnet utleggstrekk | 1–10 |
| 2nd | Child support | Barnebidrag | 11–20 |
| 3rd | Legal offence | Erstatning ved lovbrudd | 21–30 |
| 4th | Unpaid tax | Restskatt | 31–40 |
| 5th | Government claim | Statens innkrevingssentral | 41–50 |
| 6th | User-defined | Andre trekk | 51–60 |
For coordinated claims during the 2026–2029 transition period, priority follows the coordinating
authority's instructions and is not bound by conventional ordering.
updatedAtTimestamp of the last modification to the record. Set by the service on every write.
From 2026, Norwegian authorities are transitioning to coordinated garnishments (samordnet
utleggstrekk), consolidating multiple public creditor claims into a single deduction per employee.
The coordinated type is expected to become the only public-creditor claim type by 2029, fully
replacing individual tax, governmentClaim, and legalOffence claims.
Example
Create Tax creditor claim (fixed amount):
POST /tenants/{tenantId}/employees/{employeeId}/creditor-claims
Authorization: Bearer <token>
Content-Type: application/json
{
"type": "tax",
"creditorId": "8/0",
"from": "2026-01-01",
"to": "2027-12-31",
"startAmount": "50000.00",
"amount": "2500.00",
"incomeYear": 2024,
"description": "Unpaid tax 2024"
}
Coordinated claim (percentage-based):
{
"type": "coordinated",
"creditorId": "10/0",
"from": "2026-06-01",
"percentage": "15.00",
"kidNumber": "12345678903"
}
A successful request returns 201 Created with the full CreditorClaim resource, including the
server-generated id and updatedAt.
| Event | Trigger | Consumers |
|---|---|---|
creditorClaim.created |
New claim registered | Payroll |
creditorClaim.updated |
Existing claim modified (e.g. to date set to end claim) |
Payroll |
creditorClaim.deleted |
Claim removed | Payroll |
From 2026, Norwegian authorities are transitioning to coordinated garnishments (samordnet
utleggstrekk), consolidating multiple public creditor claims into a single deduction per employee.
The coordinated type is expected to become the only public-creditor claim type by 2029, fully
replacing individual tax, governmentClaim, and legalOffence claims.
Example
Create Tax creditor claim (fixed amount):
POST /tenants/{tenantId}/employees/{employeeId}/creditor-claims
Authorization: Bearer <token>
Content-Type: application/json
{
"type": "tax",
"creditorId": "8/0",
"from": "2026-01-01",
"to": "2027-12-31",
"startAmount": "50000.00",
"amount": "2500.00",
"incomeYear": 2024,
"description": "Unpaid tax 2024"
}
Coordinated claim (percentage-based):
{
"type": "coordinated",
"creditorId": "10/0",
"from": "2026-06-01",
"percentage": "15.00",
"kidNumber": "12345678903"
}
A successful request returns 201 Created with the full CreditorClaim resource, including the
server-generated id and updatedAt.
| Event | Trigger | Consumers |
|---|---|---|
creditorClaim.created |
New claim registered | Payroll |
creditorClaim.updated |
Existing claim modified (e.g. to date set to end claim) |
Payroll |
creditorClaim.deleted |
Claim removed | Payroll |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| asOfDate | string <date> Filter timeline entities active as of this date |
| pageSize | integer [ 1 .. 1000 ] Parameter indicates the number of results that the client would like to see in the response. |
| x-cursor | string or null Pagination token used to query for the next part of a list. |
[- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "creditor": "string",
- "creditorPaymentType": "string",
- "startAmount": "string",
- "deductionMethod": "amount",
- "amount": "string",
- "percentage": "string",
- "incomeYear": 0,
- "description": "string",
- "referenceNumber": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
]| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| id | string <uuid> Optional client-provided identifier. If omitted, a server-generated UUID is assigned. If the ID already exists, a 409 Conflict is returned. |
| creditor | string or null (creditor) Creditor name (Kreditor) - e.g., NAV, Skatteetaten, private creditor Monolith notes: Field "Creditor" (5f7c9e6a-8c04-40d3-80b7-04287ae4a694). |
| creditorPaymentType | string or null (creditorPaymentType) Payment reference type for creditor Monolith notes: Field "Creditor payment type" (4697d649-b786-49f4-a052-5df6d8f4495d). |
| startAmount | string (startAmount) Original debt amount (Opprinnelig beløp) Monolith notes: Field "Start amount" (b5253714-9650-42d6-88a4-6468109f6652). |
| deductionMethod | string or null (creditorDeductionMethod) Enum: "amount" "percentage" How to calculate deduction:
Monolith notes: Field "Deduction method" (103dca57-eacb-439d-9349-52075b626941). |
| amount | string (amount) Deduction amount when method is 'amount' Monolith notes: Field "Amount" (6c3fb0d6-5193-4ba0-872f-b4dcb082d6f1). |
| percentage | string <decimal-13-2> (percentage-2) ^-?\d{1,11}(\.\d{1,2})?$ Deduction percentage when method is 'percentage' Monolith notes: Field "Percentage" (20837836-1af4-4afa-a7df-27c8661e16e7). |
| incomeYear | integer (incomeYear) Income year the claim relates to (Inntektsår) Monolith notes: Field "Income year" (837d9c6c-0c4b-47c9-93c4-96d7c17640f9). |
| description | string or null (claimDescription) Description of the claim Monolith notes: Field "Description" (989e8ef6-c262-4ff1-8bc8-835f33339b4e). |
| referenceNumber | string or null (referenceNumber) Case/reference number from enforcement authority (Saksnummer) Monolith notes: Field "Reference number" (f3313acd-5720-4a07-8de2-23421afd8fd3). |
| from required | string <date> Effective-from date |
| to | string or null <date> Effective-until date |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "creditor": "string",
- "creditorPaymentType": "string",
- "startAmount": "string",
- "deductionMethod": "amount",
- "amount": "string",
- "percentage": "string",
- "incomeYear": 0,
- "description": "string",
- "referenceNumber": "string",
- "from": "2019-08-24",
- "to": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "creditor": "string",
- "creditorPaymentType": "string",
- "startAmount": "string",
- "deductionMethod": "amount",
- "amount": "string",
- "percentage": "string",
- "incomeYear": 0,
- "description": "string",
- "referenceNumber": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| creditorClaimId required | string <uuid> Creditor claim unique identifier |
{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "creditor": "string",
- "creditorPaymentType": "string",
- "startAmount": "string",
- "deductionMethod": "amount",
- "amount": "string",
- "percentage": "string",
- "incomeYear": 0,
- "description": "string",
- "referenceNumber": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| creditorClaimId required | string <uuid> Creditor claim unique identifier |
| creditor | string or null (creditor) Creditor name (Kreditor) - e.g., NAV, Skatteetaten, private creditor Monolith notes: Field "Creditor" (5f7c9e6a-8c04-40d3-80b7-04287ae4a694). |
| creditorPaymentType | string or null (creditorPaymentType) Payment reference type for creditor Monolith notes: Field "Creditor payment type" (4697d649-b786-49f4-a052-5df6d8f4495d). |
| startAmount | string (startAmount) Original debt amount (Opprinnelig beløp) Monolith notes: Field "Start amount" (b5253714-9650-42d6-88a4-6468109f6652). |
| deductionMethod | string or null (creditorDeductionMethod) Enum: "amount" "percentage" How to calculate deduction:
Monolith notes: Field "Deduction method" (103dca57-eacb-439d-9349-52075b626941). |
| amount | string (amount) Deduction amount when method is 'amount' Monolith notes: Field "Amount" (6c3fb0d6-5193-4ba0-872f-b4dcb082d6f1). |
| percentage | string <decimal-13-2> (percentage-2) ^-?\d{1,11}(\.\d{1,2})?$ Deduction percentage when method is 'percentage' Monolith notes: Field "Percentage" (20837836-1af4-4afa-a7df-27c8661e16e7). |
| incomeYear | integer (incomeYear) Income year the claim relates to (Inntektsår) Monolith notes: Field "Income year" (837d9c6c-0c4b-47c9-93c4-96d7c17640f9). |
| description | string or null (claimDescription) Description of the claim Monolith notes: Field "Description" (989e8ef6-c262-4ff1-8bc8-835f33339b4e). |
| referenceNumber | string or null (referenceNumber) Case/reference number from enforcement authority (Saksnummer) Monolith notes: Field "Reference number" (f3313acd-5720-4a07-8de2-23421afd8fd3). |
| etag required | string Opaque version identifier for optimistic concurrency control. Must be included in PATCH request body. |
| from required | string <date> Effective-from date |
| to | string or null <date> Effective-until date |
{- "creditor": "string",
- "creditorPaymentType": "string",
- "startAmount": "string",
- "deductionMethod": "amount",
- "amount": "string",
- "percentage": "string",
- "incomeYear": 0,
- "description": "string",
- "referenceNumber": "string",
- "etag": "1",
- "from": "2019-08-24",
- "to": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "creditor": "string",
- "creditorPaymentType": "string",
- "startAmount": "string",
- "deductionMethod": "amount",
- "amount": "string",
- "percentage": "string",
- "incomeYear": 0,
- "description": "string",
- "referenceNumber": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| creditorClaimId required | string <uuid> Creditor claim unique identifier |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}People to contact in case of an employee emergency. Typically a spouse, partner, parent, or close relative.
Emergency contacts are not a standalone resource — they are stored as an array on the embedded
contactDetails object of an Employee. In the legacy system they shared the
relatives list with children; in the new service they are separated — children are managed as
their own entity (see Children).
Entity type: Embedded array (no timeline, no id) — managed via the Employee PATCH endpoint by
sending the full replacement array on contactDetails.emergencyContacts.
| Property | Type | Required | Description |
|---|---|---|---|
firstName |
string | Yes | Emergency contact's first name. |
lastName |
string | Yes | Emergency contact's last name. |
mainContact |
boolean | No | Whether this is the primary emergency contact. |
phoneNumber |
string | No | Contact phone number. null when not provided. |
email |
string | No | Contact email address. Must be a valid email. null allowed. |
Key Validation Rules
firstName and lastName are required on every entry and must not be empty.email, when provided, must be a valid email format.emergencyContacts from a PATCH preserves the
existing array; providing an empty array ([]) clears all contacts.firstNameFirst name of the emergency contact. Required on every entry in the array and must not be empty or whitespace-only.
lastNameLast name of the emergency contact. Required on every entry in the array and must not be empty or whitespace-only.
mainContactMarks this entry as the primary emergency contact — the person to call first. When omitted,
defaults to false. At most one contact per employee should have mainContact = true; when
multiple are marked, the first one in the array is treated as primary.
phoneNumberPhone number to reach the contact.
emailEmail address for the contact.
Emergency contacts are embedded in the Employee resource and do not publish a dedicated event
topic. Changes are surfaced through the Employee's employee.updated event.
| Event | Trigger | Consumers |
|---|---|---|
employee.updated |
Emergency contacts added, modified, or cleared via Employee PATCH | Payroll, A-melding |
Read-only view of the Visma Connect user account linked to this employee. Provides the identity-system details (first name, last name, email, account status) so clients can correlate an HR employee record with the corresponding SSO/login account.
The fields are sourced from Visma Connect and managed externally through Visma.net Admin — Employee
Core never writes to them. Attempts to set linkedUserData in a create or update request are
ignored.
Entity type: Embedded object (no timeline) — appears as the linkedUserData property on the
Employee resource.
| Property | Type | Required | Description |
|---|---|---|---|
firstName |
string | (read-only) | User account first name from Visma Connect. |
lastName |
string | (read-only) | User account last name from Visma Connect. |
email |
string (email) | (read-only) | User account login email from Visma Connect. |
status |
string | (read-only) | User account status (e.g. active, pending, inactive, suspended). |
odpUserId |
string | (read-only) | Visma Connect (ODP) user account identifier. Set once the account has been successfully created. |
linkedUserData is populated by Visma Connect, not by callers of this API. The typical flow is:
contactDetails.workEmail (business
email).linkedUserData.odpUserId is populated with
the account identifier.linkedUserData fields are populated.linkedUserData.status.Until the account exists and is activated, linkedUserData is null on the Employee resource.
Status: Planned — not yet implemented. The endpoint described below is on the roadmap; integrators cannot call it today. In the current service, Visma Connect provisioning must still be initiated through Visma.net Admin.
Employee Core will expose a dedicated endpoint for triggering Visma Connect user account creation, so integrators do not need to switch tools to onboard an employee end-to-end:
POST /tenants/{tenantId}/employees/{employeeId}/user
Authorization: Bearer <token>
Planned behavior:
contactDetails.workEmail, and the organization
must have user creation enabled in Visma Connect.202 Accepted — account provisioning is asynchronous. linkedUserData
on the Employee resource becomes populated once Visma Connect finishes activation (see the
Lifecycle flow above).Until this endpoint ships, integrators should treat linkedUserData as pure read-only and drive
user creation through Visma.net Admin.
Key Validation Rules
linkedUserData and all of its fields are read-only. Values supplied by clients on POST/PATCH are
ignored — no error is returned, but the data is not persisted.contactDetails.workEmail must not match linkedUserData.email. The business email is
separate from the identity-system login email.personalInformation.firstName / personalInformation.lastName should match
linkedUserData.firstName / linkedUserData.lastName (case-insensitive) — mismatches surface as
a warning, not a blocking error.firstNameUser's first name as registered in the Visma Connect identity system. May differ from
personalInformation.firstName (legal name) — for example, a preferred name used in IT systems.
lastNameUser's last name as registered in the Visma Connect identity system. May differ from
personalInformation.lastName for the same reasons as firstName.
emailLogin email for the Visma Connect user account. This is the address the employee uses to sign in
and receive activation/notification messages from Connect. It is distinct from
contactDetails.workEmail and contactDetails.homeEmail, and must not equal
contactDetails.workEmail.
statusCurrent state of the Visma Connect user account. Typical values:
| Value | Meaning |
|---|---|
active |
Account is provisioned and the user can sign in. |
pending |
Invitation sent; awaiting employee activation. |
inactive |
Account exists but is disabled. |
suspended |
Account temporarily blocked (e.g. by admin). |
Status changes are driven by Visma Connect and Visma.net Admin, not by this service.
odpUserIdIdentifier of the linked Visma Connect (ODP) user account. Set by Connect once the user account has
been successfully created — the presence of this value is the signal that provisioning completed.
While the account is being provisioned, or if no account exists for the employee, odpUserId is
null.
Exposed as a string because the underlying value is a 64-bit integer and can exceed the JavaScript safe-integer range (2^53). Clients that need to treat the value numerically must use a big-integer-safe representation.
linkedUserData is an embedded part of the Employee resource and has no events of its own. Changes
to it — driven by Visma Connect — are surfaced through the standard Employee event stream.
| Event | Trigger | Consumers |
|---|---|---|
employee.updated |
Any change to the Employee resource, including updates to linkedUserData. |
Downstream services |
Payroll and payment settings for the employee (Lønnsinnstillinger). Covers salary payment method, bank account details, payslip format, and tax-card retrieval preferences. This entity is an embedded object on the Employee resource — it is not timelined, and changes only affect future payments.
Payroll Settings does not compute tax, deductions, or payment runs. Those are performed by the payroll system; this service only stores the configuration used by payroll.
Entity type: Embedded object (no timeline) — appears as the payrollSettings property on the
Employee resource.
| Property | Type | Required | Description |
|---|---|---|---|
payslipOnPaper |
boolean | No | Generate a paper payslip in addition to the electronic one. Default: false. |
payslipLanguage |
enum | No | Payslip language: norwegian (default) or english. |
paymentType |
enum | Yes | Salary payment method: bank or cash. |
norwegianBankAccount |
string | Conditional | Norwegian bank account number. 11 digits with MOD11 check digit. Required when paymentType = bank and internationalBank is not provided. |
internationalBank |
object | Conditional | International bank account details (IBAN, SWIFT, country, remittance country). Required when paymentType = bank and payment is to a foreign bank account. |
internationalBank.iban |
string | Yes | IBAN for international transfers. Length and format depend on the country (e.g. Norwegian IBAN: NO + 2 check digits + 11-digit account number, 15 characters total). |
internationalBank.swift |
string | Yes | BIC/SWIFT code identifying the bank. 8 or 11 characters (e.g. DNBANOKKXXX). |
internationalBank.country |
string | Yes | Country where the bank is located. ISO 3166-1 alpha-2 code. |
internationalBank.remittanceCountry |
string | Yes | Remittance destination country. ISO 3166-1 alpha-2 code. May differ from country. |
retrieveTaxCardOnWageRun |
boolean | No | When true, the tax card is fetched from Skatteetaten at the start of each wage run. Default: true. |
lastTaxCardRetrieveDate |
date | (read-only) | Date the tax card was last retrieved from Skatteetaten. Managed by the service. |
Tax card retrieval, payment execution, and A-melding reporting are performed by the payroll system and a background process, not by this service. This service stores the configuration and enforces validation only.
Key Validation Rules
paymentType is required. Must be bank or cash.paymentType = bank, exactly one of norwegianBankAccount or internationalBank must be
provided.paymentType = cash, neither norwegianBankAccount nor internationalBank may be
provided.norwegianBankAccount, when provided, must be an 11-digit numeric string with a valid MOD11
check digit.internationalBank, when provided, must contain all four sub-fields (iban, swift, country,
remittanceCountry).internationalBank.country and internationalBank.remittanceCountry must be valid ISO 3166-1
alpha-2 codes.lastTaxCardRetrieveDate is read-only and must not be supplied on create or update.payslipOnPaperfalse)Whether the payroll system should generate a paper payslip in addition to the electronic one. A paper payslip is a PDF artefact intended for print — the service does not physically print anything.
Feedback (pending schema change): this property is proposed to be renamed from
printPaysliptopayslipOnPaperto avoid the implication that the service itself triggers printing. The YAML schema still usesprintPayslip— the rename will be applied in a follow-up change.
payslipLanguagenorwegian | englishnorwegian)Language used when the payroll system renders the payslip. Intended to make the default locale explicit and to leave room for additional languages later.
| Value | Description |
|---|---|
norwegian |
Render payslip in Norwegian (default). |
english |
Render payslip in English — typically for non-Norwegian speakers. |
Feedback (pending schema change): this property is proposed to be renamed from the boolean
payslipInEnglishto the enumpayslipLanguage, so that the default is explicit (Norwegian) and additional languages can be added without introducing new boolean flags. The YAML schema still usespayslipInEnglish— the rename will be applied in a follow-up change.
paymentTypebank | cashHow the employee's salary is paid out.
| Value | Norwegian | Description |
|---|---|---|
bank |
Bankoverføring | Salary paid by bank transfer. Requires exactly one of norwegianBankAccount or internationalBank. |
cash |
Kontant | Salary paid in cash. No bank account fields may be provided. Cash payments have additional documentation requirements for the employer. |
norwegianBankAccountpaymentType = bank and internationalBank is not
provided; prohibited otherwiseNorwegian bank account number. Stored as an 11-digit numeric string.
The 11th digit is a check digit calculated using the Norwegian MOD11 algorithm and is validated on write.
internationalBankpaymentType = bank and the employee is paid to a
foreign bank account; prohibited otherwiseInternational bank account details for salary paid outside Norway. Grouped as a nested object so the related fields stay together and the caller can tell at a glance which fields belong to an international payment.
| Sub-property | Type | Required | Description |
|---|---|---|---|
iban |
string | Yes | IBAN for international transfers. Length and format depend on the country (e.g. Norwegian IBAN: NO + 2 check digits + 11-digit account number, 15 characters total). |
swift |
string | Yes | BIC/SWIFT code identifying the bank. 8 or 11 characters (e.g. DNBANOKKXXX). |
country |
string | Yes | Country where the bank is located. ISO 3166-1 alpha-2 code. |
remittanceCountry |
string | Yes | Remittance destination country. ISO 3166-1 alpha-2 code. May differ from country. |
retrieveTaxCardOnWageRuntrue)When true, the payroll system automatically fetches this employee's tax card from Skatteetaten
(via Altinn/EDAG) at the start of each wage run. When false, the tax card properties must be
updated manually.
lastTaxCardRetrieveDateYYYY-MM-DD)Date on which the tax card was last retrieved from Skatteetaten. Set by the service whenever a
retrieval completes (either triggered manually or by a wage run with
retrieveTaxCardOnWageRun = true). Clients may read this field but may not set it.
Example: Create Employee with Payroll Settings (Norwegian bank account)
POST /tenants/{tenantId}/employees
Authorization: Bearer <token>
Content-Type: application/json
{
"number": "1001",
"payrollSettings": {
"paymentType": "bank",
"norwegianBankAccount": "12345678903",
"payslipOnPaper": false,
"payslipLanguage": "norwegian",
"retrieveTaxCardOnWageRun": true
}
}
Example: Create Employee with Payroll Settings (international bank account)
POST /tenants/{tenantId}/employees
Authorization: Bearer <token>
Content-Type: application/json
{
"number": "1002",
"payrollSettings": {
"paymentType": "bank",
"internationalBank": {
"iban": "SE3550000000054910000003",
"swift": "ESSESESS",
"country": "SE",
"remittanceCountry": "SE"
},
"payslipLanguage": "english"
}
}
A successful request returns 201 Created with the full Employee resource, including the
persisted payrollSettings.
payrollSettings is an embedded part of the Employee resource and has no events of its own.
Changes to it are surfaced through the standard Employee event stream.
| Event | Trigger | Consumers |
|---|---|---|
employee.updated |
Any change to the Employee resource, including updates to payrollSettings. |
Payroll, A-melding exporter |
Links an employee to a pension provider (Pensjonsleverandør) so payroll can calculate and report occupational pension contributions. Central to OTP (Obligatorisk tjenestepensjon — Mandatory Occupational Pension) compliance in Norway.
Pension company master data (name, organisation number, contribution rates, tier thresholds, active
period) lives in the Org API (/pensions, available via /icLookup) and is out of scope here. This
entity only stores the link between an employee and a pension company plus the effective-date range.
Timeline type: Flexible — gaps allowed, to may be open-ended. Overlaps
are not allowed: at most one pension link may be active on any given date for a single employee.
| Property | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes (read-only) | Unique pension link identifier. Server-generated on create. |
from |
date | Yes | Enrolment start date. |
to |
date | No | Enrolment end date. null means ongoing. |
pensionLinkId |
string | No | Foreign key to a pension company in the Org API (Pensjonsleverandør-ID). |
etag |
string | (read-only) | Opaque version identifier for optimistic concurrency. Must be included in PATCH request body. |
updatedAt |
datetime | (read-only) | Timestamp of last modification. |
Employer contribution rates, employee deduction rates, tier calculations, and A-melding pension reporting are produced by the Org API (pension company settings) and the payroll system, not by this service. This service only stores the link and publishes events.
Key Validation Rules
pensionLinkId, when provided, must reference a pension company that exists and is active in the
Org API for the entire link period (from–to).from is required and must be a valid date between 1910-04-15 and 2089-09-17.to, when provided, must be on or after from and within both the pension company's active
period and the employee's active position/contract period.etag must match the current version on updates (optimistic concurrency).idUnique identifier for the pension link record. Generated by the service on create; never supplied by clients.
fromYYYY-MM-DD)Date the pension enrolment starts. Must fall within both the pension company's active period in the Org API and the employee's position/contract period. Future dates are allowed.
toYYYY-MM-DD)Date the pension enrolment ends. null (or omitted) means the enrolment is ongoing. When provided,
must be on or after from and within the pension company's and employee's active periods. Setting
to is the standard way to close an open-ended link — the supported in-place modification on an
existing link. To switch provider, end the current link and create a new one starting the next day.
If
tois accidentally set to a past date, the link cannot be re-opened — the only recovery is to delete the entry and create a similar one. This may cause retroactive changes that cancel each other out in payroll.
pensionLinkIdForeign key to a pension company in the Org API. Must reference an existing, active pension company in the Org API for the entire link period. Clients must gracefully handle an invalid reference and require the end user to fix it.
etagOpaque version identifier used for optimistic concurrency control. Returned by the service on every
read and must be included in PATCH request bodies. If the etag does not match the current
version, the update is rejected with 409 Conflict.
updatedAtTimestamp of the last modification to the record. Set by the service on every write.
Example: Create Pension Link
POST /tenants/{tenantId}/employees/{employeeId}/pension-links
Authorization: Bearer <token>
Content-Type: application/json
{
"from": "2026-05-01",
"pensionLinkId": "958935420"
}
A successful request returns 201 Created with the full PensionLink resource, including the
server-generated id, employeeId, etag, and updatedAt. Omit to to register an open-ended
enrolment.
| Event | Trigger | Consumers |
|---|---|---|
pensionLink.created |
New pension link registered on employee | Payroll |
pensionLink.updated |
Existing pension link modified (e.g. to date set to end the link) |
Payroll |
pensionLink.deleted |
Pension link removed from employee | Payroll |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| asOfDate | string <date> Filter timeline entities active as of this date |
| pageSize | integer [ 1 .. 1000 ] Parameter indicates the number of results that the client would like to see in the response. |
| x-cursor | string or null Pagination token used to query for the next part of a list. |
[- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "pensionLinkId": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
]| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| id | string <uuid> Optional client-provided identifier. If omitted, a server-generated UUID is assigned. If the ID already exists, a 409 Conflict is returned. |
| pensionLinkId | string or null (pensionLinkId) Pension company identifier (Pensjonsleverandør-ID) Monolith notes: Field "Pension company" (8ecd6a2c-418e-4347-8884-ba5b9d46d8f8). |
| from required | string <date> Effective-from date |
| to | string or null <date> Effective-until date |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "pensionLinkId": "string",
- "from": "2019-08-24",
- "to": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "pensionLinkId": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| pensionLinkId required | string <uuid> Pension link unique identifier |
{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "pensionLinkId": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| pensionLinkId required | string <uuid> Pension link unique identifier |
| pensionLinkId | string or null (pensionLinkId) Pension company identifier (Pensjonsleverandør-ID) Monolith notes: Field "Pension company" (8ecd6a2c-418e-4347-8884-ba5b9d46d8f8). |
| etag required | string Opaque version identifier for optimistic concurrency control. Must be included in PATCH request body. |
| from required | string <date> Effective-from date |
| to | string or null <date> Effective-until date |
{- "pensionLinkId": "string",
- "etag": "1",
- "from": "2019-08-24",
- "to": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "pensionLinkId": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| pensionLinkId required | string <uuid> Pension link unique identifier |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}Identity and personal details for an employee — legal name, government-issued identification, gender, and date of birth.
Contact details (address, email, phone) are managed separately under the
contactDetails entity and are not part of personalInformation.
Singleton — at most one PersonalInformation record per employee, no timeline. Manage it via
the dedicated personal-information endpoint (GET, POST, PATCH, DELETE); creating a second
record for the same employee returns 409 Conflict.
| Property | Type | Required | Description |
|---|---|---|---|
firstName |
string | Yes | Legal first name (Fornavn). Max 100 characters. |
lastName |
string | Yes | Legal last name (Etternavn). Max 100 characters. |
nationalId |
string | At-most-one | Norwegian national identity number (Fødselsnummer). Max 20 characters. |
dNumber |
string | At-most-one | D-number (D-nummer) for foreign workers without a permanent Norwegian ID. Max 20 characters. |
internationalId |
object | At-most-one | International identification. See sub-fields below. |
internationalId.type |
enum | Yes (within) | Type: Pass, SocialSecurity, TaxNo, or ValueAddedTaxNo. |
internationalId.value |
string | Yes (within) | The identification number. Max 50 characters. |
internationalId.countryCode |
string | No | Country code of issuance. Max 10 characters. |
gender |
enum | No | Female or Male. |
dateOfBirth |
date | No | Date of birth (ISO 8601, YYYY-MM-DD). Must not be a future date. |
etag |
string | (read-only) | Opaque version identifier for optimistic concurrency. Must be included in PATCH body and DELETE request. |
updatedAt |
datetime | (read-only) | Timestamp of last modification. |
At most one of nationalId, dNumber, or internationalId may be provided. All three may also be
omitted.
Key Validation Rules
firstName and lastName are required, must not be empty or whitespace-only, and are limited
to 100 characters.nationalId, dNumber, or internationalId may be provided (mutual exclusivity,
not strictly required).nationalId and dNumber: max 20 characters. Format-level validation (e.g. MOD11 check digits)
is not enforced by this service.internationalId is provided:type is required and must be a valid enum value.value is required, must not be empty, and is limited to 50 characters.countryCode, when provided, is limited to 10 characters.dateOfBirth, when provided, must not be a future date.dateOfBirth or gender from nationalId or dNumber — clients
must provide them explicitly if needed.etag must match the current version on PATCH and DELETE (optimistic concurrency); a
mismatch returns 409 Conflict.PersonalInformation record may exist per employee. Posting a second record returns
409 Conflict.firstNameLegal first name of the employee. Must not be empty or whitespace-only. Max 100 characters.
lastNameLegal last name of the employee. Must not be empty or whitespace-only. Max 100 characters.
nationalIdnationalId, dNumber, or internationalIdNorwegian national identity number (Fødselsnummer). Max 20 characters. 11 digits with valid MOD11 check digits.
Validation
dNumber and internationalId.dNumbernationalId, dNumber, or internationalIdD-number for foreign workers without a permanent Norwegian national ID. Max 20 characters. 11 digits with valid MOD11 check digits.
Validation
nationalId and internationalId.internationalIdnationalId, dNumber, or internationalIdInternational identification for employees without a Norwegian ID. The countryCode naming aligns
with the convention already used in contactDetails.countryCode.
Sub-fields
internationalId.type — enum (Pass | SocialSecurity | TaxNo | ValueAddedTaxNo). Required.internationalId.value — string, max 50 characters. Required, must not be empty.internationalId.countryCode — string, max 10 characters. Optional.Validation
type must be a valid enum value when internationalId is provided.value is required and must not be empty when internationalId is provided.nationalId and dNumber.genderFemale | MaleEmployee's gender. The service does not derive gender from nationalId or dNumber values.
dateOfBirthYYYY-MM-DD)Employee's date of birth. Must not be a future date. The service does not derive dateOfBirth
from nationalId or dNumber.
etagPATCH (in body) and DELETE (as parameter); returned on every readOpaque version identifier used for optimistic concurrency control. If the value does not match the
server's current version, the request returns 409 Conflict.
updatedAtTimestamp of the last modification to the record. Set by the service on every write.
Example: Create Personal Information
National ID:
POST /tenants/{tenantId}/employees/{employeeId}/personal-information
Authorization: Bearer <token>
Content-Type: application/json
{
"firstName": "Ola",
"lastName": "Nordmann",
"nationalId": "12345678901",
"gender": "Male",
"dateOfBirth": "1985-03-15"
}
International ID:
{
"firstName": "Jan",
"lastName": "Kowalski",
"internationalId": {
"type": "Pass",
"value": "AB1234567",
"countryCode": "PL"
},
"gender": "Male",
"dateOfBirth": "1990-07-22"
}
A successful request returns 201 Created with the full PersonalInformation resource, including
the id, employeeId, etag, and updatedAt. Posting a second record for the same employee
returns 409 Conflict.
| Event | Trigger | Consumers |
|---|---|---|
personalInformation.created |
New personal information record registered | Payroll, A-melding |
personalInformation.updated |
Record modified (e.g. name change) | Payroll, A-melding |
personalInformation.deleted |
Record removed | Payroll, A-melding |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "nationalId": "string",
- "dNumber": "string",
- "internationalId": {
- "type": "Pass",
- "value": "string",
- "countryCode": "string"
}, - "gender": "Female",
- "dateOfBirth": "2019-08-24",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| id | string <uuid> |
| firstName required | string or null (firstName) |
| lastName required | string or null (lastName) |
| nationalId | string or null (nationalId) |
| dNumber | string or null (dNumber) |
object or null (internationalId) | |
| gender | string or null (gender) Enum: "Female" "Male" |
| dateOfBirth | string or null <date> (dateOfBirth) |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "firstName": "string",
- "lastName": "string",
- "nationalId": "string",
- "dNumber": "string",
- "internationalId": {
- "type": "Pass",
- "value": "string",
- "countryCode": "string"
}, - "gender": "Female",
- "dateOfBirth": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "nationalId": "string",
- "dNumber": "string",
- "internationalId": {
- "type": "Pass",
- "value": "string",
- "countryCode": "string"
}, - "gender": "Female",
- "dateOfBirth": "2019-08-24",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| firstName | string or null (firstName) |
| lastName | string or null (lastName) |
| nationalId | string or null (nationalId) |
| dNumber | string or null (dNumber) |
object or null (internationalId) | |
| gender | string or null (gender) Enum: "Female" "Male" |
| dateOfBirth | string or null <date> (dateOfBirth) |
| etag required | string Opaque version identifier for optimistic concurrency control. Must be included in PATCH request body. |
{- "firstName": "string",
- "lastName": "string",
- "nationalId": "string",
- "dNumber": "string",
- "internationalId": {
- "type": "Pass",
- "value": "string",
- "countryCode": "string"
}, - "gender": "Female",
- "dateOfBirth": "2019-08-24",
- "etag": "1"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "firstName": "string",
- "lastName": "string",
- "nationalId": "string",
- "dNumber": "string",
- "internationalId": {
- "type": "Pass",
- "value": "string",
- "countryCode": "string"
}, - "gender": "Female",
- "dateOfBirth": "2019-08-24",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}Employee-level sickness and absence configuration that tracks periods when the employee holds chronically ill status. The status allows the employer to claim NAV reimbursement from day one of a sick leave instead of waiting the usual employer period, and is approved by NAV based on medical documentation.
Prepaid sickness, prepaid other absence, and redundancy periods are managed on position-level via
endpoint (positions/{positionId}/sickness-and-absence). Only chronicallyIllPeriods is stored on
the employee.
Timeline type: Flexible — multiple periods allowed with gaps between
them, but overlaps are not allowed. to may be open-ended.
| Property | Type | Required | Description |
|---|---|---|---|
chronicallyIllPeriods |
array | No | Periods when the employee has chronic illness status. See period shape below. |
chronicallyIllPeriods[].id |
UUID | Yes (read-only) | Unique period identifier. |
chronicallyIllPeriods[].from |
date | Yes | Period effective from date. |
chronicallyIllPeriods[].to |
date | No | Period effective until date. null means ongoing. |
lastModified |
datetime | (read-only) | Timestamp of the most recent modification. null when no periods exist. |
Key Validation Rules
from is required on every period and must be a valid date.to, when provided, must be on or after from.chronicallyIllPeriods must not overlap each other. Gaps between periods are
allowed; a new period may start on the day after a previous period's to, but not on or before
it.chronicallyIllPeriods is accepted at the employee level. Sending prepaidSicknessPeriods,
prepaidOtherAbsencePeriods, or redundancyPeriods here returns 400 — post those to the
position-level endpoint instead.asOfDate query parameter on GET to retrieve only periods active on a specific date
(from <= asOfDate AND (to is null OR to >= asOfDate)).chronicallyIllPeriodsArray of periods when the employee has chronic illness status recognised by NAV. When the current date falls within an active period, the employer can apply for NAV reimbursement from day one of a sick leave instead of after the standard employer period (typically day 17).
Multiple periods may be recorded to reflect changes over time — for example, if the status lapses and is later reinstated. Gaps between periods are allowed, but periods must not overlap: at any given date the employee is either chronically ill or not.
PATCH semantics
chronicallyIllPeriods from a PATCH request preserves the existing periods unchanged.[]) clears all chronically ill periods.chronicallyIllPeriods[].idUnique identifier for the period. Generated by the service; never supplied by clients.
chronicallyIllPeriods[].fromYYYY-MM-DD)Date the chronic illness status starts. Future dates are allowed.
chronicallyIllPeriods[].toYYYY-MM-DD)Date the chronic illness status ends. null (or omitted) means the status is ongoing. When
provided, must be on or after from.
lastModifiedTimestamp of the last modification to any period on this object. Set by the service on every
write. null when no periods have ever been recorded.
Example:
The employee-level sickness and absence resource is not created directly — it is created together
with the employee. Include sicknessAndAbsence.chronicallyIllPeriods in the POST /employees
body:
POST /tenants/{tenantId}/employees
Authorization: Bearer <token>
Content-Type: application/json
{
"number": "1001",
"sicknessAndAbsence": {
"chronicallyIllPeriods": [
{
"from": "2026-06-15"
}
]
}
}
A successful request returns 201 Created with the full Employee resource. Each period in the
response includes the server-generated id, and sicknessAndAbsence.lastModified is set to the
creation timestamp.
To add, replace, or clear periods on an existing employee, use
PATCH /tenants/{tenantId}/employees/{employeeId}/sickness-and-absence with a sicknessAndAbsence
body following the same shape.
Employee-level sickness and absence is embedded in the Employee resource and does not publish a
dedicated event topic. Changes to chronicallyIllPeriods are surfaced through the Employee's
employee.updated event.
| Event | Trigger | Consumers |
|---|---|---|
employee.updated |
chronicallyIllPeriods added, modified, or cleared via Employee or SaA PATCH |
Payroll, NAV |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| asOfDate | string <date> Filter timeline entities active as of this date |
{- "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "lastModified": "2019-08-24T14:15:22Z"
}Partially replaces sickness and absence periods. Only period types explicitly included in the request body are replaced; omitted types are preserved.
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
Array of objects (SicknessAndAbsencePeriod) Chronically ill periods (Kronisk syk) - affects sick leave quota.
PATCH: omit to preserve existing; Monolith notes: Field "Chronically ill" (0546c71c-3a0e-40f2-923a-8e48c1218577). |
{- "chronicallyIllPeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24"
}
]
}{- "chronicallyIllPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "lastModified": "2019-08-24T14:15:22Z"
}Tracks special tax and contribution rules that apply to an employee (Særregler for skatt og avgift)
— net salary arrangements, seafarer's deduction, Svalbard and Jan Mayen tax schemes. Each rule
affects how payroll calculates withholding and employer contributions, and is reported to A-melding
under spesielleInntektsforhold.
The A-melding report itself is generated by the payroll system; this service only stores the rule data and publishes events.
Timeline type: Flexible — gaps allowed, to may be open-ended. Multiple
rules of different types may be active concurrently, but two rules of the same
taxAndContributionRuleType must not overlap.
| Property | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes (read-only) | Unique rule identifier. Server-generated on create. |
from |
date | Yes | Rule effective from date. |
to |
date | No | Rule effective until date. null means ongoing. |
taxAndContributionRuleType |
enum | Yes | Type of special rule: JanMayen, netSalary, netSalaryForSeafarers, specialAllowanceForSeafarers, Svalbard. |
etag |
string | (read-only) | Opaque version identifier for optimistic concurrency. Must be included in PATCH request body. |
updatedAt |
datetime | (read-only) | Timestamp of last modification. |
The actual tax, withholding and A-melding values are computed by the payroll system, not this service. This service only stores the rule and publishes events so payroll can act on it.
Key Validation Rules
from is required and must be a valid date between 1910-04-15 and 2089-09-17.to, when provided, must be on or after from and within the same date bounds. Defaults to
null (ongoing) when unspecified.taxAndContributionRuleType is required and must be one of the enum values listed above.taxAndContributionRuleType must not have
overlapping date ranges on the same employee.nettoloenn and
saerskiltFradragForSjoefolk active at the same time).etag must match the current version on updates (optimistic concurrency).idUnique identifier for the rule record. Generated by the service on create; never supplied by clients.
fromYYYY-MM-DD)Date the rule starts applying. Future dates are allowed. Must be a valid date between 1910-04-15
and 2089-09-17.
toYYYY-MM-DD)Date the rule stops applying. null (or omitted) means the rule is ongoing. When provided, must
be on or after from. Setting to is the standard way to close an open-ended rule — the only
in-place modification supported on an existing rule. To change any other field, end the current
rule and create a new one.
taxAndContributionRuleTypeJanMayen | netSalary | netSalaryForSeafarers |
specialAllowanceForSeafarers | SvalbardClassifies the special rule. The value is passed through to A-melding as the
spesielleInntektsforhold code for the employment relationship:
| Value | Norwegian | Description |
|---|---|---|
JanMayen |
Jan Mayen og bilandene | Separate tax rules for employees on Jan Mayen and Norwegian dependencies. |
netSalary |
Nettolønn | Net salary arrangement — employer pays the employee's income tax on their behalf. |
netSalaryForSeafarers |
Nettolønn for sjøfolk | Net salary arrangement for seafarers — employer pays tax for maritime employees. |
specialAllowanceForSeafarers |
Særskilt fradrag for sjøfolk | Seafarer's deduction — 30% special deduction from maritime income (capped annually). |
Svalbard |
Svalbardskatteloven | Svalbard Tax Act — flat-rate taxation for employees working on Svalbard. |
etagOpaque version identifier used for optimistic concurrency control. Returned by the service on
every read and must be included in PATCH request bodies. If the etag does not match the current
version, the update is rejected with 409 Conflict.
updatedAtTimestamp of the last modification to the record. Set by the service on every write.
Example: Create Tax and Contribution Rule
POST /tenants/{tenantId}/employees/{employeeId}/tax-and-contribution-rules
Authorization: Bearer <token>
Content-Type: application/json
{
"from": "2026-05-01",
"to": "2027-12-31",
"taxAndContributionRuleType": "netSalary"
}
A successful request returns 201 Created with the full TaxAndContributionRule resource,
including the server-generated id, employeeId, etag, and updatedAt. Omit to to register
an open-ended rule.
| Event | Trigger | Consumers |
|---|---|---|
taxAndContributionRule.created |
New special rule registered on employee | Payroll |
taxAndContributionRule.updated |
Existing rule modified (e.g. to date set to end rule) |
Payroll |
taxAndContributionRule.deleted |
Rule removed from employee | Payroll |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| asOfDate | string <date> Filter timeline entities active as of this date |
| pageSize | integer [ 1 .. 1000 ] Parameter indicates the number of results that the client would like to see in the response. |
| x-cursor | string or null Pagination token used to query for the next part of a list. |
[- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "taxAndContributionRuleType": "JanMayen",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
]| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| id | string <uuid> Optional client-provided identifier. If omitted, a server-generated UUID is assigned. If the ID already exists, a 409 Conflict is returned. |
| taxAndContributionRuleType | string or null (taxAndContributionRuleType) Enum: "JanMayen" "nettoloenn" "nettoloennForSjoefolk" "saerskiltFradragForSjoefolk" "Svalbard" Type of special rule:
Monolith notes: Field "Tax and contribution rule type" (ac7c9f8d-517e-4d9d-ad20-72a885208c46). |
| from required | string <date> Effective-from date |
| to | string or null <date> Effective-until date |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "taxAndContributionRuleType": "JanMayen",
- "from": "2019-08-24",
- "to": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "taxAndContributionRuleType": "JanMayen",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| taxAndContributionRuleId required | string <uuid> Tax and contribution rule unique identifier |
{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "taxAndContributionRuleType": "JanMayen",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| taxAndContributionRuleId required | string <uuid> Tax and contribution rule unique identifier |
| taxAndContributionRuleType | string or null (taxAndContributionRuleType) Enum: "JanMayen" "nettoloenn" "nettoloennForSjoefolk" "saerskiltFradragForSjoefolk" "Svalbard" Type of special rule:
Monolith notes: Field "Tax and contribution rule type" (ac7c9f8d-517e-4d9d-ad20-72a885208c46). |
| etag required | string Opaque version identifier for optimistic concurrency control. Must be included in PATCH request body. |
| from required | string <date> Effective-from date |
| to | string or null <date> Effective-until date |
{- "taxAndContributionRuleType": "JanMayen",
- "etag": "1",
- "from": "2019-08-24",
- "to": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "taxAndContributionRuleType": "JanMayen",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| taxAndContributionRuleId required | string <uuid> Tax and contribution rule unique identifier |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}Tax Information contains the employee's tax deduction settings from their tax card. This entity uses a strict timeline, meaning changes create new records with no gaps or overlaps.
Timeline type: Strict
| Property | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes (read-only) | Unique record identifier |
from |
date | Yes | Effective date for these tax settings |
to |
date | (read-only) | Calculated end date of this record's validity period. Automatically set to the day before the next record's from. Null if this is the most recent record. |
mainEmployer |
boolean | No | Is this the main employer? |
borderCommuter |
boolean | No | Is employee a border commuter? |
borderCommuterTaxPercentage |
number | No | Border commuter tax percentage |
table |
string | No | Tax table number from tax card (4-digit pattern) |
percentage |
decimal | No | Tax deduction percentage. Mandatory if table is set, otherwise optional. Default 50 if required but not set. |
payeTaxPercentage |
decimal | No | PAYE withholding percentage for foreign workers |
hasExemptionCard |
boolean | No | Employee has tax exemption card |
exemptionCardAmount |
decimal | No | Remaining exemption card amount. Mandatory if hasExemptionCard is true, otherwise prohibited. |
isFullyWithholdingChristmasTax |
boolean | No | Apply full tax withholding before Christmas (overrides the default Christmas exemption) |
taxCardId |
string | No | Tax card identifier from Skatteetaten |
taxCardIncomeYear |
string | (read-only) | Income year the tax card applies to |
taxCardIssuedDate |
date | No | Date tax card was issued by Skatteetaten |
lastTaxCardRetrieveDate |
date | No | Date tax card was last retrieved by the service |
isPostedFromUsCanada |
boolean | No | Employee posted from US/Canada with tax treaty benefits |
taxFromFirstKroneForTaxFreeOrg |
boolean | No | Apply tax from first krone for tax-free organizations |
isReceivingPension |
boolean | No | Whether the employee receives pension through this employer. Gates all pension-related fields (pensionTable, pensionPercentage, etc.). |
pensionTable |
string | No | Pension tax table number (4-digit pattern) |
pensionPercentage |
decimal | No | Pension tax percentage. Mandatory if pensionTable is set, otherwise optional. Default 30 if required but not set. |
pensionPercentagePaye |
decimal | No | Pension PAYE tax percentage for source-tax pensioners |
hasPensionExemptionCard |
boolean | No | Pension exemption card (Frikort for pension) |
updatedAt |
datetime | (read-only) | Timestamp of last modification |
Tax deduction amounts, A-melding reporting, and tax card retrieval from Skatteetaten are performed by the payroll system and a background process, not by this service. This service stores tax settings and enforces validation only.
Key Validation Rules
percentage is mandatory when table is set. If required but not supplied, default to 50.exemptionCardAmount is mandatory when hasExemptionCard is true, prohibited otherwise.borderCommuterTaxPercentage — only allowed when borderCommuter is true; mandatory when
payrollSettings.retrieveTaxCardOnWageRun is also false.pensionPercentage is mandatory when pensionTable is set. If required but not supplied, default
to 30.pensionTable, pensionPercentage, pensionPercentagePaye,
hasPensionExemptionCard) are only relevant when isReceivingPension is true.table and pensionTable, when provided, must match the 4-digit pattern ^[0-9]{4}$.pensionPercentagePaye allows at most
1 decimal digit, the others allow 2.exemptionCardAmount must be non-negative with at most 2 decimal places.to is calculated automatically — only one record is active
at any date.payrollSettings.retrieveTaxCardOnWageRun is true, the system-managed fields (table,
percentage, payeTaxPercentage, borderCommuterTaxPercentage, hasExemptionCard,
exemptionCardAmount, pensionTable, pensionPercentage, pensionPercentagePaye,
hasPensionExemptionCard) must not be overwritten by external API consumers — they are updated by
the Skatteetaten retrieval background process.idUnique identifier for the tax information record. If the client supplies an id on create that
already exists, the service returns 409 Conflict.
fromYYYY-MM-DD)Effective date the tax settings become active. Future dates are allowed.
toYYYY-MM-DD)End date of this record's validity period. Calculated by the service as the day before the next
record's from. null when this is the most recent record (currently active).
mainEmployerIs this the main employer (Hovedarbeidsgiver)? Only main employers use table-based tax deduction; secondary employers use percentage-based deduction. An employee should have only one main employer at any time.
Feedback (pending schema change): this property is proposed to be renamed from
isMainEmployertomainEmployer(dropping theisprefix). The YAML schema has not yet been updated — the rename will be applied in a follow-up change.
borderCommuterIs the employee a border commuter (Grensependler)? Border commuters living in a neighbouring country
may qualify for a special tax rate set via borderCommuterTaxPercentage.
borderCommuterTaxPercentageBorder commuter tax percentage. Dependency on payrollSettings.retrieveTaxCardOnWageRun and borderCommuter:
retrieveTaxCardOnWageRun |
borderCommuter |
Behavior |
|---|---|---|
true |
true |
Optional |
false |
true |
Mandatory |
true |
false |
Prohibited |
false |
false |
Prohibited |
Skatteetaten schema: prosentsats where trekkode is
loennKunTrygdeavgiftTilUtenlandskBorgerSomGrensegjenger.
table^[0-9]{4}$)Tax table number (Trekktabell) from the tax card. Tax tables change annually — always use tables from the current year's tax card.
Skatteetaten schema: tabellnummer where trekkode is loennFraHovedarbeidsgiver.
percentagetable is set, optional otherwiseTax deduction percentage (Trekkprosent). If a value is required but not supplied, default to 50.
Skatteetaten schema: prosentsats where trekkode is loennFraHovedarbeidsgiver or loennFraBiarbeidsgiver.
payeTaxPercentagePAYE withholding percentage for foreign workers (Kildeskattprosent). PAYE is a simplified flat-rate scheme (currently 25 %) on gross income with no deductions or allowances.
Skatteetaten schema: prosentsats where trekkode is loennFraHovedarbeidsgiver or
loennFraBiarbeidsgiver and a tilleggsopplysning is kildeskattPaaLoenn.
hasExemptionCardEmployee has a tax exemption card (Frikort) — no tax is deducted up to the exemptionCardAmount
limit. Typically used by students and part-time workers.
Skatteetaten schema: true if frikortbeloep is set where trekkode is loennFraHovedarbeidsgiver
or loennFraBiarbeidsgiver.
exemptionCardAmounthasExemptionCard is true, prohibited otherwiseRemaining exemption card amount (Frikortbeløp). Once exhausted, normal tax deduction resumes.
Skatteetaten schema: frikortbeloep where trekkode is loennFraHovedarbeidsgiver or
loennFraBiarbeidsgiver.
isFullyWithholdingChristmasTaxtrue accepted; absence implies false)Override the default Christmas tax withholding exemption — when true, taxes before Christmas are
fully withheld. See the Christmas Tax Withholding Exemption section below.
taxCardIdSkatteetaten's identifier for this tax card.
Skatteetaten schema: skattekortidentifikator.
Feedback (pending schema change): this property — together with
taxCardIssuedDate, and possiblytaxCardIncomeYear— is proposed to move out of the stricttaxInformationtimeline.taxCardIdandtaxCardIssuedDatedescribe the tax-card document itself and do not need an active timeline; they fit better alongside the proposed entity forlastTaxCardRetrieveDate.taxCardIncomeYearmay still need an active timeline, pending design confirmation. The YAML schema has not yet been updated.
taxCardIncomeYearIncome year the tax card applies to.
Skatteetaten schema: inntektsaar.
Feedback (pending schema change): same as
taxCardId— candidate for moving out of the timeline. Whether this field needs an active timeline of its own is an open design question.
taxCardIssuedDateDate Skatteetaten issued the tax card. May be misleading if the parent record's values were changed manually after issuance.
Skatteetaten schema: utstedtDato.
Feedback (pending schema change): same as
taxCardId— candidate for moving out of the timeline alongside the proposedlastTaxCardRetrieveDateentity.
lastTaxCardRetrieveDateDate when Tax Card was last retrieved from Skatteetaten. Tax Card retrieval process is initiated from Payroll UI by users.
Pending (not yet implemented): a method to initiate the tax card retrieval process from Skatteetaten needs to be added to this service. It is planned but not yet implemented.
isPostedFromUsCanadaEmployee posted from US or Canada under a tax treaty. May qualify for treaty-based benefits and special social security arrangements.
taxFromFirstKroneForTaxFreeOrgtrue accepted; absence implies false)For tax-free organizations only. Deducts tax from the first krone to avoid a large catch-up withholding in the month total payments exceed 10 000 NOK, or when the employee would otherwise have underpaid tax. Payroll always reports from the first krone using the tax and contribution rule "Tax-free organisation"; this field controls the employee-side withholding.
pensionTable^[0-9]{4}$)Pension tax table number. The value is not validated against the actual Skatteetaten deduction-table
catalogue. Relevant only when isReceivingPension is true.
Skatteetaten schema: tabellnummer where trekkode is pensjon.
pensionPercentagepensionTable is set, optional otherwisePension tax percentage. If a value is required but not supplied, default to 30.
Skatteetaten schema: prosentsats where trekkode is pensjon.
pensionPercentagePaye^(100(\.0)?|[0-9]{1,2}(\.[0-9])?)$Pension PAYE tax percentage for source-tax pensioners (Kildeskattpensjonist). Only one digit after the decimal separator is allowed (unlike the other percentage fields, which allow two).
Skatteetaten schema: prosentsats where trekkode is pensjon and a tilleggsopplysning is
kildeskattpensjonist.
hasPensionExemptionCardtrue accepted; absence implies false)Pension exemption card (Frikort for pension).
Skatteetaten schema: true if frikortbeloep is set where trekkode is pensjon.
updatedAtTimestamp of the last modification to the record. Set by the service on every write.
Tax information uses a strict timeline.
to field is automatically calculated as the day before the next
record's fromRecord 1: from: 2024-01-01, to: 2024-12-31, table: "7100"
Record 2: from: 2025-01-01, to: null, table: "7150"
Record 1's to is automatically set to 2024-12-31.
Example: Create Tax Information
POST /tenants/{tenantId}/employees/{employeeId}/tax-information
Authorization: Bearer <token>
Content-Type: application/json
{
"from": "2026-01-01",
"mainEmployer": true,
"table": "7100",
"percentage": "22.00",
"taxCardId": "SK-2026-123456",
"taxCardIssuedDate": "2025-12-15"
}
A successful request returns 201 Created with the full TaxInformation resource, including the
server-generated id, calculated to, etag, and updatedAt.
| Event | Trigger | Consumers |
|---|---|---|
tax-information-created-v1 |
New tax information record registered | Payroll |
tax-information-updated-v1 |
Existing record modified | Payroll |
tax-information-deleted-v1 |
Record hard-deleted | Payroll |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| asOfDate | string <date> Filter timeline entities active as of this date |
| pageSize | integer [ 1 .. 1000 ] Parameter indicates the number of results that the client would like to see in the response. |
| x-cursor | string or null Pagination token used to query for the next part of a list. |
[- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "isMainEmployer": true,
- "isBorderCommuter": true,
- "borderCommuterTaxPercentage": "string",
- "table": "string",
- "percentage": "string",
- "payeTaxPercentage": "string",
- "hasExemptionCard": true,
- "exemptionCardAmount": "string",
- "isFullyWithholdingChristmasTax": true,
- "taxCardId": "string",
- "taxCardIncomeYear": "string",
- "taxCardIssuedDate": "2019-08-24",
- "isPostedFromUsCanada": true,
- "taxFromFirstKroneForTaxFreeOrg": true,
- "isReceivingPension": true,
- "pensionTable": "string",
- "pensionPercentage": "string",
- "pensionPercentagePaye": "string",
- "hasPensionExemptionCard": true,
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
]| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| id | string <uuid> Optional client-provided identifier. If omitted, a server-generated UUID is assigned. If the ID already exists, a 409 Conflict is returned. |
| isMainEmployer | boolean (isMainEmployer) Is this the main employer (Hovedarbeidsgiver)? Only main employer uses table-based tax deduction. Monolith notes: Field "Main employer" (a2cf27eb-e1f4-44d3-8cd7-e15016ff433c) |
| isBorderCommuter | boolean (isBorderCommuter) Is employee a border commuter (Grensependler)? Special tax rate applies. Monolith notes: Field "Border commuter employee" (0a4247ee-64c5-490f-871d-fb247eefa4d5). |
| borderCommuterTaxPercentage | string <decimal-13-2> (borderCommuterTaxPercentage) ^-?\d{1,11}(\.\d{1,2})?$ Depending on
Skatteetaten schema: Monolith notes: Field "Border commuter tax percentage" (c37085f5-8d19-4792-8338-06c4ee13147a). |
| table | string or null (table) ^[0-9]{4}$ Skatteetaten schema: Monolith notes: Field "Tax table" (48148e6a-1864-40e8-9172-b3f5edee9d48). |
| percentage | string <decimal-13-2> (percentage) [ 0 .. 100 ] Mandatory if If no explicit value is set and a value is required, use 50. Skatteetaten schema: Monolith notes: Field "Tax percentage" (d06a1507-ca8e-4c12-9188-23a7fb612f4b). |
| payeTaxPercentage | string <decimal-13-2> (payeTaxPercentage) [ 0 .. 100 ] PAYE withholding percentage for foreign workers (Kildeskattprosent)
Skatteetaten schema: Monolith notes: Field "PAYE tax percentage" (c4d57402-34be-4fba-8876-8820ea4ffe3f). |
| hasExemptionCard | boolean (hasExemptionCard) Employee has tax exemption card (Frikort) - no tax deduction up to limit
Skatteetaten schema: Monolith notes: Field "Freecard" (554d7abb-679b-4d71-8a7d-2e19ce09ae8b). |
| exemptionCardAmount | string <decimal-13-2> (exemptionCardAmount) Remaining exemption card amount (Frikortbeløp)
Mandatory if Skatteetaten schema: Monolith notes: Field "Freecard amount" (ffdc30d2-f067-4ceb-a816-ef5b32b2eb01). |
| isFullyWithholdingChristmasTax | boolean (isFullyWithholdingChristmasTax) Also known as Full tax in Nov/Dec.
Only
Monolith notes: Field "Full tax in Nov/Dec" (d066796a-26d4-473b-bf52-edf13d90b130). Mapping to values in reference table 10040 No / Yes:
|
| taxCardId | string or null (taxCardId) Skatteetaten's ID for this tax card. Skatteetaten schema: Monolith notes: Field "Taxcard ID" (dee3ab67-ab4e-449c-95b2-33f647bb387e). |
| taxCardIncomeYear | string <integer-15> Income year the tax card applies to (Inntektsår). |
| taxCardIssuedDate | string <date> (taxCardIssuedDate) The date Skatteetaten issued this tax card. This may be misleading because the parent object's values could have been changed manually since then. Skatteetaten schema: Monolith notes: Field "Taxcard date" (1ca9b054-e960-462f-b7eb-431d2d6bb764). |
| isPostedFromUsCanada | boolean (isPostedFromUsCanada) Employee posted from US/Canada with tax treaty benefits Monolith notes: Field "Posted from US/Canada" (9f437c4b-0bc6-44b0-9160-3b7b37e1afb9). |
| taxFromFirstKroneForTaxFreeOrg | boolean (taxFromFirstKroneForTaxFreeOrg) Only Field should only applies for tax free organizations. Note that payroll always reports from first krone, using tax and contribution rule "Tax-free organisation". This field is used to deduct tax for the employee from the first payment, to avoid withholding much the month that total payments exceed 10 000 and/or the employee having underpaid tax. Monolith notes: Field "Tax from the 1st NOK" (954b6779-4c16-45f4-bcc0-b75dfab081e4). |
| isReceivingPension | boolean (isReceivingPension) Only Monolith notes: Field "Pension benefits paid out to this person" (0b674566-0004-479e-a735-a86aff426964). |
| pensionTable | string (pensionTable) ^[0-9]{4}$ It is not validated whether this is a real deduction table number.
Skatteetaten schema: Monolith notes: Field "Pension tax table" (86f929f0-6780-4eb2-9518-c5a787a21c78).
Known issue: It is not validated whether this is an actual tax table.
Vintage UI hides this field if |
| pensionPercentage | string <decimal-13-2> (pensionPercentage) [ 0 .. 100 ] Mandatory if Monolith notes: Field "Pension tax percentage" (65a40dd9-4d88-43fe-a21a-e916e0365db0).
Vintage UI hides this field if |
| pensionPercentagePaye | string <decimal-13-1> (pensionPercentagePaye) ^(100(\.0)?|[0-9]{1,2}(\.[0-9])?)$ Skatteetaten schema: Monolith notes: Field "Pension PAYE tax percentage" (58f48566-6b6b-47db-a8c8-4df82de4b345).
Known issue (discrepancy): Minimum and maximum are not defined, unlike all other percentages.
Known issue (TBD: possibly): Only allows a 1 digit after the decimal separator,
unlike all other fields with of type decimal (which allow 2 digits).
Vintage UI hides this field if |
| hasPensionExemptionCard | boolean (hasPensionExemptionCard) Only Monolith notes: Field "Pension freecard" (ad3a4a83-748b-4ac5-8e0c-8f34e06fac40).
Vintage UI hides this field if |
| from required | string <date> Effective-from date for this timeline version. |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "isMainEmployer": true,
- "isBorderCommuter": true,
- "borderCommuterTaxPercentage": "string",
- "table": "string",
- "percentage": "string",
- "payeTaxPercentage": "string",
- "hasExemptionCard": true,
- "exemptionCardAmount": "string",
- "isFullyWithholdingChristmasTax": true,
- "taxCardId": "string",
- "taxCardIncomeYear": "string",
- "taxCardIssuedDate": "2019-08-24",
- "isPostedFromUsCanada": true,
- "taxFromFirstKroneForTaxFreeOrg": true,
- "isReceivingPension": true,
- "pensionTable": "string",
- "pensionPercentage": "string",
- "pensionPercentagePaye": "string",
- "hasPensionExemptionCard": true,
- "from": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "isMainEmployer": true,
- "isBorderCommuter": true,
- "borderCommuterTaxPercentage": "string",
- "table": "string",
- "percentage": "string",
- "payeTaxPercentage": "string",
- "hasExemptionCard": true,
- "exemptionCardAmount": "string",
- "isFullyWithholdingChristmasTax": true,
- "taxCardId": "string",
- "taxCardIncomeYear": "string",
- "taxCardIssuedDate": "2019-08-24",
- "isPostedFromUsCanada": true,
- "taxFromFirstKroneForTaxFreeOrg": true,
- "isReceivingPension": true,
- "pensionTable": "string",
- "pensionPercentage": "string",
- "pensionPercentagePaye": "string",
- "hasPensionExemptionCard": true,
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| taxInformationId required | string <uuid> Tax information unique identifier |
{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "isMainEmployer": true,
- "isBorderCommuter": true,
- "borderCommuterTaxPercentage": "string",
- "table": "string",
- "percentage": "string",
- "payeTaxPercentage": "string",
- "hasExemptionCard": true,
- "exemptionCardAmount": "string",
- "isFullyWithholdingChristmasTax": true,
- "taxCardId": "string",
- "taxCardIncomeYear": "string",
- "taxCardIssuedDate": "2019-08-24",
- "isPostedFromUsCanada": true,
- "taxFromFirstKroneForTaxFreeOrg": true,
- "isReceivingPension": true,
- "pensionTable": "string",
- "pensionPercentage": "string",
- "pensionPercentagePaye": "string",
- "hasPensionExemptionCard": true,
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| taxInformationId required | string <uuid> Tax information unique identifier |
| isMainEmployer | boolean (isMainEmployer) Is this the main employer (Hovedarbeidsgiver)? Only main employer uses table-based tax deduction. Monolith notes: Field "Main employer" (a2cf27eb-e1f4-44d3-8cd7-e15016ff433c) |
| isBorderCommuter | boolean (isBorderCommuter) Is employee a border commuter (Grensependler)? Special tax rate applies. Monolith notes: Field "Border commuter employee" (0a4247ee-64c5-490f-871d-fb247eefa4d5). |
| borderCommuterTaxPercentage | string <decimal-13-2> (borderCommuterTaxPercentage) ^-?\d{1,11}(\.\d{1,2})?$ Depending on
Skatteetaten schema: Monolith notes: Field "Border commuter tax percentage" (c37085f5-8d19-4792-8338-06c4ee13147a). |
| table | string or null (table) ^[0-9]{4}$ Skatteetaten schema: Monolith notes: Field "Tax table" (48148e6a-1864-40e8-9172-b3f5edee9d48). |
| percentage | string <decimal-13-2> (percentage) [ 0 .. 100 ] Mandatory if If no explicit value is set and a value is required, use 50. Skatteetaten schema: Monolith notes: Field "Tax percentage" (d06a1507-ca8e-4c12-9188-23a7fb612f4b). |
| payeTaxPercentage | string <decimal-13-2> (payeTaxPercentage) [ 0 .. 100 ] PAYE withholding percentage for foreign workers (Kildeskattprosent)
Skatteetaten schema: Monolith notes: Field "PAYE tax percentage" (c4d57402-34be-4fba-8876-8820ea4ffe3f). |
| hasExemptionCard | boolean (hasExemptionCard) Employee has tax exemption card (Frikort) - no tax deduction up to limit
Skatteetaten schema: Monolith notes: Field "Freecard" (554d7abb-679b-4d71-8a7d-2e19ce09ae8b). |
| exemptionCardAmount | string <decimal-13-2> (exemptionCardAmount) Remaining exemption card amount (Frikortbeløp)
Mandatory if Skatteetaten schema: Monolith notes: Field "Freecard amount" (ffdc30d2-f067-4ceb-a816-ef5b32b2eb01). |
| isFullyWithholdingChristmasTax | boolean (isFullyWithholdingChristmasTax) Also known as Full tax in Nov/Dec.
Only
Monolith notes: Field "Full tax in Nov/Dec" (d066796a-26d4-473b-bf52-edf13d90b130). Mapping to values in reference table 10040 No / Yes:
|
| taxCardId | string or null (taxCardId) Skatteetaten's ID for this tax card. Skatteetaten schema: Monolith notes: Field "Taxcard ID" (dee3ab67-ab4e-449c-95b2-33f647bb387e). |
| taxCardIssuedDate | string <date> (taxCardIssuedDate) The date Skatteetaten issued this tax card. This may be misleading because the parent object's values could have been changed manually since then. Skatteetaten schema: Monolith notes: Field "Taxcard date" (1ca9b054-e960-462f-b7eb-431d2d6bb764). |
| isPostedFromUsCanada | boolean (isPostedFromUsCanada) Employee posted from US/Canada with tax treaty benefits Monolith notes: Field "Posted from US/Canada" (9f437c4b-0bc6-44b0-9160-3b7b37e1afb9). |
| taxFromFirstKroneForTaxFreeOrg | boolean (taxFromFirstKroneForTaxFreeOrg) Only Field should only applies for tax free organizations. Note that payroll always reports from first krone, using tax and contribution rule "Tax-free organisation". This field is used to deduct tax for the employee from the first payment, to avoid withholding much the month that total payments exceed 10 000 and/or the employee having underpaid tax. Monolith notes: Field "Tax from the 1st NOK" (954b6779-4c16-45f4-bcc0-b75dfab081e4). |
| isReceivingPension | boolean (isReceivingPension) Only Monolith notes: Field "Pension benefits paid out to this person" (0b674566-0004-479e-a735-a86aff426964). |
| pensionTable | string (pensionTable) ^[0-9]{4}$ It is not validated whether this is a real deduction table number.
Skatteetaten schema: Monolith notes: Field "Pension tax table" (86f929f0-6780-4eb2-9518-c5a787a21c78).
Known issue: It is not validated whether this is an actual tax table.
Vintage UI hides this field if |
| pensionPercentage | string <decimal-13-2> (pensionPercentage) [ 0 .. 100 ] Mandatory if Monolith notes: Field "Pension tax percentage" (65a40dd9-4d88-43fe-a21a-e916e0365db0).
Vintage UI hides this field if |
| pensionPercentagePaye | string <decimal-13-1> (pensionPercentagePaye) ^(100(\.0)?|[0-9]{1,2}(\.[0-9])?)$ Skatteetaten schema: Monolith notes: Field "Pension PAYE tax percentage" (58f48566-6b6b-47db-a8c8-4df82de4b345).
Known issue (discrepancy): Minimum and maximum are not defined, unlike all other percentages.
Known issue (TBD: possibly): Only allows a 1 digit after the decimal separator,
unlike all other fields with of type decimal (which allow 2 digits).
Vintage UI hides this field if |
| hasPensionExemptionCard | boolean (hasPensionExemptionCard) Only Monolith notes: Field "Pension freecard" (ad3a4a83-748b-4ac5-8e0c-8f34e06fac40).
Vintage UI hides this field if |
| etag required | string Opaque version identifier for optimistic concurrency control. Must be included in PATCH request body. |
| from required | string <date> Effective-from date for this timeline version. |
{- "isMainEmployer": true,
- "isBorderCommuter": true,
- "borderCommuterTaxPercentage": "string",
- "table": "string",
- "percentage": "string",
- "payeTaxPercentage": "string",
- "hasExemptionCard": true,
- "exemptionCardAmount": "string",
- "isFullyWithholdingChristmasTax": true,
- "taxCardId": "string",
- "taxCardIssuedDate": "2019-08-24",
- "isPostedFromUsCanada": true,
- "taxFromFirstKroneForTaxFreeOrg": true,
- "isReceivingPension": true,
- "pensionTable": "string",
- "pensionPercentage": "string",
- "pensionPercentagePaye": "string",
- "hasPensionExemptionCard": true,
- "etag": "1",
- "from": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "isMainEmployer": true,
- "isBorderCommuter": true,
- "borderCommuterTaxPercentage": "string",
- "table": "string",
- "percentage": "string",
- "payeTaxPercentage": "string",
- "hasExemptionCard": true,
- "exemptionCardAmount": "string",
- "isFullyWithholdingChristmasTax": true,
- "taxCardId": "string",
- "taxCardIncomeYear": "string",
- "taxCardIssuedDate": "2019-08-24",
- "isPostedFromUsCanada": true,
- "taxFromFirstKroneForTaxFreeOrg": true,
- "isReceivingPension": true,
- "pensionTable": "string",
- "pensionPercentage": "string",
- "pensionPercentagePaye": "string",
- "hasPensionExemptionCard": true,
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| taxInformationId required | string <uuid> Tax information unique identifier |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}Tracks an employee's union memberships (Fagforeningsmedlemskap) for payroll deductions, insurance participation, and A-melding reporting of union fees.
Union master data (the union catalogue itself — names, organisation numbers, active periods) lives
in the Org API (/unions, available via /icLookup) and is out of scope here. This entity only
stores the link between an employee and a union plus the parameters payroll needs for fee and
insurance deductions.
Timeline type: Flexible — gaps allowed, to may be open-ended. Overlaps
are not allowed: at most one union link may be active on any given date for a single employee.
| Property | Type | Required | Description |
|---|---|---|---|
id |
UUID | (read-only) | Unique union link identifier. Server-generated on create. |
from |
date | Yes | Membership start date. Must be the 1st of the month. |
to |
date | No | Membership end date. null means ongoing. |
unionId |
string | Yes | Foreign key to a union in the Org API. |
memberNumber |
string | No | Employee's union member number. Max 20 characters. |
includedInCollectiveInsurance |
boolean | Yes | Employee is included in the union's collective insurance scheme. |
includedInUnionsInsurance |
boolean | Yes | Employee is included in the union's own insurance scheme. |
collectiveInsuranceAmount |
string | No | Employee's contribution to collective insurance as a decimal string. |
unionsInsuranceAmount |
string | No | Employee's contribution to the union's insurance as a decimal string. |
kidNumber |
string | No | KID-number used as payment reference on union fee transfers. 2–25 digits, optional trailing -, MOD10/MOD11 checked. |
etag |
string | (read-only) | Opaque version identifier for optimistic concurrency. Must be included in PATCH request body. |
updatedAt |
datetime | (read-only) | Timestamp of last modification. |
Union fee and insurance deduction amounts, sequence numbers, and A-melding
fagforeningskontingentreporting are produced by the payroll system, not this service. This service only stores the link and publishes events.
Key Validation Rules
unionId must reference a union that exists and is active in the Org API for the entire link
period (from–to).from must be the 1st day of a month (Norway: union fee deductions are calculated monthly).to, when provided, must be on or after from and within both the union's active period and the
employee's active position/contract period.etag must match the current version on updates (optimistic concurrency).idUnique identifier for the union link record. Generated by the service on create; never supplied by clients.
fromYYYY-MM-DD)Date the membership starts. Must be the 1st of the month and fall within both the union's active period in the Org API and the employee's position/contract period. Future dates are allowed.
toYYYY-MM-DD)Date the membership ends. null (or omitted) means the membership is ongoing. When provided, must
be on or after from and within the union's and the employee's active periods. Setting to is the
standard way to close an open-ended link — the supported in-place modification on an existing link.
To change any other field, end the current link and create a new one.
unionIdForeign key to a union in the Org API. Must reference an existing, active union in the Org API for the entire link period. Clients must gracefully handle an invalid reference and require the end user to fix it.
memberNumberThe employee's membership identifier with the union, used by the union for correspondence and benefits administration. Typically printed on the union membership card.
includedInCollectiveInsuranceWhether the employee participates in the collective insurance scheme negotiated between employer and union. Required on create — a union link always implies an explicit opt-in or opt-out, so there is no "unset" state.
includedInUnionsInsuranceWhether the employee participates in the union's own insurance scheme (Fagforeningens forsikring) —
typically death and disability cover. Required on create for the same reason as
includedInCollectiveInsurance.
collectiveInsuranceAmountEmployee's monthly contribution to collective insurance. Must be between 0 and 9,999,999 when
provided. Typically 0 (or omitted) when includedInCollectiveInsurance is false. Stored as a
string to preserve decimal precision.
unionsInsuranceAmountEmployee's monthly contribution to the union's insurance. Must be between 0 and 9,999,999 when
provided. Typically 0 (or omitted) when includedInUnionsInsurance is false. Stored as a
string to preserve decimal precision.
kidNumberNorwegian KID-number used as the payment reference when union fee deductions are remitted to the
union. Must pass a MOD10 or MOD11 check-digit validation; a trailing - forces MOD11 only,
otherwise MOD10 is tried first and MOD11 is the fallback. Same rules as a creditor claim
kidNumber.
etagOpaque version identifier used for optimistic concurrency control. Returned by the service on every
read and must be included in PATCH request bodies. If the etag does not match the current
version, the update is rejected with 409 Conflict.
updatedAtTimestamp of the last modification to the record. Set by the service on every write.
Example: Create Union Link
POST /tenants/{tenantId}/employees/{employeeId}/union-links
Authorization: Bearer <token>
Content-Type: application/json
{
"from": "2026-05-01",
"unionId": "971318600",
"memberNumber": "123456",
"includedInCollectiveInsurance": true,
"includedInUnionsInsurance": true,
"collectiveInsuranceAmount": "150.00",
"unionsInsuranceAmount": "50.00",
"kidNumber": "1234567890123"
}
A successful request returns 201 Created with the full UnionLink resource, including the
server-generated id, employeeId, etag, and updatedAt. Omit to to register an open-ended
membership; omit the insurance amount fields when the employee is not participating in that scheme.
| Event | Trigger | Consumers |
|---|---|---|
unionLink.created |
New union membership registered on employee | Payroll |
unionLink.updated |
Existing union link modified (e.g. to date set to end it) |
Payroll |
unionLink.deleted |
Union link removed from employee | Payroll |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| asOfDate | string <date> Filter timeline entities active as of this date |
| pageSize | integer [ 1 .. 1000 ] Parameter indicates the number of results that the client would like to see in the response. |
| x-cursor | string or null Pagination token used to query for the next part of a list. |
[- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "unionId": "string",
- "unionMemberNumber": "string",
- "includedInCollectiveInsurance": true,
- "includedInUnionsInsurance": true,
- "employeeAmountForCollectiveInsurance": "string",
- "employeeAmountForUnionsInsurance": "string",
- "employeeReferenceNumber": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
]| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| id | string <uuid> Optional client-provided identifier. If omitted, a server-generated UUID is assigned. If the ID already exists, a 409 Conflict is returned. |
| unionId required | string or null (unionId) Union identifier (Fagforenings-ID) Monolith notes: Field "Union" (c04a62bd-ef2b-4348-8722-ac77bca76095). |
| unionMemberNumber required | string or null (unionMemberNumber) Employee's union member number (Medlemsnummer) Monolith notes: Field "Union member number" (19760b35-bbaa-41ee-a85d-71527214a47b). |
| includedInCollectiveInsurance | boolean (includedInCollectiveInsurance) Included in collective insurance scheme (Kollektiv forsikring) Monolith notes: Field "Included in collective insurance" (aa29af9c-8b86-4e4b-a4a2-ea1a31e69ff2). |
| includedInUnionsInsurance | boolean (includedInUnionsInsurance) Included in union's insurance scheme (Fagforeningens forsikring) Monolith notes: Field "Included in unions insurance" (0ba1f7ed-4b4f-4ed7-a2d1-179063917888). |
| employeeAmountForCollectiveInsurance | string (employeeAmountForCollectiveInsurance) Employee's contribution to collective insurance (Ansattes andel kollektiv) Monolith notes: Field "Employee amount for collective insurance" (56bf59d1-904a-454a-af23-ebc6809331ae). |
| employeeAmountForUnionsInsurance | string (employeeAmountForUnionsInsurance) Employee's contribution to union insurance (Ansattes andel fagforening) Monolith notes: Field "Employee amount for unions insurance" (2f7d11ca-7107-4fa1-8602-170745980acb). |
| employeeReferenceNumber | string or null (employeeReferenceNumber) Reference number for union payments Monolith notes: Field "Employee reference number" (eaeb3157-4f41-4f1c-ac30-ee10d7da4d2f). |
| from required | string <date> Effective-from date |
| to | string or null <date> Effective-until date |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "unionId": "string",
- "unionMemberNumber": "string",
- "includedInCollectiveInsurance": true,
- "includedInUnionsInsurance": true,
- "employeeAmountForCollectiveInsurance": "string",
- "employeeAmountForUnionsInsurance": "string",
- "employeeReferenceNumber": "string",
- "from": "2019-08-24",
- "to": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "unionId": "string",
- "unionMemberNumber": "string",
- "includedInCollectiveInsurance": true,
- "includedInUnionsInsurance": true,
- "employeeAmountForCollectiveInsurance": "string",
- "employeeAmountForUnionsInsurance": "string",
- "employeeReferenceNumber": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| unionLinkId required | string <uuid> Union link unique identifier |
{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "unionId": "string",
- "unionMemberNumber": "string",
- "includedInCollectiveInsurance": true,
- "includedInUnionsInsurance": true,
- "employeeAmountForCollectiveInsurance": "string",
- "employeeAmountForUnionsInsurance": "string",
- "employeeReferenceNumber": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| unionLinkId required | string <uuid> Union link unique identifier |
| unionId | string or null (unionId) Union identifier (Fagforenings-ID) Monolith notes: Field "Union" (c04a62bd-ef2b-4348-8722-ac77bca76095). |
| unionMemberNumber | string or null (unionMemberNumber) Employee's union member number (Medlemsnummer) Monolith notes: Field "Union member number" (19760b35-bbaa-41ee-a85d-71527214a47b). |
| includedInCollectiveInsurance | boolean (includedInCollectiveInsurance) Included in collective insurance scheme (Kollektiv forsikring) Monolith notes: Field "Included in collective insurance" (aa29af9c-8b86-4e4b-a4a2-ea1a31e69ff2). |
| includedInUnionsInsurance | boolean (includedInUnionsInsurance) Included in union's insurance scheme (Fagforeningens forsikring) Monolith notes: Field "Included in unions insurance" (0ba1f7ed-4b4f-4ed7-a2d1-179063917888). |
| employeeAmountForCollectiveInsurance | string (employeeAmountForCollectiveInsurance) Employee's contribution to collective insurance (Ansattes andel kollektiv) Monolith notes: Field "Employee amount for collective insurance" (56bf59d1-904a-454a-af23-ebc6809331ae). |
| employeeAmountForUnionsInsurance | string (employeeAmountForUnionsInsurance) Employee's contribution to union insurance (Ansattes andel fagforening) Monolith notes: Field "Employee amount for unions insurance" (2f7d11ca-7107-4fa1-8602-170745980acb). |
| employeeReferenceNumber | string or null (employeeReferenceNumber) Reference number for union payments Monolith notes: Field "Employee reference number" (eaeb3157-4f41-4f1c-ac30-ee10d7da4d2f). |
| etag required | string Opaque version identifier for optimistic concurrency control. Must be included in PATCH request body. |
| from required | string <date> Effective-from date |
| to | string or null <date> Effective-until date |
{- "unionId": "string",
- "unionMemberNumber": "string",
- "includedInCollectiveInsurance": true,
- "includedInUnionsInsurance": true,
- "employeeAmountForCollectiveInsurance": "string",
- "employeeAmountForUnionsInsurance": "string",
- "employeeReferenceNumber": "string",
- "etag": "1",
- "from": "2019-08-24",
- "to": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "unionId": "string",
- "unionMemberNumber": "string",
- "includedInCollectiveInsurance": true,
- "includedInUnionsInsurance": true,
- "employeeAmountForCollectiveInsurance": "string",
- "employeeAmountForUnionsInsurance": "string",
- "employeeReferenceNumber": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| unionLinkId required | string <uuid> Union link unique identifier |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}Represents an employment role held by an employee (Stilling / Arbeidsforhold). Positions hold the contract-specific data — type of employment, dates, appointment form, and maritime details — and act as the parent for related salary, work arrangement, tax unit, and cost unit records.
An employee can have one or more positions. At least one position is required per employee. While the data model supports multiple concurrent positions, overlapping active periods are currently not allowed (rule L-010) — this will be lifted once payroll supports concurrent positions.
Timeline type: Flexible — gaps allowed, explicit to, open-ended
(to = null) permitted. Timelines cannot overlap
| Property | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes (read-only) | Unique position identifier. |
from |
date | Yes | Position start date (Startdato). Must be on or after 1973-01-01. |
to |
date | No | Position end date (Sluttdato). null means ongoing. When set, must be on or after from. |
positionNumber |
integer | (read-only) | Sequence number within employee (1, 2, 3 ...). Auto-incremented on create. |
employmentType |
enum | Yes | Type of employment discriminator (Arbeidsforholdtype). Immutable after creation. Determines which other fields are required, optional, or forbidden. |
appointmentType |
enum | Conditional | Type of appointment (Ansettelsesform). Required for Ordinary and Maritime; must not be set for Freelancer, Pension, or PermanentlyAdaptedWork. |
positionEndReason |
enum | Conditional | Reason the position ended (Sluttårsak). Required when to is set, employmentType is Ordinary or Maritime, and to is on or after 2020-01-01. |
managerId |
UUID | No | Employee ID of the direct manager (Nærmeste leder). Must reference an employee in the same tenant. |
maritimeWorker |
object | Conditional | Maritime employment details (ship register, vessel type, shipping area). Required when employmentType is Maritime; must not be set for other types. |
tagLinks |
UUID[] | No | Tag identifiers assigned to this position (Etiketter). |
updatedAt |
datetime | (read-only) | Timestamp of the last modification. |
Each position has its own timeline-based sub-resources, managed via dedicated endpoints after creation:
| Entity | Timeline | Path suffix | Purpose |
|---|---|---|---|
| SalaryInformation | Strict | /salary-information |
Compensation details (monthly / hourly / yearly, rates). |
| WorkArrangements | Strict | /work-arrangements |
Working hours, part-time factor, working-time agreement. |
| TaxUnitLinks | Strict | /tax-unit-links |
Links the position to an organisational sub-entity (virksomhet) for A-melding reporting. |
| CostUnitLinks | Flexible | /cost-unit-links |
Wage-cost allocation across accounting dimensions. |
At position creation:
SalaryInformation — at least one record required for Ordinary, Maritime, Freelancer.
Optional for Pension (only rate4 used) and PermanentlyAdaptedWork.WorkArrangement — at least one record required for Ordinary, Maritime, Freelancer. Not
allowed for Pension or PermanentlyAdaptedWork.SalaryInformation / WorkArrangement from must match the position's from.from must be on or after 1973-01-01. Cannot be changed if transactions or
expense claims exist before the new date.to, when provided, must be on or after from.employmentType cannot be changed after creation; end the position and
create a new one instead.positionEndReason requires to to be set, and vice versa
(bidirectional).Ordinary or Maritime position with
to >= 2020-01-01, positionEndReason must be supplied.from in the future can always be deleted.idUnique identifier for the position record. Generated by the service on create; never supplied by clients.
fromYYYY-MM-DD)Date the position becomes active (Startdato). Drives the employee's effective start date and acts
as the anchor for child records — the first SalaryInformation and WorkArrangement must start on
the same date.
Validation
1973-01-01.to when to is set.toYYYY-MM-DD)Date the position ends (Sluttdato). null means the position is ongoing. Setting to is the
standard way to close an open-ended position — combined with positionEndReason, this triggers
A-melding termination reporting.
Validation
from (same date is allowed).null) while positionEndReason still has a value — clear the
reason first.Ordinary or Maritime position with to on or after 2020-01-01,
positionEndReason is required.positionNumberSequence number within the employee (1, 2, 3 ...). Auto-incremented on create and never supplied by clients. Used in the A-melding reported position ID computation together with the tax unit link.
employmentTypeOrdinary | Maritime | Freelancer | Pension | PermanentlyAdaptedWorkPrimary discriminator — drives field applicability, validation, and A-melding reporting. Immutable after creation; changing the type requires ending the position and creating a new one.
| Value | Norwegian | When to use | A-melding mapping |
|---|---|---|---|
Ordinary |
Ordinært arbeidsforhold | Standard employment contract. Default value. | ordinaertArbeidsforhold |
Maritime |
Maritimt arbeidsforhold | Seafarer employment. maritimeWorker sub-object becomes mandatory. |
maritimtArbeidsforhold |
Freelancer |
Frilanser, oppdragstaker | Freelance, contractor, or honorarium-only arrangements. Fewer mandatory fields than Ordinary/Maritime. |
frilanserOppdragstakerHonorarPersonerMm |
Pension |
Pensjon og andre ytelser | Post-employment pension and other remunerations without active employment. Salary (apart from rate4) and work arrangements not allowed. |
pensjonOgAndreTyterIArbeidsforhold |
PermanentlyAdaptedWork |
Varig tilrettelagt arbeid | Permanently adapted work for recipients of disability benefits (NAV scheme). Minimal field requirements. | — (reported as tiltak) |
Required when employmentType is Maritime; must not be set for other types. All three sub-fields
are required when the object is present.
| Sub-field | Values |
|---|---|
shipRegister |
NorwegianShipRegister (Norwegian Ship Register), NorwegianInternationalShipRegister (NIS), InternationalShipRegister (foreign / international) |
vesselType |
CruiseShip (Turistskip), DrillingPlatform (Boreplattform), Other (Annet) |
shippingArea |
Domestic (Innenriks), International (Utenriks) |
appointmentTypePermanent | Temporary | PermanentHiredOut | TemporaryHiredOut |
OncallStaffOrdinary and Maritime, must not be set for
Freelancer, Pension, or PermanentlyAdaptedWorkMaps directly to A-melding. Required for Ordinary and Maritime; forbidden for Freelancer,
Pension, and PermanentlyAdaptedWork.
| Value | Norwegian | Description |
|---|---|---|
Permanent |
Fast ansatt | Permanent employment. Default. |
Temporary |
Midlertidig ansatt | Temporary / fixed-term employment. |
PermanentHiredOut |
Fast ansatt og utleid | Permanent, hired out to another company. |
TemporaryHiredOut |
Midlertidig ansatt og utleid | Temporary, hired out. |
OncallStaff |
Tilkallingsvikar | On-call / substitute staff. |
positionEndReasonEmployeeResigned | EmployerTerminated | ContractEnded |
ShouldNeverHaveBeenReported | OrganisationalChangeOrInternalJobSwap |
PayrollSystemOrAccountantChangedemploymentType is Ordinary or Maritime, set to
date.Reason the position ended. Maps to the A-melding <sluttaarsak> element. Positions ended before
2020-01-01 do not require an end reason — A-melding did not mandate it for older records.
Required when closing an Ordinary or Maritime position with to >= 2020-01-01. Not applicable
for Freelancer, Pension, or PermanentlyAdaptedWork.
| Value | Label | Norwegian | A-melding code |
|---|---|---|---|
EmployeeResigned |
The employee has resigned from his/her position | Arbeidstaker har sagt opp selv | 1 |
EmployerTerminated |
The employer has terminated the employment relationship | Arbeidsgiver har sagt opp arbeidstaker | 2 |
ContractEnded |
Contract, temporary appointment or temporary position has been terminated | Kontrakt, engasjement eller vikariat er utløpt | 3 |
ShouldNeverHaveBeenReported |
The employment should never have been reported | Arbeidsforholdet skulle aldri vært rapportert | 4 |
OrganisationalChangeOrInternalJobSwap |
Changes in organisational structure or internal job swap | Endring i organisasjonsstruktur eller byttet jobb internt | 5 |
PayrollSystemOrAccountantChanged |
Changed payroll system or accountant | Byttet lønnssystem eller regnskapsfører | 6 |
Maritime fields follow the parent position timeline — if ship or route details change, the position must be ended and a new one created.
Validation
to has a value.Freelancer, Pension, or PermanentlyAdaptedWork.to: setting an end reason requires an end date, and clearing the end date
requires clearing the reason first.managerIdEmployee ID of the direct manager (Nærmeste leder). Used for organisational hierarchy only — not reported to A-melding.
Validation
maritimeWorkeremploymentType is Maritime, must not be set otherwiseEmbedded object holding seafarer-specific details (shipRegister, vesselType, shippingArea).
Follows the parent position's lifecycle; if maritime details change, the position must be ended and
a new one created. See the dedicated MaritimeWorker documentation for
per-field details.
Validation
tagLinksTag identifiers (Etiketter) assigned to this position. Free-form classification used for reporting and filtering; has no effect on payroll or A-melding.
updatedAtTimestamp of the last modification to the record. Set by the service on every write.
| Trigger | Employee-level effect |
|---|---|
Position from created / updated / position deleted |
Employee effective start date = earliest from across all positions. |
Position to created / updated / cleared / position deleted |
Employee effective end date = latest to across all positions, or null if any position is open-ended. |
Example: Create an Ordinary Position
POST /tenants/{tenantId}/employees/{employeeId}/positions
Authorization: Bearer <token>
Content-Type: application/json
{
"from": "2026-05-01",
"employmentType": "Ordinary",
"appointmentType": "Permanent",
"managerId": "b1c2d3e4-5f6a-7b8c-9d0e-1f2a3b4c5d6e",
"salaryInformation": [
{
"from": "2026-05-01",
"compensationMethod": "Period",
"salaryBasis": "Monthly",
"salary": "54166.67"
}
],
"workArrangements": [
{
"from": "2026-05-01",
"occupationCode": "2512102",
"setOfAccount": "White",
"workTimeAgreementId": "NotShift",
"workingHoursWeek": "37.50",
"ftePercentage": "100.00"
}
]
}
A successful request returns 201 Created with the full Position resource, including the
server-generated id, positionNumber, and updatedAt.
| Event | Trigger | Consumers |
|---|---|---|
position.created |
New position registered | Payroll |
position.updated |
Existing position modified (e.g. to date set, rename) |
Payroll |
position.deleted |
Position removed | Payroll |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| asOfDate | string <date> Filter timeline entities active as of this date |
| pageSize | integer [ 1 .. 1000 ] Parameter indicates the number of results that the client would like to see in the response. |
| x-cursor | string or null Pagination token used to query for the next part of a list. |
[- {
- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "positionNumber": 0,
- "positionEndReason": "EmployeeResigned",
- "managerId": "b2c2c359-55f3-4680-a660-901475c7a693",
- "appointmentType": "Permanent",
- "employmentType": "Ordinary",
- "maritimeWorker": {
- "shipRegister": "InternationalShipRegister",
- "vesselType": "CruiseShip",
- "shippingArea": "Domestic"
}, - "tagLinks": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "salaryInformation": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "workArrangements": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
]Creates a new position with initial salary information and work arrangements. Child entities (salaryInformation, workArrangements) are created atomically with the position. After creation, child entities are managed through their dedicated endpoints.
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| id | string <uuid> Optional client-provided identifier. If omitted, a server-generated UUID is assigned. If the ID already exists, a 409 Conflict is returned. |
| positionEndReason | string or null (positionEndReason) Enum: "EmployeeResigned" "EmployerTerminated" "ContractEnded" "ShouldNeverHaveBeenReported" "OrganisationalChangeOrInternalJobSwap" "PayrollSystemOrAccountantChanged" Reason the position ended (Sluttårsak). Maps to A-melding sluttaarsak. Required when an Ordinary or Maritime position has to >= 2020-01-01. Monolith notes: Field "Position end reason" (51dbd5a3-b28b-4522-b2df-38fb1ad3c447). |
| managerId | string or null <uuid> (managerId) Employee ID of direct manager (Narmeste leder) Monolith notes: Field "Manager" (e82bbb69-937f-4f67-b667-0629bd6cf860). |
| appointmentType | string or null (appointmentType) Enum: "Permanent" "Temporary" "PermanentHiredOut" "TemporaryHiredOut" "OncallStaff" Type of appointment (Ansettelsesform). Required when employmentType is Ordinary or Maritime; must not be set otherwise.
Monolith notes: Field "Employment form" (c19fc3ca-b644-439c-9801-24691a7ebf39). |
| employmentType required | string (employmentType) Enum: "Ordinary" "Maritime" "Freelancer" "Pension" "PermanentlyAdaptedWork" Type of employment discriminator (Arbeidsforholdtype). Determines which fields are required/applicable. Required on POST. Immutable after creation — PATCH requests that target this field are rejected; changing type requires ending the position and creating a new one.
Monolith notes: Field "Employment type" (e7b5dcb2-11cb-401c-9332-89fc645e4ec6). |
object or null Maritime employment details. Required only for Maritime positions; must be null for all other employment types. | |
Array of objects (SalaryInformationCreate) | |
Array of objects (WorkArrangementCreate) | |
Array of objects (SicknessAndAbsencePeriod) Initial prepaid sickness periods for this position. Defaults to empty. | |
Array of objects (SicknessAndAbsencePeriod) Initial prepaid other absence periods for this position. Defaults to empty. | |
Array of objects (RedundancyPeriod) Initial redundancy periods for this position. Defaults to empty. | |
| tagLinks | Array of strings or null <uuid> [ items <uuid > ] Tag identifiers to assign to this position. |
| from required | string <date> Effective-from date |
| to | string or null <date> Effective-until date |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "positionEndReason": "EmployeeResigned",
- "managerId": "b2c2c359-55f3-4680-a660-901475c7a693",
- "appointmentType": "Permanent",
- "employmentType": "Ordinary",
- "maritimeWorker": {
- "shipRegister": "InternationalShipRegister",
- "vesselType": "CruiseShip",
- "shippingArea": "Domestic"
}, - "salaryInformation": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "from": "2019-08-24"
}
], - "workArrangements": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "from": "2019-08-24"
}
], - "prepaidSicknessPeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "prepaidOtherAbsencePeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "redundancyPeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24",
- "leavePercentage": "string"
}
], - "tagLinks": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "from": "2019-08-24",
- "to": "2019-08-24"
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "positionNumber": 0,
- "positionEndReason": "EmployeeResigned",
- "managerId": "b2c2c359-55f3-4680-a660-901475c7a693",
- "appointmentType": "Permanent",
- "employmentType": "Ordinary",
- "maritimeWorker": {
- "shipRegister": "InternationalShipRegister",
- "vesselType": "CruiseShip",
- "shippingArea": "Domestic"
}, - "tagLinks": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "salaryInformation": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "workArrangements": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| embed | string Comma-separated list of related entities to embed in the position response. Available values: salaryInformation, workArrangements By default, child entities are not included in GET responses. Use this parameter to request them. Example: ?embed=salaryInformation,workArrangements |
{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "positionNumber": 0,
- "positionEndReason": "EmployeeResigned",
- "managerId": "b2c2c359-55f3-4680-a660-901475c7a693",
- "appointmentType": "Permanent",
- "employmentType": "Ordinary",
- "maritimeWorker": {
- "shipRegister": "InternationalShipRegister",
- "vesselType": "CruiseShip",
- "shippingArea": "Domestic"
}, - "tagLinks": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "salaryInformation": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "workArrangements": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| etag required | string Opaque version identifier for optimistic concurrency control. |
| from | string <date> Position start date (Startdato) |
| to | string or null <date> Position end date (Sluttdato). Send null to clear an existing end date. |
| positionEndReason | string or null (positionEndReason) Enum: "EmployeeResigned" "EmployerTerminated" "ContractEnded" "ShouldNeverHaveBeenReported" "OrganisationalChangeOrInternalJobSwap" "PayrollSystemOrAccountantChanged" Reason the position ended (Sluttårsak). Maps to A-melding sluttaarsak. Required when an Ordinary or Maritime position has to >= 2020-01-01. Monolith notes: Field "Position end reason" (51dbd5a3-b28b-4522-b2df-38fb1ad3c447). |
| managerId | string or null <uuid> (managerId) Employee ID of direct manager (Narmeste leder) Monolith notes: Field "Manager" (e82bbb69-937f-4f67-b667-0629bd6cf860). |
| appointmentType | string or null (appointmentType) Enum: "Permanent" "Temporary" "PermanentHiredOut" "TemporaryHiredOut" "OncallStaff" Type of appointment (Ansettelsesform). Required when employmentType is Ordinary or Maritime; must not be set otherwise.
Monolith notes: Field "Employment form" (c19fc3ca-b644-439c-9801-24691a7ebf39). |
object or null Maritime employment details. Send null to clear when ending the position or correcting historic data. (employmentType itself is immutable post-creation.) | |
| tagLinks | Array of strings or null <uuid> [ items <uuid > ] Tag identifiers to assign to this position. Replaces existing tag links entirely. |
{- "etag": "1",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "positionEndReason": "EmployeeResigned",
- "managerId": "b2c2c359-55f3-4680-a660-901475c7a693",
- "appointmentType": "Permanent",
- "maritimeWorker": {
- "shipRegister": "InternationalShipRegister",
- "vesselType": "CruiseShip",
- "shippingArea": "Domestic"
}, - "tagLinks": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}{- "employeeId": "b0e78c8f-8c8b-4410-8293-9239e39d9e17",
- "positionNumber": 0,
- "positionEndReason": "EmployeeResigned",
- "managerId": "b2c2c359-55f3-4680-a660-901475c7a693",
- "appointmentType": "Permanent",
- "employmentType": "Ordinary",
- "maritimeWorker": {
- "shipRegister": "InternationalShipRegister",
- "vesselType": "CruiseShip",
- "shippingArea": "Domestic"
}, - "tagLinks": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
], - "salaryInformation": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "workArrangements": [
- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
], - "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}Cost allocation that distributes a position's wage costs across accounting cost units such as department, project, or cost centre. Each record links a position to a single cost unit value for a given period.
Cost unit is a child of Position, not of Employee — different positions on the same employee may have different allocations. Cost allocation is internal accounting only: it is not reported to authorities (not part of A-melding).
The cost unit type/value master data is managed in the Accounts Service in Payroll and is out of scope here — this entity only stores the allocation link for a position.
Timeline type: Flexible — gaps and overlaps allowed. Multiple concurrent
allocations across different cost units are expected. to may be open-ended.
| Property | Type | Required | Description |
|---|---|---|---|
id |
UUID | (read-only) | Unique allocation record identifier. Server-generated on create. |
from |
date | Yes | Allocation effective from date. |
to |
date | No | Allocation effective until date. null means ongoing. |
costUnitType |
string | Yes | Type of cost unit — e.g. department, project, cost centre. |
costUnit |
string | Yes | Cost unit code (Kostnadsbarer) — e.g. department number or project code. |
etag |
string | (read-only) | Opaque version identifier for optimistic concurrency. Must be included in PATCH request body. |
updatedAt |
datetime | (read-only) | Timestamp of last modification. |
Key Validation Rules
from is required and must be on or after the parent position's from date.to, when provided, must be on or after from.costUnitType and costUnit are required and must reference values defined in the Accounts
Service in Payroll. The value referenced by costUnit must be associated with the type
referenced by costUnitType and active for the allocation period.costUnitType + costUnit combination must not be created
with an identical or overlapping date range on the same position (prevents exact-duplicate
allocations on the same dimension).etag must match the current version on updates (optimistic concurrency).idUnique identifier for the cost unit allocation record. Generated by the service on create; never supplied by clients.
fromYYYY-MM-DD)Date the allocation starts. Must fall on or after the parent position's from date. Future dates
are allowed.
toYYYY-MM-DD)Date the allocation ends. null (or omitted) means the allocation is ongoing. When provided, must
be on or after from. Setting to is the standard way to close an open-ended allocation.
costUnitTypeType of cost unit. Identifies which accounting cost units this allocation belongs to, e.g. department, project, cost centre, product, customer, or location. The available types are configured per organisation based on its accounting structure. Must reference a valid cost unit type defined in the Accounts Service in Payroll.
costUnitCost unit — the actual value for the chosen cost unit, e.g. department number ("100"), project
code ("PRJ-2025-001"), or cost centre ("CC-SALES"). Must reference a valid cost unit value
defined in the Accounts Service in Payroll, associated with the cost unit type identified by
costUnitType.
etagOpaque version identifier used for optimistic concurrency control. Returned by the service on
every read and must be included in PATCH request bodies. If the etag does not match the current
version, the update is rejected with 409 Conflict.
updatedAtTimestamp of the last modification to the record. Set by the service on every write.
Cost units use a flexible (loose) timeline:
to is nullable; null means no set end date.Example
POST /tenants/{tenantId}/employees/{employeeId}/positions/{positionId}/cost-unit-links
Authorization: Bearer <token>
Content-Type: application/json
{
"costUnitType": "Department",
"costUnit": "100",
"from": "2026-05-01"
}
An employee's position allocated to a department and a temporary project in parallel:
CostUnit 1: costUnitType: "Department", costUnit: "100", from: 2025-01-01, to: null
CostUnit 2: costUnitType: "Project", costUnit: "PRJ-2025-01", from: 2025-03-01, to: 2025-08-31
A successful request returns 201 Created with the full CostUnitLink resource, including the
server-generated id, positionId, etag, and updatedAt.
| Event | Trigger | Consumers |
|---|---|---|
costUnitLink.created |
New cost allocation added to a position | Payroll, Accounting |
costUnitLink.updated |
Existing cost allocation modified (e.g. to set) |
Payroll, Accounting |
costUnitLink.deleted |
Cost allocation removed from a position | Payroll, Accounting |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| asOfDate | string <date> Filter timeline entities active as of this date |
| pageSize | integer [ 1 .. 1000 ] Parameter indicates the number of results that the client would like to see in the response. |
| x-cursor | string or null Pagination token used to query for the next part of a list. |
[- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "costUnitType": "string",
- "costUnit": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
]| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| id | string <uuid> Optional client-provided identifier. If omitted, a server-generated UUID is assigned. If the ID already exists, a 409 Conflict is returned. |
| costUnitType required | string or null (costUnitType) <= 50 characters Identifier of the cost-unit dimension (Kostnadsbarertype) — opaque ODP dimension-type id, e.g. "2" or "5". The semantic label (department, project, etc.) is resolved separately by the consumer; the API surfaces only the raw identifier. Monolith notes: Field "Dimension Definition" (e8943812-d263-4e57-988a-dd7eb912bcc3). Sourced from the active TimelineValue segment under the AccountingDimension parent. |
| costUnit required | string or null (costUnit) <= 50 characters Business code of the cost unit (Kostnadsbarer) — the human-readable value stored inside the monolith's "Value" segment, e.g. "4200" (a department number) or "PRJ-01" (a project code). This is NOT the field-definition UUID. Monolith notes: Field "Value" (041229f2-1f49-4e89-b2c7-521de610c356), nested under "Dimension value" container (bf361163-80a2-40d6-8963-7c46a4346c57). Sourced from the timeline-dated value segment slice (ActiveStart/ActiveEnd). |
| from required | string <date> Effective-from date |
| to | string or null <date> Effective-until date |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "costUnitType": "string",
- "costUnit": "string",
- "from": "2019-08-24",
- "to": "2019-08-24"
}{- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "costUnitType": "string",
- "costUnit": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| costUnitLinkId required | string <uuid> Cost unit link unique identifier |
{- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "costUnitType": "string",
- "costUnit": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| costUnitLinkId required | string <uuid> Cost unit link unique identifier |
| costUnitType | string or null (costUnitType) <= 50 characters Identifier of the cost-unit dimension (Kostnadsbarertype) — opaque ODP dimension-type id, e.g. "2" or "5". The semantic label (department, project, etc.) is resolved separately by the consumer; the API surfaces only the raw identifier. Monolith notes: Field "Dimension Definition" (e8943812-d263-4e57-988a-dd7eb912bcc3). Sourced from the active TimelineValue segment under the AccountingDimension parent. |
| costUnit | string or null (costUnit) <= 50 characters Business code of the cost unit (Kostnadsbarer) — the human-readable value stored inside the monolith's "Value" segment, e.g. "4200" (a department number) or "PRJ-01" (a project code). This is NOT the field-definition UUID. Monolith notes: Field "Value" (041229f2-1f49-4e89-b2c7-521de610c356), nested under "Dimension value" container (bf361163-80a2-40d6-8963-7c46a4346c57). Sourced from the timeline-dated value segment slice (ActiveStart/ActiveEnd). |
| etag required | string Opaque version identifier for optimistic concurrency control. Must be included in PATCH request body. |
| from required | string <date> Effective-from date |
| to | string or null <date> Effective-until date |
{- "costUnitType": "string",
- "costUnit": "string",
- "etag": "1",
- "from": "2019-08-24",
- "to": "2019-08-24"
}{- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "costUnitType": "string",
- "costUnit": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24",
- "to": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| costUnitLinkId required | string <uuid> Cost unit link unique identifier |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}Captures seafarer-specific details (maritimt arbeidsforhold) required by A-melding when a position represents maritime employment.
Maritime Worker is an embedded object on Position, not a standalone resource. It is created, updated, and deleted with its parent Position and has no endpoints of its own.
Timeline type: None — Maritime Worker follows the parent Position's lifecycle. If maritime details change, the Position must be ended and a new one created.
| Property | Type | Required | Description |
|---|---|---|---|
shipRegister |
enum | Conditional | Ship register (Skipsregister): InternationalShipRegister, NorwegianInternationalShipRegister, or NorwegianShipRegister. |
vesselType |
enum | Conditional | Type of vessel (Fartøytype): CruiseShip, DrillingPlatform, or Other. |
shippingArea |
enum | Conditional | Shipping area (Fartsområde): Domestic or International. |
The entire maritimeWorker object is required when employmentType is Maritime and must
not be set for any other position type. When the object is present, all three fields must be
supplied together.
| Value | Description |
|---|---|
NorwegianShipRegister |
Norwegian Ship Register (Norsk Ordinært Skipsregister). Norwegian-flagged. |
NorwegianInternationalShipRegister |
Norwegian International Ship Register. International shipping, tax relief. |
InternationalShipRegister |
International ship register. Foreign-flagged vessels. |
| Value | Norwegian | Description |
|---|---|---|
CruiseShip |
Turistskip | Cruise and passenger vessels. |
DrillingPlatform |
Boreplattform | Offshore drilling platforms and rigs. |
Other |
Annet | All other vessel classifications (cargo, tankers, supply, etc.). |
| Value | Description |
|---|---|
Domestic |
Coastal and inland shipping within Norwegian territory. |
International |
International trade and shipping routes. |
The taxable seafarer's deduction (særskilt fradrag for sjøfolk) and A-melding reporting are performed by the payroll system, not this service. Employee Core only stores the maritime details so payroll and A-melding can consume them.
Key Validation Rules
maritimeWorker is required when employmentType is Maritime and prohibited for Ordinary,
Freelancer, Pension, and PermanentlyAdaptedWork.maritimeWorker is present, all three fields (shipRegister, vesselType, shippingArea)
must be supplied.employmentType is immutable — switching a position to or from Maritime is not allowed; end
the position and create a new one instead.shipRegisterNorwegianShipRegister | NorwegianInternationalShipRegister |
InternationalShipRegisteremploymentType is Maritime, prohibited otherwiseIndicates which national ship register the vessel is enrolled in. Determines downstream tax and social-security treatment in A-melding:
NorwegianShipRegister — standard Norwegian register; ships in domestic and international
trade. Subject to full Norwegian labour regulations.NorwegianInternationalShipRegister — international register with more flexible crew rules and
tax advantages for shipowners; primarily cargo and specialised vessels.InternationalShipRegister — foreign ship register; Norwegian tax treatment depends on flag
state, tax treaties, and residency.vesselTypeCruiseShip | DrillingPlatform | OtheremploymentType is Maritime, prohibited otherwiseClassification of the vessel the seafarer is assigned to. Drives tax-calculation rules applied by payroll (for example, cruise-ship and drilling-platform crews have distinct provisions).
shippingAreaDomestic | InternationalemploymentType is Maritime, prohibited otherwiseWhether the vessel operates in domestic or international waters. Affects the employer's National Insurance contribution zone and which A-melding codes apply.
Example: Create Maritime Position
Maritime Worker is submitted as part of the parent Position create request. The service rejects the
request if employmentType is Maritime and maritimeWorker is missing, or if maritimeWorker
is supplied for any other position type.
POST /tenants/{tenantId}/employees/{employeeId}/positions
Authorization: Bearer <token>
Content-Type: application/json
{
"from": "2026-05-01",
"employmentType": "Maritime",
"appointmentType": "Permanent",
"maritimeWorker": {
"shipRegister": "NorwegianInternationalShipRegister",
"vesselType": "CruiseShip",
"shippingArea": "International"
},
"salaryInformation": [
{
"from": "2026-05-01",
"compensationMethod": "Period",
"salaryBasis": "Monthly",
"salary": "52000.00"
}
],
"workArrangements": [
{
"from": "2026-05-01",
"occupationCode": "5120108",
"setOfAccount": "White",
"workTimeAgreementId": "RoundTheClockShift355",
"workingHoursWeek": "35.50",
"ftePercentage": "100.00"
}
]
}
A successful request returns 201 Created with the full Position resource, including the
embedded maritimeWorker block.
Maritime Worker does not emit its own events. Changes are published as part of the parent
Position's position.created and position.updated events.
| Value | Description |
|---|---|
NorwegianShipRegister |
Norwegian Ship Register (Norsk Ordinært Skipsregister). Norwegian-flagged. |
NorwegianInternationalShipRegister |
Norwegian International Ship Register. International shipping, tax relief. |
InternationalShipRegister |
International ship register. Foreign-flagged vessels. |
| Value | Norwegian | Description |
|---|---|---|
CruiseShip |
Turistskip | Cruise and passenger vessels. |
DrillingPlatform |
Boreplattform | Offshore drilling platforms and rigs. |
Other |
Annet | All other vessel classifications (cargo, tankers, supply, etc.). |
| Value | Description |
|---|---|
Domestic |
Coastal and inland shipping within Norwegian territory. |
International |
International trade and shipping routes. |
The taxable seafarer's deduction (særskilt fradrag for sjøfolk) and A-melding reporting are performed by the payroll system, not this service. Employee Core only stores the maritime details so payroll and A-melding can consume them.
Key Validation Rules
maritimeWorker is required when employmentType is Maritime and prohibited for Ordinary,
Freelancer, Pension, and PermanentlyAdaptedWork.maritimeWorker is present, all three fields (shipRegister, vesselType, shippingArea)
must be supplied.employmentType is immutable — switching a position to or from Maritime is not allowed; end
the position and create a new one instead.shipRegisterNorwegianShipRegister | NorwegianInternationalShipRegister |
InternationalShipRegisteremploymentType is Maritime, prohibited otherwiseIndicates which national ship register the vessel is enrolled in. Determines downstream tax and social-security treatment in A-melding:
NorwegianShipRegister — standard Norwegian register; ships in domestic and international
trade. Subject to full Norwegian labour regulations.NorwegianInternationalShipRegister — international register with more flexible crew rules and
tax advantages for shipowners; primarily cargo and specialised vessels.InternationalShipRegister — foreign ship register; Norwegian tax treatment depends on flag
state, tax treaties, and residency.vesselTypeCruiseShip | DrillingPlatform | OtheremploymentType is Maritime, prohibited otherwiseClassification of the vessel the seafarer is assigned to. Drives tax-calculation rules applied by payroll (for example, cruise-ship and drilling-platform crews have distinct provisions).
shippingAreaDomestic | InternationalemploymentType is Maritime, prohibited otherwiseWhether the vessel operates in domestic or international waters. Affects the employer's National Insurance contribution zone and which A-melding codes apply.
Example: Create Maritime Position
Maritime Worker is submitted as part of the parent Position create request. The service rejects the
request if employmentType is Maritime and maritimeWorker is missing, or if maritimeWorker
is supplied for any other position type.
POST /tenants/{tenantId}/employees/{employeeId}/positions
Authorization: Bearer <token>
Content-Type: application/json
{
"from": "2026-05-01",
"employmentType": "Maritime",
"appointmentType": "Permanent",
"maritimeWorker": {
"shipRegister": "NorwegianInternationalShipRegister",
"vesselType": "CruiseShip",
"shippingArea": "International"
},
"salaryInformation": [
{
"from": "2026-05-01",
"compensationMethod": "Period",
"salaryBasis": "Monthly",
"salary": "52000.00"
}
],
"workArrangements": [
{
"from": "2026-05-01",
"occupationCode": "5120108",
"setOfAccount": "White",
"workTimeAgreementId": "RoundTheClockShift355",
"workingHoursWeek": "35.50",
"ftePercentage": "100.00"
}
]
}
A successful request returns 201 Created with the full Position resource, including the
embedded maritimeWorker block.
Maritime Worker does not emit its own events. Changes are published as part of the parent
Position's position.created and position.updated events.
Position-level sickness and absence configuration that tracks periods where the employer prepays
NAV benefits on behalf of the employee, along with severance (redundancy) periods. Each period
type is an independent array with effective date ranges, so history is preserved and can be
filtered with asOfDate.
Chronic illness status (Kronisk syk) is not stored here — it lives on the employee-level
sicknessAndAbsence object because it applies to the person, not the position.
Timeline type: Flexible — multiple periods per type allowed with gaps
between them, but overlaps are not allowed within the same array. to may be open-ended.
| Property | Type | Required | Description |
|---|---|---|---|
prepaidSicknessPeriods |
array | No | Periods when employer prepays NAV sick leave for this position. |
prepaidSicknessPeriods[].id |
UUID | Yes (read-only) | Unique period identifier. |
prepaidSicknessPeriods[].from |
date | Yes | Period effective from date. |
prepaidSicknessPeriods[].to |
date | No | Period effective until date. null means ongoing. |
prepaidOtherAbsencePeriods |
array | No | Periods when employer prepays other NAV benefits (parental, care, training). |
prepaidOtherAbsencePeriods[].id |
UUID | Yes (read-only) | Unique period identifier. |
prepaidOtherAbsencePeriods[].from |
date | Yes | Period effective from date. |
prepaidOtherAbsencePeriods[].to |
date | No | Period effective until date. null means ongoing. |
redundancyPeriods |
array | No | Redundancy / severance periods (Etterlønn) with a leave percentage. |
redundancyPeriods[].id |
UUID | Yes (read-only) | Unique period identifier. |
redundancyPeriods[].from |
date | Yes | Period effective from date. |
redundancyPeriods[].to |
date | No | Period effective until date. null means ongoing. |
redundancyPeriods[].leavePercentage |
string (decimal, 2 dp) | Yes | Leave percentage for the redundancy period. Range 0–100. |
lastModified |
datetime | (read-only) | Timestamp of the most recent modification across all period types. null when no periods exist. |
Key Validation Rules
from is required on every period and must be a valid date.to, when provided, must be on or after from.to, but not on or before it.redundancyPeriods[].leavePercentage is required and must be between 0 and 100 (inclusive).chronicallyIllPeriods to the
employee-level sickness-and-absence endpoint instead.asOfDate query parameter on GET to retrieve only periods active on a specific date
(from <= asOfDate AND (to is null OR to >= asOfDate)).prepaidSicknessPeriodsMultiple periods may be recorded to reflect changes over time; gaps are allowed, but the periods must not overlap.
PATCH semantics
prepaidSicknessPeriods from a PATCH request preserves the existing periods
unchanged.[]) clears all periods.prepaidOtherAbsencePeriodsPeriods during which the employer prepays other NAV benefits on behalf of the employee. Typically covers parental leave, care days for sick children, care for seriously ill children, training benefits.
Same PATCH semantics and overlap rules as prepaidSicknessPeriods.
redundancyPeriodsRedundancy / severance arrangements for the position — for example redundancy, early retirement,
or a negotiated termination. Each period carries a leavePercentage that drives A-melding
reporting.
Deleting a redundancy period triggers a new A-melding submission for all periods within the affected timespan, because the reported redundancy percentage changes.
Same PATCH semantics and overlap rules as the prepaid arrays.
redundancyPeriods[].leavePercentage0 – 100Percentage of leave for the redundancy period. Transported as a string to preserve decimal
precision; values like "75.50" are valid.
lastModifiedTimestamp of the last modification to any period on this object. Set by the service on every
write. null when no periods have ever been recorded.
Example: Create Position with Sickness and Absence Periods
Position-level sickness and absence is not a stand-alone resource — it is created together with
the position. The period arrays are accepted at the top level of the POST /positions body:
POST /tenants/{tenantId}/employees/{employeeId}/positions
Authorization: Bearer <token>
Content-Type: application/json
{
"from": "2026-05-01",
"employmentType": "Ordinary",
"appointmentType": "Permanent",
"salaryInformation": [
{ "from": "2026-05-01", "compensationMethod": "Period", "salaryBasis": "Monthly", "salary": "45000.00" }
],
"workArrangements": [
{ "from": "2026-05-01", "occupationCode": "2512102", "setOfAccount": "White", "workTimeAgreementId": "NotShift", "workingHoursWeek": "37.50", "ftePercentage": "100.00" }
],
"prepaidSicknessPeriods": [
{ "from": "2026-05-01" }
],
"prepaidOtherAbsencePeriods": [
{ "from": "2026-05-01" }
],
"redundancyPeriods": [
{ "from": "2026-06-01", "to": "2026-08-31", "leavePercentage": "75.50" }
]
}
A successful request returns 201 Created with the full Position resource. Each period in the
response includes the server-generated id, and sicknessAndAbsence.lastModified is set to the
creation timestamp.
To add, replace, or clear periods on an existing position afterwards, use
PATCH /tenants/{tenantId}/employees/{employeeId}/positions/{positionId}/sickness-and-absence
with a body in the shape of this schema (period arrays at the top level).
Position-level sickness and absence is embedded in the Position resource and does not publish a
dedicated event topic. Changes are surfaced through the Position's position.updated event;
redundancy changes additionally trigger A-melding re-submission.
| Event | Trigger | Consumers |
|---|---|---|
position.updated |
Any period in prepaidSicknessPeriods, prepaidOtherAbsencePeriods, or redundancyPeriods changes |
Payroll, A-melding |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| asOfDate | string <date> Filter timeline entities active as of this date |
{- "prepaidSicknessPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "prepaidOtherAbsencePeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "redundancyPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "leavePercentage": "string"
}
], - "lastModified": "2019-08-24T14:15:22Z"
}Partially replaces position-level sickness and absence periods. Only period types explicitly included in the request body are replaced; omitted types are preserved.
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
Array of objects (SicknessAndAbsencePeriod) Periods when employer prepays sick leave for this position (Forskutterer sykepenger).
PATCH: omit to preserve existing; Monolith notes: Field "Prepaid sickness" (a39dbd0f-ee89-4f84-88fb-dd3963ec2433). | |
Array of objects (SicknessAndAbsencePeriod) Periods when employer prepays other leave for this position (Forskutterer andre ytelser).
PATCH: omit to preserve existing; Monolith notes: Field "Prepaid other absence" (2534dd2f-ff2e-41d9-aecc-b0bafa44acfb). | |
Array of objects (RedundancyPeriod) Redundancy/severance periods for this position (Etterlonn).
PATCH: omit to preserve existing; Monolith notes: Was on position, part of absence object as a decimal timeline. No single field GUID available. |
{- "prepaidSicknessPeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "prepaidOtherAbsencePeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "redundancyPeriods": [
- {
- "from": "2019-08-24",
- "to": "2019-08-24",
- "leavePercentage": "string"
}
]
}{- "prepaidSicknessPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "prepaidOtherAbsencePeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "from": "2019-08-24",
- "to": "2019-08-24"
}
], - "redundancyPeriods": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "from": "2019-08-24",
- "to": "2019-08-24",
- "leavePercentage": "string"
}
], - "lastModified": "2019-08-24T14:15:22Z"
}Salary and compensation configuration for a Position: compensation method, base salary amount, and
company-configurable supplementary rates. Used by payroll for wage calculation and by A-melding
reporting (avloenningstype, sisteLoennsendringsdato).
Salary amounts feed gross pay which is then distributed across payment destinations (creditor claims, union fees, additional accounts, salary account) during payroll processing. Deduction sequencing and A-melding mapping are owned by the payroll system, not this service — this entity only stores the compensation timeline and publishes events.
Parent entity: Position
Timeline type: Strict — no gaps, no overlaps; to is implicit (the day
before the next record's from). The last record has no end date.
At least one record is required for Ordinary, Maritime, and Freelancer position types. For Pension
positions, only rate4 is permitted; compensationMethod, salaryBasis, salary, and
rate5–rate9 must not be set.
| Property | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes (read-only) | Unique record identifier. Server-generated on create (clients may optionally supply). |
from |
date | Yes | Effective-from date. First record's from must equal the position's from. |
to |
date | (read-only) | Computed end of validity — day before the next record's from. null when this is the latest record. |
compensationMethod |
enum (Period/Hourly) |
Conditional | How salary is paid (Avlønningstype). Required for Ordinary, Maritime. Optional for Freelancer, PermanentlyAdaptedWork. Prohibited for Pension. |
salaryBasis |
enum (Hourly/Monthly/Yearly) |
Conditional | Salary basis in employment contract (Kontraktstype lønn). Determines the unit of salary. Required for Ordinary, Maritime. Optional for Freelancer, PermanentlyAdaptedWork. Prohibited for Pension. |
salary |
string (decimal, 2 places) | Conditional | Base salary amount (Grunnlønn) in units defined by salaryBasis. Required when compensationMethod is set. Prohibited for Pension. |
rate4 |
string (decimal, 2 places) | No | Company-configurable supplementary rate 4 (Sats 4). Permitted for all position types, including Pension. |
rate5 |
string (decimal, 2 places) | No | Company-configurable supplementary rate 5 (Sats 5). Prohibited for Pension. |
rate6 |
string (decimal, 2 places) | No | Company-configurable supplementary rate 6 (Sats 6). Prohibited for Pension. |
rate7 |
string (decimal, 2 places) | No | Company-configurable supplementary rate 7 (Sats 7). Prohibited for Pension. |
rate8 |
string (decimal, 2 places) | No | Company-configurable supplementary rate 8 (Sats 8). Prohibited for Pension. |
rate9 |
string (decimal, 2 places) | No | Company-configurable supplementary rate 9 (Sats 9). Prohibited for Pension. |
etag |
string | (read-only) | Opaque version identifier for optimistic concurrency. Must be included in PATCH request bodies. |
updatedAt |
datetime | (read-only) | Timestamp of last modification. |
Benefit amount, deduction sequencing, and A-melding reporting are produced by the payroll system, not this service. This service only stores the salary timeline and publishes events.
Key Validation Rules
from must equal the parent position's from; no gaps or overlaps across the
timeline.from must not be earlier than 1973-01-01.compensationMethod + salaryBasis must be consistent: Period requires Monthly or Yearly;
Hourly requires Hourly.salary is required whenever compensationMethod is set; must be >= 0, 2 decimal places.rate4; all other salary fields must be absent.etag must match the current version on updates.id409 Conflict is returned.Unique identifier for the salary record. Generated by the service on create when not supplied by the client.
fromYYYY-MM-DD)Date this salary configuration takes effect. The first record on a position must start on the same
date as the position itself. Subsequent records must be strictly later than any existing record's
from (strict timeline — no gaps, no overlaps). Must not be earlier than 1973-01-01. The most
recent from across all records on a position feeds A-melding <sisteLoennsendringsdato>.
toYYYY-MM-DD)Implicit end date — the day before the next record's from. null when this is the latest record
on the position. Clients never supply to; timeline progression is managed by adding new records.
compensationMethodPeriod | HourlyMust be consistent with salaryBasis: Period requires Monthly or Yearly; Hourly requires
Hourly.
| Value | Norwegian | A-melding mapping | When to use |
|---|---|---|---|
Period |
Fastlønn | fastloenn / provisjon / akkord / honorar |
Fixed periodic salary. Payroll picks the fine-grained A-melding sub-code. |
Hourly |
Timelønn | timeloenn |
Paid per hour worked. |
salaryBasisHourly | Monthly | YearlyUnit in which salary is expressed in the employment contract (Kontraktstype lønn). Drives how
downstream consumers interpret the salary value — the service does not convert between units.
| Value | Norwegian | salary represents |
|---|---|---|
Hourly |
Timesats | Per-hour rate. |
Monthly |
Månedslønn | Monthly salary at 100% position. |
Yearly |
Årslønn | Annual salary at 100% position. |
salarycompensationMethod is set; prohibited for PensionBase salary amount (Grunnlønn) expressed in the unit defined by salaryBasis. Must be >= 0.
Maximum is type-dependent: 99,999,999.99 for Monthly, 1,199,999,999.88 for Yearly.
Represented as a string to preserve precision beyond JavaScript's safe integer range.
rate4Company-configurable supplementary rate (Sats 4). The meaning is defined by the company's payroll
configuration — the Employee Core Service stores the value without interpreting it. Must be >= 0.
rate4 is the only salary field permitted for Pension positions.
rate5 – rate9Five additional company-configurable supplementary rates (Sats 5 – Sats 9). Like rate4, their
business meaning is entirely up to the company's payroll configuration. Typical uses include
overtime supplements, shift allowances, bonus rates, or other company-specific compensation
components. Must be >= 0. Supplementary rates are not reported in A-melding.
etagOpaque version identifier used for optimistic concurrency control. Returned by the service on every
read and must be included in PATCH request bodies. A mismatched etag results in 409 Conflict.
updatedAtTimestamp of the last modification to the record. Set by the service on every write.
Example: Create Salary Information
POST /tenants/{tenantId}/employees/{employeeId}/positions/{positionId}/salary-information
Authorization: Bearer <token>
Content-Type: application/json
{
"from": "2026-05-01",
"compensationMethod": "Period",
"salaryBasis": "Monthly",
"salary": "50000.00",
"rate4": "375.00"
}
A successful request returns 201 Created with the full SalaryInformation resource, including
the server-generated id, positionId, etag, and updatedAt. For hourly employees, set
compensationMethod to Hourly, salaryBasis to Hourly, and salary to the per-hour rate
(e.g. "250.00"). For Pension positions, omit compensationMethod, salaryBasis, and salary —
only from and (optionally) rate4 are permitted. The first record on a position must use the
position's from date.
| Event | Trigger | Consumers |
|---|---|---|
salaryInformation.created |
New salary record added to a position | Payroll |
salaryInformation.updated |
Existing salary record modified | Payroll |
salaryInformation.deleted |
Salary record removed from a position | Payroll |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| asOfDate | string <date> Filter timeline entities active as of this date |
| pageSize | integer [ 1 .. 1000 ] Parameter indicates the number of results that the client would like to see in the response. |
| x-cursor | string or null Pagination token used to query for the next part of a list. |
[- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
]| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| id | string <uuid> Optional client-provided identifier. If omitted, a server-generated UUID is assigned. If the ID already exists, a 409 Conflict is returned. |
| compensationMethod required | string or null (compensationMethod) Enum: "Period" "Hourly" How salary is paid (Avlønningstype):
Monolith notes: Field "SalaryType" (117a92a4-992e-4d71-9b5e-ad690f526ae0). Renamed from: |
| salaryBasis required | string or null (salaryBasis) Enum: "Hourly" "Monthly" "Yearly" Salary basis in employment contract (Kontraktstype lønn). Determines the unit of
Monolith notes: Field "ContractSalaryType" (43368bbd-e463-479d-8015-3351fff67272). Renamed from: |
| salary | string (salary) Base salary amount (Grunnlønn) in units defined by Monolith notes: Fields "MonthlySalary" (a7d2628e-e52f-491e-a1bb-1616595d5913), "HourlySalary" (f9d00ecd-ae37-42f0-8768-416570b29c2c), "YearlySalary" (1bf17d28-faf7-480b-ae86-0519396da64d). Which field is used depends on |
| rate4 | string (rate4) Company-configurable supplementary rate 4 (Sats 4). The meaning of this rate is defined by the company's payroll configuration — the Employee Core Service stores the value without interpreting it. Optional for all position types including Pension — this is the only salary field permitted for Pension positions. Must be >= 0. 2 decimal places. Monolith notes: Field "SalaryRate4" (efd20632-0c3d-45f3-a830-5c90fe50b600). |
| rate5 | string (rate5) Company-configurable supplementary rate 5 (Sats 5). The meaning of this rate is defined by the company's payroll configuration — the Employee Core Service stores the value without interpreting it. Optional for Ordinary, Maritime, Freelancer, VTA. Prohibited for Pension. Must be >= 0. 2 decimal places. Monolith notes: Field "SalaryRate5" (ff353df2-f569-48db-9437-1621793d0578). |
| rate6 | string (rate6) Company-configurable supplementary rate 6 (Sats 6). The meaning of this rate is defined by the company's payroll configuration — the Employee Core Service stores the value without interpreting it. Optional for Ordinary, Maritime, Freelancer, VTA. Prohibited for Pension. Must be >= 0. 2 decimal places. Monolith notes: Field "SalaryRate6" (61527c31-13c2-42b8-90d9-4c679b41506f). |
| rate7 | string (rate7) Company-configurable supplementary rate 7 (Sats 7). The meaning of this rate is defined by the company's payroll configuration — the Employee Core Service stores the value without interpreting it. Optional for Ordinary, Maritime, Freelancer, VTA. Prohibited for Pension. Must be >= 0. 2 decimal places. Monolith notes: Field "SalaryRate7" (517b603c-e71b-49b7-b87a-52e62f7e37a8). |
| rate8 | string (rate8) Company-configurable supplementary rate 8 (Sats 8). The meaning of this rate is defined by the company's payroll configuration — the Employee Core Service stores the value without interpreting it. Optional for Ordinary, Maritime, Freelancer, VTA. Prohibited for Pension. Must be >= 0. 2 decimal places. Monolith notes: Field "SalaryRate8" (3653b0fa-ee03-4e79-9938-66875ca6441f). |
| rate9 | string (rate9) Company-configurable supplementary rate 9 (Sats 9). The meaning of this rate is defined by the company's payroll configuration — the Employee Core Service stores the value without interpreting it. Optional for Ordinary, Maritime, Freelancer, VTA. Prohibited for Pension. Must be >= 0. 2 decimal places. Monolith notes: Field "SalaryRate9" (63bcdead-854b-4369-bcf2-99e0f4b31bea). New field in v2 (no legacy equivalent). |
| from required | string <date> Effective-from date for this timeline version. |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "from": "2019-08-24"
}{- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| salaryInformationId required | string <uuid> Salary information unique identifier |
{- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| salaryInformationId required | string <uuid> Salary information unique identifier |
| compensationMethod | string or null (compensationMethod) Enum: "Period" "Hourly" How salary is paid (Avlønningstype):
Monolith notes: Field "SalaryType" (117a92a4-992e-4d71-9b5e-ad690f526ae0). Renamed from: |
| salaryBasis | string or null (salaryBasis) Enum: "Hourly" "Monthly" "Yearly" Salary basis in employment contract (Kontraktstype lønn). Determines the unit of
Monolith notes: Field "ContractSalaryType" (43368bbd-e463-479d-8015-3351fff67272). Renamed from: |
| salary | string (salary) Base salary amount (Grunnlønn) in units defined by Monolith notes: Fields "MonthlySalary" (a7d2628e-e52f-491e-a1bb-1616595d5913), "HourlySalary" (f9d00ecd-ae37-42f0-8768-416570b29c2c), "YearlySalary" (1bf17d28-faf7-480b-ae86-0519396da64d). Which field is used depends on |
| rate4 | string (rate4) Company-configurable supplementary rate 4 (Sats 4). The meaning of this rate is defined by the company's payroll configuration — the Employee Core Service stores the value without interpreting it. Optional for all position types including Pension — this is the only salary field permitted for Pension positions. Must be >= 0. 2 decimal places. Monolith notes: Field "SalaryRate4" (efd20632-0c3d-45f3-a830-5c90fe50b600). |
| rate5 | string (rate5) Company-configurable supplementary rate 5 (Sats 5). The meaning of this rate is defined by the company's payroll configuration — the Employee Core Service stores the value without interpreting it. Optional for Ordinary, Maritime, Freelancer, VTA. Prohibited for Pension. Must be >= 0. 2 decimal places. Monolith notes: Field "SalaryRate5" (ff353df2-f569-48db-9437-1621793d0578). |
| rate6 | string (rate6) Company-configurable supplementary rate 6 (Sats 6). The meaning of this rate is defined by the company's payroll configuration — the Employee Core Service stores the value without interpreting it. Optional for Ordinary, Maritime, Freelancer, VTA. Prohibited for Pension. Must be >= 0. 2 decimal places. Monolith notes: Field "SalaryRate6" (61527c31-13c2-42b8-90d9-4c679b41506f). |
| rate7 | string (rate7) Company-configurable supplementary rate 7 (Sats 7). The meaning of this rate is defined by the company's payroll configuration — the Employee Core Service stores the value without interpreting it. Optional for Ordinary, Maritime, Freelancer, VTA. Prohibited for Pension. Must be >= 0. 2 decimal places. Monolith notes: Field "SalaryRate7" (517b603c-e71b-49b7-b87a-52e62f7e37a8). |
| rate8 | string (rate8) Company-configurable supplementary rate 8 (Sats 8). The meaning of this rate is defined by the company's payroll configuration — the Employee Core Service stores the value without interpreting it. Optional for Ordinary, Maritime, Freelancer, VTA. Prohibited for Pension. Must be >= 0. 2 decimal places. Monolith notes: Field "SalaryRate8" (3653b0fa-ee03-4e79-9938-66875ca6441f). |
| rate9 | string (rate9) Company-configurable supplementary rate 9 (Sats 9). The meaning of this rate is defined by the company's payroll configuration — the Employee Core Service stores the value without interpreting it. Optional for Ordinary, Maritime, Freelancer, VTA. Prohibited for Pension. Must be >= 0. 2 decimal places. Monolith notes: Field "SalaryRate9" (63bcdead-854b-4369-bcf2-99e0f4b31bea). New field in v2 (no legacy equivalent). |
| etag required | string Opaque version identifier for optimistic concurrency control. Must be included in PATCH request body. |
| from required | string <date> Effective-from date for this timeline version. |
{- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "etag": "1",
- "from": "2019-08-24"
}{- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "compensationMethod": "Period",
- "salaryBasis": "Hourly",
- "salary": "string",
- "rate4": "string",
- "rate5": "string",
- "rate6": "string",
- "rate7": "string",
- "rate8": "string",
- "rate9": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| salaryInformationId required | string <uuid> Salary information unique identifier |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}Links a position to an organizational sub-unit (Underenhet) for Norwegian A-melding reporting. Companies with multiple locations or legal entities register each site as a sub-unit with its own 9-digit organisation number; this entity records which sub-unit the position is reported under at any point in time.
Tax unit master data (the sub-unit catalogue itself — organisation numbers, names, active periods) lives in the Org API and is out of scope here. This entity only stores the link between a position and a tax unit plus the A-melding employment identifier.
Parent entity: Position
Timeline type: Strict — no gaps, no overlaps, to is calculated
server-side from the next record's from.
| Property | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes (read-only) | Unique record identifier. Server-generated on create. |
from |
date | Yes | Effective-from date for this assignment. |
to |
date | (read-only) | Calculated end date. Automatically set to the day before the next record's from. null when this is the most recent record (currently active). |
taxUnitId |
string | No | 9-digit organisation number of the sub-entity (Underenhetens organisasjonsnummer). Identifies the <virksomhet> used for A-melding reporting. |
reportedPositionId |
string | (read-only) | Employment identifier reported to A-melding (Arbeidsforhold-ID / <arbeidsforholdId>). Must be unique within the tax unit and should stay stable across reports for the same employment relationship. |
etag |
string | Yes | Opaque version identifier for optimistic concurrency. Must be included in PATCH request bodies. |
updatedAt |
datetime | (read-only) | Timestamp of last modification. |
A-melding reporting itself is performed by the payroll system, not this service. This service only stores the link between position and tax unit and publishes events when it changes.
Key Validation Rules
taxUnitId must be a 9-digit Norwegian organisation number and must reference an active sub-unit
of the tenant's employer for the entire assignment period.from must equal the parent position's from — the timeline must cover the
position from day one.to is calculated automatically — only one record is
active at any date.from must be on or after 1973-01-01 and on or after the parent position's from.reportedPositionId should change whenever the tax unit changes (Skatteetaten requires a new
<arbeidsforholdId> for a new <virksomhet> under the same employer/employee).etag must match the current version on updates (optimistic concurrency).idUnique identifier for the tax unit link record. If the client supplies an id on create that
already exists, the service returns 409 Conflict.
fromYYYY-MM-DD)Date this tax unit assignment becomes effective. The first record on a position must start on the
position's from. Subsequent records must start strictly after the previous record's from — the
previous record's implicit to is the day before. Future dates are allowed.
toYYYY-MM-DD)End date of this record's validity period. Calculated by the service as the day before the next
record's from. null when this is the most recent record (currently active). Clients cannot set
this field directly — close a record by inserting a new one with a later from.
taxUnitIdOrganisation number of the sub-entity where the employee is registered (Underenhetens
organisasjonsnummer). Determines the <virksomhet> context in A-melding and drives the employer's
national-insurance zone. Must be an active sub-unit of the tenant's employer for the full
assignment period.
reportedPositionIdEmployment identifier reported to A-melding as <arbeidsforholdId> (Arbeidsforhold-ID).
Clarification: reportedPositionId is a read-only, system-generated field. Clients must not
supply reportedPositionId in create requests. Any create-request examples for TaxUnitLink
should omit this property, while response examples may include it.
Guidelines
101,
POS-552, or EMP_99_1 are acceptable. See
Skatteetaten — Employment ID.taxUnitId changes — a new tax unit implies a new <arbeidsforholdId>.etagOpaque version identifier used for optimistic concurrency control. Returned by the service on every
read and must be included in PATCH request bodies. If the etag does not match the current
version, the update is rejected with 409 Conflict.
updatedAtTimestamp of the last modification to the record. Set by the service on every write.
Tax unit links use a strict timeline. See Timeline Types for comprehensive documentation.
to field is automatically the day before the next record's from.Record 1: from: 2024-01-01, to: 2024-06-30, taxUnitId: "987654321" (Oslo)
Record 2: from: 2024-07-01, to: null, taxUnitId: "876543210" (Bergen)
The employee transferred from Oslo to Bergen on 1 July. Record 1's to is automatically set to
2024-06-30. A new reportedPositionId is normally issued when the tax unit changes, per
Skatteetaten's employment-ID guidance.
Sub-unit structure (Hovedenhet / Underenhet). Norwegian companies have one main unit (Hovedenhet, 9-digit org number) and one or more sub-units (Underenhet, each with its own 9-digit org number) — branches, departments, or locations. A-melding and employer's national insurance are reported per sub-unit.
Employer's national insurance (Arbeidsgiveravgift). The tax unit's location determines the applicable zone rate (Zone 1 — Oslo and major cities — 14.1 %; lower rates in Zones 2–5; 0 % for Svalbard). Correct tax unit assignment is therefore not just a reporting concern but a payroll-cost concern.
A-melding accuracy. Employees must be reported to the correct sub-unit so the municipal tax,
employer-tax zone, and NAV Aa-register records stay accurate. When an employee transfers between
offices belonging to different org numbers, create a new record with the transfer date as from.
Example: Create Tax Unit Link
POST /tenants/{tenantId}/employees/{employeeId}/positions/{positionId}/tax-unit-links
Authorization: Bearer <token>
Content-Type: application/json
{
"from": "2026-05-01",
"taxUnitId": "987654321",
"reportedPositionId": "POS-2026-001"
}
A successful request returns 201 Created with the full TaxUnitLink resource, including the
server-generated id, positionId, calculated to, etag, and updatedAt. For the very first
record on a position, from must equal the position's own from.
| Event | Trigger | Consumers |
|---|---|---|
taxUnitLink.created |
New tax unit link registered on a position | Payroll, A-melding exporter |
taxUnitLink.updated |
Existing link modified (e.g. reportedPositionId changed) |
Payroll, A-melding exporter |
taxUnitLink.deleted |
Link removed from position | Payroll, A-melding exporter |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| asOfDate | string <date> Filter timeline entities active as of this date |
| pageSize | integer [ 1 .. 1000 ] Parameter indicates the number of results that the client would like to see in the response. |
| x-cursor | string or null Pagination token used to query for the next part of a list. |
[- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "taxUnitId": "string",
- "reportedPositionId": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
]| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| id | string <uuid> Optional client-provided identifier. If omitted, a server-generated UUID is assigned. If the ID already exists, a 409 Conflict is returned. |
| taxUnitId | string or null (taxUnitId) Organization number of sub-entity (Underenhetens organisasjonsnummer) Monolith notes: Field "Tax unit" (c000bbaa-b39a-4724-b45c-0c706617a504). |
| reportedPositionId | string or null (reportedPositionId) Position ID as reported to A-melding (Arbeidsforhold-ID) Monolith notes: Field "Reported position ID" (a90b0e8c-2d3c-46ca-b000-68565f0d6934). |
| from required | string <date> Effective-from date for this timeline version. |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "taxUnitId": "string",
- "reportedPositionId": "string",
- "from": "2019-08-24"
}{- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "taxUnitId": "string",
- "reportedPositionId": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| taxUnitLinkId required | string <uuid> Tax unit link unique identifier |
{- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "taxUnitId": "string",
- "reportedPositionId": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| taxUnitLinkId required | string <uuid> Tax unit link unique identifier |
| taxUnitId | string or null (taxUnitId) Organization number of sub-entity (Underenhetens organisasjonsnummer) Monolith notes: Field "Tax unit" (c000bbaa-b39a-4724-b45c-0c706617a504). |
| reportedPositionId | string or null (reportedPositionId) Position ID as reported to A-melding (Arbeidsforhold-ID) Monolith notes: Field "Reported position ID" (a90b0e8c-2d3c-46ca-b000-68565f0d6934). |
| etag required | string Opaque version identifier for optimistic concurrency control. Must be included in PATCH request body. |
| from required | string <date> Effective-from date for this timeline version. |
{- "taxUnitId": "string",
- "reportedPositionId": "string",
- "etag": "1",
- "from": "2019-08-24"
}{- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "taxUnitId": "string",
- "reportedPositionId": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| taxUnitLinkId required | string <uuid> Tax unit link unique identifier |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}Captures the working-time configuration of a Position: occupation code, worker classification, work
time agreement, weekly full-time hours, and part-time factor. Used by payroll for wage calculation
and by A-melding reporting (yrke, arbeidstidsordning,
antallTimerPerUkeSomEnFullStillingTilsvarer, stillingsprosent).
Work time agreement master data (the company's catalogue of WTAs and their normal weekly hours) lives outside this entity. STYRK-08 occupation codes are maintained by Statistics Norway (SSB) and are out of scope here — this entity only stores the code reference chosen for the position.
Parent entity: Position
Timeline type: Strict — no gaps, no overlaps; to is implicit (the day
before the next record's from). The last record has no end date.
At least one record is required for Ordinary, Maritime, and Freelancer position types. Work Arrangement is forbidden for Pension and PermanentlyAdaptedWork position types.
| Property | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes (read-only) | Unique record identifier. Server-generated on create. |
from |
date | Yes | Effective-from date of this record. Must equal the position's from for the first record. |
to |
date | No (read-only) | Computed end of validity — day before the next record's from. null when this is the latest record. |
occupationCode |
string | Conditional | 7-digit STYRK-08 occupation code (Yrkeskode). |
setOfAccount |
enum (White/Blue/Other) |
No | Worker category for payroll accounting (Kontosett). |
personType |
enum (see below) | No | Special person type for tax purposes (Persontype). |
workTimeAgreementId |
string | Conditional | Work time agreement code (Arbeidstidsavtale) referencing a WTA defined for the tenant/company. |
workingHoursWeek |
string (decimal, up to 13.2) | Conditional | Normal weekly hours for the position (Antall timer per uke som en full stilling tilsvarer). |
ftePercentage |
string (decimal, up to 13.2) | Conditional | Part-time percentage (Stillingsprosent); 100 means full-time. Range 0.00–100.00. |
etag |
string | Yes | Opaque version identifier for optimistic concurrency. Must be included in PATCH request bodies. |
updatedAt |
datetime | (read-only) | Timestamp of last modification. |
Payroll calculations, A-melding reporting, and NAV Aa-register reporting are produced by the payroll system, not this service. This service only stores the work-arrangement timeline and publishes events.
Key Validation Rules
from must equal the parent position's from; no gaps or overlaps across the
timeline.from must not be earlier than 1973-01-01.occupationCode, when provided, must be a valid 7-digit STYRK-08 occupation code; required for
Ordinary, Maritime, and Freelancer.workTimeAgreementId and workingHoursWeek are required for Ordinary and Maritime;
workTimeAgreementId is optional for Freelancer.workTimeAgreementId is set, workingHoursWeek must match the WTA's required normal weekly
hours (see Work Time Agreement Codes).ftePercentage must be in the range 0.00–100.00 and must be consistent with workingHoursWeek /
normal weekly hours (±0.01 tolerance).etag must match the current version on updates.idUnique identifier for the work-arrangement record. Generated by the service on create; never supplied by clients.
fromYYYY-MM-DD)Date this work arrangement takes effect. The first record on a position must start on the same date
as the position itself. Subsequent records must be strictly later than any existing record's from
(strict timeline — no gaps, no overlaps). Must not be earlier than 1973-01-01.
toYYYY-MM-DD)Implicit end date — the day before the next record's from. null when this is the latest record
on the position. Clients never supply to; timeline progression is managed by adding new records.
occupationCodeOccupation code (Yrkeskode) classifying the type of work performed. Must be a valid 7-digit code
from Statistics Norway's STYRK-08 classification (based on ISCO-08). Reported to A-melding as
<yrke>.
| Level | Digits | Example | Meaning |
|---|---|---|---|
| Major group | 1 | 2 | Professionals |
| Sub-major group | 2 | 25 | ICT professionals |
| Minor group | 3 | 251 | Software developers |
| Unit group (full) | 7 | 2512102 | Software developer |
setOfAccountWhite | Blue | OtherWorker category for payroll accounting (Kontosett). Determines which payroll accounts wages and related costs are posted to, and can influence pension scheme and collective-agreement applicability.
| Value | Norwegian | Description |
|---|---|---|
White |
Funksjonar | Office / administrative / salaried workers (white collar). |
Blue |
Arbeider | Manual / production / hourly workers (blue collar). |
Other |
Annet | Workers who do not fit the white/blue classification. |
personTypeSpecial person type for tax purposes (Persontype). Identifies employees with special tax treatment such as commuters, expatriates, or offshore workers. Affects A-melding indirectly — payroll maps the value to reporting codes.
| Value | Norwegian | Description |
|---|---|---|
Commuter |
Pendler | Norwegian resident commuting to workplace; may qualify for tax deductions. |
CommuterForeign |
Utenlandsk pendler | Foreign resident commuting to Norway; home abroad. |
CommuterForeignTaxcard |
Utenlandsk pendler med skattekort | Foreign commuter holding a Norwegian tax card without standard deduction. |
ExpatNorway |
Utlending i Norge | Foreign national on expatriate assignment in Norway. |
Offshore |
Sokkelarbeider | Worker on the Norwegian continental shelf; special tax-zone rules apply. |
workTimeAgreementIdReference to the company's defined work time agreement (Arbeidstidsavtale). The selected WTA
determines the required workingHoursWeek and drives the A-melding <arbeidstidsordning> mapping.
Work Time Agreement Codes
| WTA Code | Norwegian | Required workingHoursWeek |
A-melding value |
|---|---|---|---|
NotShift |
Ikke skift | Per company settings (typically 37.5 or 40) | ikkeSkift |
offshore336 |
Offshore | 33.6 | offshore336 |
RoundTheClockShift355 |
Dognkontinuerlig skift og turnus | 35.5 | doegnkontinuerligSkiftOgTurnus355 |
ContinuousShift336 |
Helkontinuerlig skift og andre ordninger | 33.6 | helkontinuerligSkiftOgAndreOrdninger336 |
Shift365 |
Skift | 36.5 | skift365 |
For shift-based WTA types, the required normal weekly hours are fixed values defined by Norwegian
working time regulations. For NotShift, normal hours are taken from the company's configured
weekly hours (typically 37.5 or 40 for Norway).
workingHoursWeekNormal weekly hours that correspond to a 100% position (Antall timer per uke som en full stilling
tilsvarer). For shift-based work time agreements, the value is fixed by the WTA (see Work Time
Agreement Codes above). For NotShift, normal hours follow the company's configured weekly hours
(typically 37.50 or 40.00 in Norway). Reported to A-melding as
<antallTimerPerUkeSomEnFullStillingTilsvarer>.
ftePercentagePart-time percentage (Stillingsprosent) expressing the position as a fraction of full-time. 100
is full-time. When both workingHoursWeek and the applicable normal weekly hours are known, the
value must be consistent with (workingHoursWeek / normalWeeklyHours) × 100 within a ±0.01
tolerance. Reported to A-melding as <stillingsprosent>.
etagOpaque version identifier used for optimistic concurrency control. Returned by the service on every
read and must be included in PATCH request bodies. A mismatched etag results in 409 Conflict.
updatedAtTimestamp of the last modification to the record. Set by the service on every write.
Example: Create Work Arrangement
POST /tenants/{tenantId}/employees/{employeeId}/positions/{positionId}/work-arrangements
Authorization: Bearer <token>
Content-Type: application/json
{
"from": "2026-05-01",
"occupationCode": "2512102",
"setOfAccount": "White",
"personType": "Commuter",
"workTimeAgreementId": "NotShift",
"workingHoursWeek": "37.50",
"ftePercentage": "80.00"
}
A successful request returns 201 Created with the full WorkArrangement resource, including the
server-generated id, positionId, etag, and updatedAt. Omit personType when the employee
has no special tax status; the first record on a position must use the position's from date.
| Event | Trigger | Consumers |
|---|---|---|
workArrangement.created |
New work-arrangement record added to a position | Payroll |
workArrangement.updated |
Existing work-arrangement record modified | Payroll |
workArrangement.deleted |
Work-arrangement record removed | Payroll |
| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| asOfDate | string <date> Filter timeline entities active as of this date |
| pageSize | integer [ 1 .. 1000 ] Parameter indicates the number of results that the client would like to see in the response. |
| x-cursor | string or null Pagination token used to query for the next part of a list. |
[- {
- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}
]| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| id | string <uuid> Optional client-provided identifier. If omitted, a server-generated UUID is assigned. If the ID already exists, a 409 Conflict is returned. |
| occupationCode required | string or null (occupationCode) Job title or occupation code (Stillingstittel/Yrkeskode) Monolith notes: Field "Type of work" (f52a569c-6e1c-4cc8-a707-bac4b9905913). Renamed from: |
| setOfAccount required | string or null (setOfAccount) Enum: "White" "Blue" "Other" Worker category for payroll accounting:
Monolith notes: Field "Set of account" (6c6fe9f2-8582-4866-bd8e-0514a890f70f). |
| personType required | string or null (personType) Enum: "Commuter" "CommuterForeign" "CommuterForeignTaxcard" "ExpatNorway" "Offshore" Special person type for tax purposes:
Monolith notes: Field "Persontype" (659a59f5-f70a-4567-bfd3-97f6cb6ad221). Renamed from: |
| workTimeAgreementId required | string or null (workTimeAgreementId) Work time agreement code (Arbeidstidsavtale) Monolith notes: Outer container field "Work time agreement link position" (7f1210d2-37f2-4e9d-baac-518cf643cb50); value read from inner field "Work time agreement id" (2382efa5-524e-47c1-8e6f-ccc0ec97a1cf). Renamed from: |
| workingHoursWeek | string <decimal-5-2> (workingHoursWeek) ^-?\d{1,3}(\.\d{1,2})?$ Weekly working hours for full-time (Arbeidstimer per uke) Monolith notes: Field "Working hours a week" (df224c37-5efc-4b07-864a-12658cc478a2). |
| ftePercentage | string <decimal-13-2> (ftePercentage) ^-?\d{1,11}(\.\d{1,2})?$ Part-time percentage (Stillingsprosent) - 100 = 100% Monolith notes: Field "Part-time factor" (71778e37-6f41-49e0-b094-c8cb721f9bb2). Renamed from: |
| from required | string <date> Effective-from date for this timeline version. |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "from": "2019-08-24"
}{- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| workArrangementId required | string <uuid> Work arrangement unique identifier |
{- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| workArrangementId required | string <uuid> Work arrangement unique identifier |
| occupationCode | string or null (occupationCode) Job title or occupation code (Stillingstittel/Yrkeskode) Monolith notes: Field "Type of work" (f52a569c-6e1c-4cc8-a707-bac4b9905913). Renamed from: |
| setOfAccount | string or null (setOfAccount) Enum: "White" "Blue" "Other" Worker category for payroll accounting:
Monolith notes: Field "Set of account" (6c6fe9f2-8582-4866-bd8e-0514a890f70f). |
| personType | string or null (personType) Enum: "Commuter" "CommuterForeign" "CommuterForeignTaxcard" "ExpatNorway" "Offshore" Special person type for tax purposes:
Monolith notes: Field "Persontype" (659a59f5-f70a-4567-bfd3-97f6cb6ad221). Renamed from: |
| workTimeAgreementId | string or null (workTimeAgreementId) Work time agreement code (Arbeidstidsavtale) Monolith notes: Outer container field "Work time agreement link position" (7f1210d2-37f2-4e9d-baac-518cf643cb50); value read from inner field "Work time agreement id" (2382efa5-524e-47c1-8e6f-ccc0ec97a1cf). Renamed from: |
| workingHoursWeek | string <decimal-5-2> (workingHoursWeek) ^-?\d{1,3}(\.\d{1,2})?$ Weekly working hours for full-time (Arbeidstimer per uke) Monolith notes: Field "Working hours a week" (df224c37-5efc-4b07-864a-12658cc478a2). |
| ftePercentage | string <decimal-13-2> (ftePercentage) ^-?\d{1,11}(\.\d{1,2})?$ Part-time percentage (Stillingsprosent) - 100 = 100% Monolith notes: Field "Part-time factor" (71778e37-6f41-49e0-b094-c8cb721f9bb2). Renamed from: |
| etag required | string Opaque version identifier for optimistic concurrency control. Must be included in PATCH request body. |
| from required | string <date> Effective-from date for this timeline version. |
{- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "etag": "1",
- "from": "2019-08-24"
}{- "positionId": "da3402dc-13f8-45f9-83a6-bde06dd8eb35",
- "occupationCode": "string",
- "setOfAccount": "White",
- "personType": "Commuter",
- "workTimeAgreementId": "string",
- "workingHoursWeek": "string",
- "ftePercentage": "string",
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "to": "2019-08-24",
- "etag": "1",
- "updatedAt": "2019-08-24T14:15:22Z",
- "from": "2019-08-24"
}| tenantId required | string Tenant identifier |
| employeeId required | string <uuid> Employee identifier (UUID). On the monolith data-source path this is the employmentId from the legacy HRM system — always use the id from the current list or get response rather than a previously cached value. The original employee public Guid is available via legacyIds[] when the request includes includeLegacyIds=true. |
| positionId required | string <uuid> Position unique identifier |
| workArrangementId required | string <uuid> Work arrangement unique identifier |
| etag required | string Example: etag=1 Opaque version identifier for optimistic concurrency control. Obtain from the most recent GET or PATCH response. |
{- "code": "VALIDATION_ERROR",
- "group": "PrimaryValidation",
- "message": "The request contains invalid data. See details for specific field errors.",
- "target": "email",
- "details": [
- {
- "code": "FIELD_REQUIRED",
- "message": "The 'email' field is required.",
- "target": "email",
- "source": {
- "pointer": "/data/attributes/firstName",
- "parameter": "pageSize"
}
}
], - "innerError": {
- "type": "System.ArgumentNullException",
- "message": "Value cannot be null. (Parameter 'userId')",
- "stackTrace": [
- "at MyApp.Services.UserService.GetUser(Guid id)",
- "at MyApp.Controllers.UsersController.Get(Guid id)"
], - "innerException": { }
}, - "correlationId": "0HNHLQAAPC0J6",
- "etag": "2",
- "resourceUpdatedAt": "2019-08-24T14:15:22Z"
}The Employee Core API uses different timeline models to manage historical data. Understanding these models is essential for correctly working with time-sensitive employee information.
| Timeline Type | Gaps Allowed | Overlaps Allowed | End Date | Entities |
|---|---|---|---|---|
| Strict | No | No | Calculated | TaxInformation, SalaryInformation, WorkArrangement, TaxUnitLink |
| Flexible | Yes | Yes | Explicit | Position, CostUnitLink, AdditionalAccount, UnionLink, CarLink, CreditorClaim, TaxAndContributionRule, PensionLink, SicknessAndAbsence periods |
| None | N/A | N/A | N/A | Personal Information, Children, embedded objects (ContactDetails, PayrollSettings) |
Strict timeline entities maintain a continuous history with no gaps or overlaps. Used for data that must always have exactly one active value.
to field is automatically calculated as the day before the next
record's fromto FieldThe to field indicates when a record's validity period ends:
to is null: This is the most recent (current) record with no scheduled endto has a date value: The record ends on that date (inclusive), and the next record begins
on the following dayThe to value is automatically calculated by the system and returned in API responses. You do not
need to provide it when creating or updating records.
When you create a new strict timeline record:
Existing: from: 2024-01-01, to: null
New: from: 2024-07-01
Result:
Record 1: from: 2024-01-01, to: 2024-06-30
Record 2: from: 2024-07-01, to: null
The system automatically sets the previous record's to to the day before the new record's from.
When you insert a record between existing records, all to values are recalculated:
Before:
Record 1: from: 2024-01-01, to: 2024-06-30
Record 2: from: 2024-07-01, to: null
Insert new record with from: 2024-04-01
After:
Record 1: from: 2024-01-01, to: 2024-03-31 (updated)
Record N: from: 2024-04-01, to: 2024-06-30 (new, calculated)
Record 2: from: 2024-07-01, to: null (unchanged)
The system automatically adjusts the previous record's to to accommodate the new record.
When you delete a strict timeline record, the previous record inherits the deleted record's to:
Before deletion:
Record 1: from: 2024-01-01, to: 2024-06-30
Record 2: from: 2024-07-01, to: 2024-12-31
Record 3: from: 2025-01-01, to: null
Delete Record 2:
After deletion:
Record 1: from: 2024-01-01, to: 2024-12-31 (inherited from deleted record)
Record 3: from: 2025-01-01, to: null
This maintains timeline continuity by extending the previous record to cover the period that was occupied by the deleted record.
When updating records at the start of a new year:
POST /tenants/{tenantId}/employees/{id}/tax-information
{
"from": "2025-01-01",
"table": "7150",
"mainEmployer": true
}
The 2024 record automatically gets to: 2024-12-31.
When an employee receives a raise effective mid-year:
POST /tenants/{tenantId}/employees/{id}/positions/{positionId}/salary-information
{
"from": "2024-06-15",
"compensationMethod": "Period",
"salaryBasis": "Monthly",
"salary": "55000.00"
}
The previous record gets to: 2024-06-14, preserving the historical compensation.
When you need to correct historical data by inserting a record in the past:
POST /tenants/{tenantId}/employees/{id}/salary-information
{
"from": "2024-03-01",
"compensationMethod": "Period",
"salaryBasis": "Monthly",
"salary": "52000.00"
}
The system recalculates all to values to maintain timeline integrity.
POST /tenants/{tenantId}/employees/{id}/tax-information
{
"from": "2024-01-01",
"mainEmployer": true,
"table": "7100"
}
POST /tenants/{tenantId}/employees/{id}/tax-information
{
"from": "2024-06-15",
"mainEmployer": true,
"table": "7150"
}
Result: table 7100 until June 14 (to: 2024-06-14), table 7150 from June 15 (to: null).
To get the active record at a specific date, use the asOfDate query parameter:
GET /tenants/{tenantId}/employees/{id}/tax-information?asOfDate=2024-03-01
Returns the record where from <= 2024-03-01 and (to is null OR to >= 2024-03-01).
Important: If
asOfDateis not provided, it defaults to today's date. This means queries without an explicitasOfDatewill always return the currently active record.
| Entity | Parent | Norwegian |
|---|---|---|
| TaxInformation | Employee | Skatteopplysninger |
| SalaryInformation | Position | Lonnsinformasjon |
| WorkArrangement | Position | Arbeidstidsordning |
| TaxUnitLink | Position | Underenhet |
Flexible timeline entities allow gaps and overlaps. Used for data where multiple records can be active simultaneously or where there may be periods with no active records.
to field must be set when knowntoThe to field indicates when a record's validity period ends:
to is null: The record is open-ended with no scheduled end. There are no following
timeline values—this is the current and ongoing state.to has a date value: The record ends on that date (inclusive), and there may be a new
value or a gap starting after the to date.Tip: When processing timeline data, check if
toisnullto determine if this is the final/current record. A non-nulltoindicates the record has a defined end and you should look for subsequent records if needed.
Flexible timeline records are independent:
POST /tenants/{tenantId}/employees/{id}/positions
{
"from": "2024-01-01",
"employmentType": "Ordinary",
"appointmentType": "Permanent"
}
POST /tenants/{tenantId}/employees/{id}/positions
{
"from": "2024-06-01",
"to": "2024-12-31",
"employmentType": "Ordinary",
"appointmentType": "Temporary"
}
Both positions exist independently. Position 2 overlaps with Position 1.
Explicit end date required:
PATCH /tenants/{tenantId}/employees/{id}/positions/{positionId}
{
"to": "2024-12-31",
"positionEndReason": "ContractEnded"
}
An employee's salary split between departments:
POST /tenants/{tenantId}/employees/{id}/positions/{positionId}/cost-unit-links
{
"from": "2024-01-01",
"costUnitType": "Department",
"costUnit": "100"
}
POST /tenants/{tenantId}/employees/{id}/positions/{positionId}/cost-unit-links
{
"from": "2024-01-01",
"costUnitType": "Department",
"costUnit": "200"
}
Both active simultaneously - overlapping allocations.
To get all currently active records:
GET /tenants/{tenantId}/employees/{id}/positions?active=true
Returns records where from <= today AND (to is null OR to >= today).
To query records active at a specific date, use the asOfDate parameter:
GET /tenants/{tenantId}/employees/{id}/positions?asOfDate=2024-06-15
Important: If
asOfDateis not provided, it defaults to today's date. This means queries without an explicitasOfDatewill return records active as of today.
| Entity | Parent | Norwegian |
|---|---|---|
| Position | Employee | Stilling |
| CostUnitLink | Position | Kostnadsfordeling |
| AdditionalAccount | Employee | Tilleggskonto |
| UnionLink | Employee | Fagforeningsmedlemskap |
| CarLink | Employee | Firmabil |
| CreditorClaim | Employee | Utleggstrekk |
| TaxAndContributionRule | Employee | Saerregler |
| PensionLink | Employee | Pensjonsleverandor |
Entities without timeline management. Each entity instance is a current-state record.
POST /tenants/{tenantId}/employees/{id}/children
{
"firstName": "Emma",
"lastName": "Nordmann",
"birthYear": "2018-05-15",
"soleCustodyPeriods": [],
"chronicallyIllPeriods": []
}
PATCH /tenants/{tenantId}/employees/{id}/children/{childId}
{
"firstName": "Emma",
"lastName": "Hansen"
}
The update modifies the existing record directly.
| Entity | Norwegian |
|---|---|
| Children | Barn |
The following are embedded objects within Employee:
| Object | Norwegian | Has Periods |
|---|---|---|
| ContactDetails | Kontaktopplysninger | No |
| PayrollSettings | Lonnsinnstillinger | No |
| SicknessAndAbsence | Sykefravars- og fraversinnstillinger | Yes (flexible) |
All dates use ISO 8601 format: YYYY-MM-DD
Examples:
2024-01-152024-12-31Dates are interpreted as Norwegian local dates (Europe/Oslo timezone).
Example: from: 2024-01-01, to: 2024-01-31
For entities that change annually (e.g., tax information, salary):
POST /tenants/{tenantId}/employees/{id}/tax-information
{
"from": "2025-01-01",
"table": "7150",
"mainEmployer": true
}
The previous year's record automatically gets to set to 2024-12-31.
For temporary roles or allocations:
POST /tenants/{tenantId}/employees/{id}/positions
{
"from": "2024-03-01",
"to": "2024-08-31",
"employmentType": "Ordinary",
"appointmentType": "Temporary",
"positionEndReason": "ContractEnded"
}
Set both dates upfront for temporary arrangements.
To correct a historical record (strict timeline):
fromHandle retroactive changes carefully:
fromto automaticallyto field is read-only and returned in API responsesto when known