Download OpenAPI specification:
https://api.aboardhr.com/v1/The Aboard API uses Bearer token authentication. All API requests must include a valid authentication token in the Authorization header.
Using cURL:
# Set your token as an environment variable
export ABOARD_API_TOKEN="your_token_here"
# Use the token in requests
curl -H "Authorization: Bearer $ABOARD_API_TOKEN" \
https://api.aboardhr.com/v1/company
Using JavaScript/Fetch:
const token = 'your_token_here';
const response = await fetch('https://api.aboardhr.com/v1/company', {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
If your token is invalid or missing, you'll receive a 401 Unauthorized response with an empty body:
HTTP/1.1 401 Unauthorized
Content-Length: 0
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://api.aboardhr.com/v1/company
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://api.aboardhr.com/v1/employees
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.aboardhr.com/v1/employees?filter[role]=manager"
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://api.aboardhr.com/v1/time-off-requests
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://api.aboardhr.com/v1/time-tracking-projects
All list endpoints support pagination using page[limit] and page[offset] parameters:
# Get first 10 employees
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.aboardhr.com/v1/employees?page[limit]=10&page[offset]=0"
Many endpoints support filtering:
role (employee, manager, superadmin)status, time_off_policy_id, time_off_policy_type_id, date, from_date, to_date, requested_at, requested_at_from, requested_at_tostatus, time_tracking_project_id, date, from_date, to_date, from_time, to_timeAll responses follow the JSON:API specification with:
data: The main resource(s)links: Pagination linksrelationships: Links to related resourcesExample response:
{
"data": [
{
"id": "1",
"type": "employees",
"links": {
"self": "https://api.aboardhr.com/v1/employees/1"
},
"attributes": {
"first-name": "Andy",
"last-name": "Bernard",
"work-email": "andy-bernard@company.com",
"role": "manager"
},
"relationships": {
"time-off-requests": {
"links": {
"self": "https://api.aboardhr.com/v1/employees/1/relationships/time-off-requests",
"related": "https://api.aboardhr.com/v1/employees/1/time-off-requests"
}
}
}
}
],
"links": {
"first": "https://api.aboardhr.com/v1/employees?page[limit]=20&page[offset]=0",
"last": "https://api.aboardhr.com/v1/employees?page[limit]=20&page[offset]=0"
}
}
GET /v1/company - Get company informationGET /v1/employees - List all employeesGET /v1/employees/{id} - Get specific employeeGET /v1/bank-details - List all bank detailsGET /v1/bank-details/{id} - Get specific bank detailsSupported Bank Detail Types:
GET /v1/time-tracking-projects - List time tracking projectsGET /v1/time-tracking-projects/{id} - Get specific projectGET /v1/time-tracking-entries - List time tracking entriesGET /v1/time-tracking-entries/{id} - Get specific entryGET /v1/time-off-requests - List time-off requestsGET /v1/time-off-requests/{id} - Get specific requestGET /v1/time-off-policies - List time-off policiesGET /v1/time-off-policies/{id} - Get specific policyGET /v1/time-off-policy-types - List policy typesGET /v1/time-off-policy-types/{id} - Get specific policy typeGET /v1/holiday-calendars - List holiday calendarsGET /v1/holiday-calendars/{id} - Get specific holiday calendarGET /v1/departments - List departmentsGET /v1/departments/{id} - Get specific departmentPOST /v1/departments - Create a departmentPATCH /v1/departments/{id} - Update a departmentDELETE /v1/departments/{id} - Delete a departmentGET /v1/job-titles - List job titlesGET /v1/job-titles/{id} - Get specific job titlePOST /v1/job-titles - Create a job titlePATCH /v1/job-titles/{id} - Update a job titleDELETE /v1/job-titles/{id} - Delete a job titleGET /v1/locations - List locationsGET /v1/locations/{id} - Get specific locationPOST /v1/locations - Create a locationPATCH /v1/locations/{id} - Update a locationDELETE /v1/locations/{id} - Delete a locationGET /v1/profile-attributes - List custom profile attributesGET /v1/profile-attributes/{id} - Get specific profile attributeGET /v1/profile-attribute-options - List profile attribute optionsGET /v1/profile-attribute-options/{id} - Get specific optionGET /v1/profile-attribute-values - List profile attribute valuesGET /v1/profile-attribute-values/{id} - Get specific valueThe API uses standard HTTP status codes:
200 - Success401 - Unauthorized (invalid or missing token) - Returns empty response body404 - Resource not found422 - Validation errorAuthentication errors return empty response body:
HTTP/1.1 401 Unauthorized
Content-Length: 0
Retrieve a paginated list of all employees in the company
| filter[role] | string Enum: "employee" "manager" "superadmin" Example: filter[role]=manager Filter employees by role |
| filter[search] | string Example: filter[search]=jane doe Case-insensitive substring match against first name, last name, full name (first + space + last), and work email. Intended for resolving a specific employee (e.g. a manager) from an external system. |
| filter[archived] | boolean When |
| filter[legal_entity_id] | string Example: filter[legal_entity_id]=1 Only return employees whose current employment is placed in the given legal entity. |
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of employees to return per page |
| page[offset] | integer Default: 0 Number of employees to skip |
{- "data": [
- {
- "id": "1",
- "type": "employees",
- "attributes": {
- "first-name": "Andy",
- "last-name": "Bernard",
- "work-email": "andy-bernard@dundermifflin.example.com",
- "work-phone-number": null,
- "personal-phone-number": null,
- "personal-email": "andy-bernard@example.com",
- "role": "manager"
}, - "relationships": {
- "time-off-policy-types": {
- "links": {
}
}, - "time-off-policies": {
- "links": {
}
}, - "time-off-requests": {
- "links": {
}
}, - "time-tracking-projects": {
- "links": {
}
}, - "time-tracking-entries": {
- "links": {
}
}
}
}
],
}Create an employee (an Aboard Profile) in the company.
first-name, last-namerole — one of no_access, employee, or manager. superadmin (and its admin alias) cannot be assigned via the API; supplying it returns 400 Bad Request.work-email, work-phone-numberpersonal-email, personal-phone-numbernational-identification-numberdate-of-birthdaily-working-hours — defaults to 8 if omittedworkdays — semicolon-separated (monday;tuesday;...); defaults to Monday–Friday if omittedremote-status — one of office, hybrid or remote; defaults to office if omittedemployment-number — only when the company manages employee IDs manually
(Settings → Employee IDs → custom employee IDs). Must be unique within the
company. When employee IDs are auto-generated, supplying it returns
400 Bad Request.Unlike other relationships, an employee's positions and employments are created
inline as arrays under attributes (JSON:API relationship linkage references
existing records; these create new ones). Both are optional — an employee can be
created without a position — but to give the employee a job title and start date,
include at least one position.
positions[] — each needs a role (role-id, or the deprecated job-title-id
— one of them, not both, else 422) and start-date; optional level-id
(a company level that must be one of the role's levels, else 422),
department-id, location-id, manager-id.employments[] — each requires start-date; optional probation-end-date,
legal-entity-id, worker-type and employment-form-id. legal-entity-id
places the employment in one of the company's legal entities; omitted, the
company's default legal entity is used, and an entity from another company
is rejected with 422. When worker-type / employment-form-id
are supplied they seed the employment's initial terms; omitted, the employment
falls back to an employee on the company's permanent form.
If you supply a position but no employment, one employment is created with the
first position's start-date.weekly-working-hours (derived) and archived-at (set by archiving the employee
via DELETE). Any values supplied for these are ignored. employment-number is
also server-generated unless the company uses custom employee IDs (see above).
object |
{- "data": {
- "type": "employees",
- "attributes": {
- "first-name": "Jane",
- "last-name": "Doe",
- "role": "employee",
- "work-email": "jane@dundermifflin.example.com",
- "daily-working-hours": 8,
- "workdays": "monday;tuesday;wednesday;thursday;friday",
- "positions": [
- {
- "role-id": "12",
- "level-id": "7",
- "department-id": "3",
- "location-id": "5",
- "manager-id": "44",
- "start-date": "2026-06-01"
}
], - "employments": [
- {
- "start-date": "2026-06-01",
- "probation-end-date": "2026-09-01",
- "legal-entity-id": "1",
- "worker-type": "employee",
- "employment-form-id": "2"
}
]
}
}
}{- "data": {
- "id": "1",
- "type": "employees",
- "attributes": {
- "first-name": "Andy",
- "last-name": "Bernard",
- "work-email": "andy-bernard@dundermifflin.example.com",
- "work-phone-number": null,
- "personal-email": "andy-bernard@example.com",
- "personal-phone-number": null,
- "role": "manager",
- "national-identification-number": "",
- "date-of-birth": "1981-11-02",
- "employment-number": "12345",
- "daily-working-hours": 8,
- "weekly-working-hours": 40,
- "workdays": "monday;tuesday;wednesday;thursday;friday",
- "remote-status": "hybrid",
- "archived-at": null
}, - "relationships": {
- "time-tracking-projects": {
},
}
}
}Retrieve detailed information about a specific employee by their ID
| id required | string Example: 1 Unique identifier for the employee |
{- "data": {
- "id": "1",
- "type": "employees",
- "attributes": {
- "first-name": "Andy",
- "last-name": "Bernard",
- "work-email": "andy-bernard@dundermifflin.example.com",
- "work-phone-number": null,
- "personal-phone-number": null,
- "personal-email": "andy-bernard@example.com",
- "role": "manager"
}, - "relationships": {
- "time-off-policy-types": {
- "links": {
}
}, - "time-off-policies": {
- "links": {
}
}, - "time-off-requests": {
- "links": {
}
}, - "time-tracking-projects": {
- "links": {
}
}, - "time-tracking-entries": {
- "links": {
}
}
}
}
}Update an employee's mutable attributes.
first-name, last-namework-email, work-phone-numberpersonal-email, personal-phone-numbernational-identification-numberdate-of-birthdaily-working-hoursworkdays — semicolon-separated (monday;tuesday;...)remote-status — one of office, hybrid or remote. Any other value returns 422 Unprocessable Entity.role — one of no_access, employee, or manager. superadmin (and its admin alias) cannot be assigned via the API.employment-number — only when the company manages employee IDs manually
(Settings → Employee IDs → custom employee IDs). Must be unique within the
company; duplicates return 422 Unprocessable Entity. When employee IDs are
auto-generated, this attribute is read-only and setting it returns 400 Bad Request.weekly-working-hours — derived from daily-working-hours × number of workdays.archived-at — set by archiving the employee via DELETE.positions, employments — can be set on create but are not editable here.Sending a non-writable attribute, or a role the API cannot assign (e.g. superadmin),
returns 400 Bad Request.
An employee that has been archived can no longer be modified — PATCH returns
409 Conflict with code: "profile_already_archived".
| id required | string Example: 1 Unique identifier for the employee |
object |
{- "data": {
- "type": "employees",
- "id": "1",
- "attributes": {
- "first-name": "Janet",
- "workdays": "monday;tuesday;wednesday;thursday"
}
}
}{- "data": {
- "id": "1",
- "type": "employees",
- "attributes": {
- "first-name": "Andy",
- "last-name": "Bernard",
- "work-email": "andy-bernard@dundermifflin.example.com",
- "work-phone-number": null,
- "personal-email": "andy-bernard@example.com",
- "personal-phone-number": null,
- "role": "manager",
- "national-identification-number": "",
- "date-of-birth": "1981-11-02",
- "employment-number": "12345",
- "daily-working-hours": 8,
- "weekly-working-hours": 40,
- "workdays": "monday;tuesday;wednesday;thursday;friday",
- "remote-status": "hybrid",
- "archived-at": null
}, - "relationships": {
- "time-tracking-projects": {
},
}
}
}Archive an employee. This is a soft delete — it follows Aboard's offboarding flow (clears the login, ends current positions, cancels upcoming approved absences) and preserves the record and its history rather than hard-deleting it.
An employee that is already archived returns 409 Conflict with
code: "profile_already_archived".
| id required | string Example: 1 Unique identifier for the employee |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}Detailed employee data including employments, employment terms, addresses, positions, and salaries
Retrieve a paginated list of all employments
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
| filter[employee_id] | string Example: filter[employee_id]=1 Only return employments belonging to the given employee |
| filter[legal_entity_id] | string Example: filter[legal_entity_id]=1 Only return employments placed in the given legal entity |
{- "data": [
- {
- "id": "1",
- "type": "employments",
- "attributes": {
- "start-date": "2006-09-21",
- "end-date": null,
- "last-working-date": null
}, - "relationships": {
- "employee": {
- "links": {
}, - "data": {
- "type": "employees",
- "id": "1"
}
}, - "legal-entity": {
- "links": {
}, - "data": {
- "type": "legal-entities",
- "id": "1"
}
}, - "employment-terms": {
- "links": {
}
}
}
}, - {
- "id": "2",
- "type": "employments",
- "attributes": {
- "start-date": "2005-03-24",
- "end-date": null,
- "last-working-date": null
}, - "relationships": {
- "employee": {
- "links": {
}, - "data": {
- "type": "employees",
- "id": "2"
}
}, - "legal-entity": {
- "links": {
}, - "data": {
- "type": "legal-entities",
- "id": "1"
}
}, - "employment-terms": {
- "links": {
}
}
}
}
],
}Create an employment for an employee. An employment records the period an
employee is employed, from start-date until (optionally) end-date.
employee relationship — the employee this employment belongs to. The
employee must belong to your company; referencing an id that isn't visible
to your company returns 404 Not Found.start-date attribute.end-date attribute.last-working-date attribute — requires end-date, and must fall between
start-date and end-date.probation-end-date attribute.legal-entity relationship — the legal entity (employer of record) the
employment is placed in. Omitted, the employment goes into the company's
default legal entity. Referencing a legal entity from another company
returns 404 Not Found.end-date).object |
{- "data": {
- "type": "employments",
- "attributes": {
- "start-date": "2026-06-01",
- "probation-end-date": "2026-09-01"
}, - "relationships": {
- "employee": {
- "data": {
- "type": "employees",
- "id": "1"
}
}, - "legal-entity": {
- "data": {
- "type": "legal-entities",
- "id": "2"
}
}
}
}
}{- "data": {
- "id": "1",
- "type": "employments",
- "attributes": {
- "start-date": "2022-01-01",
- "end-date": null,
- "last-working-date": null,
- "probation-end-date": null,
- "termination-note": null
}, - "relationships": {
}
}
}Retrieve employment details by ID
| id required | string Example: 1 Employment ID |
{- "data": {
- "id": "1",
- "type": "employments",
- "attributes": {
- "start-date": "2006-09-21",
- "end-date": null,
- "last-working-date": null,
- "probation-end-date": null
}, - "relationships": {
- "employee": {
- "links": {
}, - "data": {
- "type": "employees",
- "id": "1"
}
}, - "legal-entity": {
- "links": {
}, - "data": {
- "type": "legal-entities",
- "id": "1"
}
}, - "employment-terms": {
- "links": {
}
}
}
}
}Update an employment's dates or move it to another legal entity.
start-dateend-date — only editable on an employment that already has one. Setting
an end-date on an active (open-ended) employment is rejected; terminate
the employment through POST /v1/employments/{employment_id}/termination
instead, which also closes any open absence cycles.last-working-date — requires end-date, and must fall between
start-date and end-date.probation-end-datelegal-entity — move the employment to another of the company's legal
entities. Referencing a legal entity from another company returns
404 Not Found.employee — an employment cannot be reassigned to another employee after
creation.Sending a non-writable attribute or relationship returns 400 Bad Request.
Setting an end-date on an active employment returns 422 Unprocessable Entity with code: "end_date_not_editable".
end-date).| id required | string Example: 1 Employment ID |
object |
{- "data": {
- "type": "employments",
- "id": "1",
- "attributes": {
- "end-date": "2026-12-31",
- "last-working-date": "2026-11-30"
}
}
}{- "data": {
- "id": "1",
- "type": "employments",
- "attributes": {
- "start-date": "2022-01-01",
- "end-date": null,
- "last-working-date": null,
- "probation-end-date": null,
- "termination-note": null
}, - "relationships": {
}
}
}Delete an employment. An employee always keeps at least one employment:
deleting their last remaining employment returns 409 Conflict with
code: "last_employment".
| id required | string Example: 1 Employment ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}Terminate an employment: set its end date together with the termination
details, and close the employee's open absence cycles. This is the same
flow admins use in Aboard, so prefer it over a plain
PATCH /v1/employments/{id} when ending an employment.
end-date attribute.last-working-date attribute — must fall between start-date and end-date.termination-note attribute — free-text note, stored encrypted.termination-reason relationship — resolve ids through
/v1/termination-reasons. The reason must belong to your company;
referencing an id that isn't visible to your company returns 404 Not Found.An employment that already has an end date cannot be terminated again and
returns 409 Conflict with code: "employment_already_terminated". Use
PATCH /v1/employments/{id} to adjust the dates of an already terminated
employment.
| employment_id required | string Example: 1 Employment ID |
object |
{- "data": {
- "type": "terminations",
- "attributes": {
- "end-date": "2026-12-31",
- "last-working-date": "2026-11-30",
- "termination-note": "Moving abroad"
}, - "relationships": {
- "termination-reason": {
- "data": {
- "type": "termination-reasons",
- "id": "1"
}
}
}
}
}{- "data": {
- "id": "1",
- "type": "employments",
- "attributes": {
- "start-date": "2022-01-01",
- "end-date": null,
- "last-working-date": null,
- "probation-end-date": null,
- "termination-note": null
}, - "relationships": {
}
}
}Retrieve a paginated list of employment terms.
Employment terms record an employee's worker type and employment form from a given effective date. Each employment keeps a history of terms; the set with the latest effective date on or before today is the employment's current terms.
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "employment-terms",
- "attributes": {
- "effective-date": "2022-01-01",
- "worker-type": "employee",
- "note": null
}, - "relationships": {
- "employment": {
- "links": {
}, - "data": {
- "type": "employments",
- "id": "1"
}
}, - "employment-form": {
- "links": {
}, - "data": {
- "type": "employment-forms",
- "id": "1"
}
}
}
}, - {
- "id": "2",
- "type": "employment-terms",
- "attributes": {
- "effective-date": "2024-03-01",
- "worker-type": "contractor",
- "note": "Switched to contracting"
}, - "relationships": {
- "employment": {
- "links": {
}, - "data": {
- "type": "employments",
- "id": "1"
}
}, - "employment-form": {
- "links": {
}, - "data": {
- "type": "employment-forms",
- "id": "2"
}
}
}
}
],
}Create a new set of employment terms for an employment.
The terms' company and effective date are derived from the supplied
employment, so a create only needs the employment and employment-form
relationships plus the worker-type attribute. An optional note and
effective-date can be supplied to override the derived effective date.
The employment relationship can be set on create but never moved on update.
object |
{- "data": {
- "type": "employment-terms",
- "attributes": {
- "worker-type": "contractor",
- "note": "Switched to contracting"
}, - "relationships": {
- "employment": {
- "data": {
- "type": "employments",
- "id": "1"
}
}, - "employment-form": {
- "data": {
- "type": "employment-forms",
- "id": "2"
}
}
}
}
}{- "data": {
- "id": "1",
- "type": "employment-terms",
- "attributes": {
- "effective-date": "2022-01-01",
- "worker-type": "employee",
- "note": null
}, - "relationships": {
}
}
}Retrieve employment terms by ID
| id required | string Example: 1 Employment terms ID |
{- "data": {
- "id": "1",
- "type": "employment-terms",
- "attributes": {
- "effective-date": "2022-01-01",
- "worker-type": "employee",
- "note": null
}, - "relationships": {
- "employment": {
- "links": {
}, - "data": {
- "type": "employments",
- "id": "1"
}
}, - "employment-form": {
- "links": {
}, - "data": {
- "type": "employment-forms",
- "id": "1"
}
}
}
}
}Update a set of employment terms. The effective-date, worker-type and
note attributes and the employment-form relationship are updatable.
The employment relationship cannot be moved — supplying a different
employment is rejected.
| id required | string Example: 1 Employment terms ID |
object |
{- "data": {
- "type": "employment-terms",
- "id": "1",
- "attributes": {
- "worker-type": "contractor"
}, - "relationships": {
- "employment-form": {
- "data": {
- "type": "employment-forms",
- "id": "2"
}
}
}
}
}{- "data": {
- "id": "1",
- "type": "employment-terms",
- "attributes": {
- "effective-date": "2022-01-01",
- "worker-type": "employee",
- "note": null
}, - "relationships": {
}
}
}Delete a set of employment terms.
This mirrors the in-app terms UI: the "every employment has terms" invariant is enforced only at creation, so the last remaining terms for an employment can be deleted.
| id required | string Example: 1 Employment terms ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}Retrieve a paginated list of home addresses
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "home-addresses",
- "attributes": {
- "start-date": "2025-09-03",
- "address-line-1": "aoeu",
- "address-line-2": "",
- "city": "aooeu",
- "zip-code": "123",
- "country-code": "AT"
}, - "relationships": {
- "employee": {
- "links": {
}, - "data": {
- "type": "employees",
- "id": "1"
}
}
}
}
],
}Create a new home address for an employee.
Each employee keeps a history of home addresses; the record with the latest start date on or before today is the employee's current address.
The employee relationship can be set on create but never moved on update.
Referencing an employee that does not exist (or belongs to another company)
returns 404.
object |
{- "data": {
- "type": "home-addresses",
- "attributes": {
- "start-date": "2026-08-01",
- "address-line-1": "1725 Slough Ave",
- "address-line-2": "Apt 2",
- "city": "Scranton",
- "zip-code": "18503",
- "country-code": "US"
}, - "relationships": {
- "employee": {
- "data": {
- "type": "employees",
- "id": "1"
}
}
}
}
}{- "data": {
- "id": "1",
- "type": "home-addresses",
- "attributes": {
- "start-date": "2022-01-01",
- "address-line-1": "1725 Slough Ave",
- "address-line-2": "Apt 2",
- "city": "Scranton",
- "zip-code": "18503",
- "country-code": "US"
}, - "relationships": {
}
}
}Retrieve home address details by ID
| id required | string Example: 1 Home address ID |
{- "data": {
- "id": "1",
- "type": "home-addresses",
- "attributes": {
- "start-date": "2025-09-03",
- "address-line-1": "aoeu",
- "address-line-2": "",
- "city": "aooeu",
- "zip-code": "123",
- "country-code": "AT"
}, - "relationships": {
- "employee": {
- "links": {
}, - "data": {
- "type": "employees",
- "id": "1"
}
}
}
}
}Update a home address. The start-date, address-line-1,
address-line-2, city, zip-code and country-code attributes are
updatable.
The employee relationship cannot be moved — supplying a different
employee is rejected.
| id required | string Example: 1 Home address ID |
object |
{- "data": {
- "type": "home-addresses",
- "id": "1",
- "attributes": {
- "city": "Stockholm",
- "zip-code": "111 22",
- "country-code": "SE"
}
}
}{- "data": {
- "id": "1",
- "type": "home-addresses",
- "attributes": {
- "start-date": "2022-01-01",
- "address-line-1": "1725 Slough Ave",
- "address-line-2": "Apt 2",
- "city": "Scranton",
- "zip-code": "18503",
- "country-code": "US"
}, - "relationships": {
}
}
}Delete a home address from an employee's address history.
| id required | string Example: 1 Home address ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}Retrieve a paginated list of positions
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "positions",
- "attributes": {
- "start-date": "2006-09-21",
- "end-date": null,
- "employment-type": "employee",
- "employment-contract": "full_time",
- "location-id": "5",
- "department-id": "3",
- "job-title-id": "12"
}, - "relationships": {
- "employee": {
- "links": {
}, - "data": {
- "type": "employees",
- "id": "1"
}
}, - "manager": {
- "links": {
}, - "data": {
- "type": "employees",
- "id": "8"
}
}, - "job-title": {
- "links": {
}, - "data": {
- "type": "job-titles",
- "id": "12"
}
}, - "role": {
- "links": {
}, - "data": {
- "type": "roles",
- "id": "12"
}
}, - "level": {
- "links": {
}, - "data": {
- "type": "levels",
- "id": "8"
}
}, - "department": {
- "links": {
}, - "data": {
- "type": "departments",
- "id": "3"
}
}, - "location": {
- "links": {
}, - "data": {
- "type": "locations",
- "id": "5"
}
}
}
}
],
}Create a position for an employee. A position records an employee's job title, start date, employment contract and (optionally) their department, location and manager over a period of time.
employee relationship — the employee this position belongs to.role / job-title. role is canonical and job-title is its
deprecated alias; they write the same field, so provide role
(preferred) or the deprecated job-title — at least one, and not
both. Sending both returns 422 with code: "conflicting_role".start-date attribute.employment-contract attribute — full_time (default), part_time.department, location, manager relationships.level (levels) — the position's level. Use a company level id that is one
of the role's levels (see GET /v1/roles/{id}/levels). Required for a role
whose level scheme is per-level.employment-type — derived from the employee's current employment terms
(worker type + employment form), readable through the
/v1/employment-terms endpoints.The location-id, department-id and job-title-id attributes are read-only.
Set the associated records through JSON:API relationships instead (employee,
role, level, department, location, manager). The job-title
relationship is a deprecated alias of role, still accepted for backward
compatibility. Each related record must belong to your company; referencing an
id that isn't visible to your company returns 404 Not Found.
object |
{- "data": {
- "type": "positions",
- "attributes": {
- "start-date": "2026-06-01",
- "employment-contract": "full_time"
}, - "relationships": {
- "employee": {
- "data": {
- "type": "employees",
- "id": "1"
}
}, - "role": {
- "data": {
- "type": "roles",
- "id": "12"
}
}, - "level": {
- "data": {
- "type": "levels",
- "id": "8"
}
}, - "department": {
- "data": {
- "type": "departments",
- "id": "3"
}
}, - "location": {
- "data": {
- "type": "locations",
- "id": "5"
}
}, - "manager": {
- "data": {
- "type": "employees",
- "id": "44"
}
}
}
}
}{- "data": {
- "id": "1",
- "type": "positions",
- "attributes": {
- "start-date": "2022-01-01",
- "end-date": null,
- "employment-type": "employee",
- "employment-contract": "full_time",
- "location-id": "1",
- "department-id": "1",
- "job-title-id": "1"
}, - "relationships": {
}
}
}Retrieve position details by ID
| id required | string Example: 1 Position ID |
{- "data": {
- "id": "1",
- "type": "positions",
- "attributes": {
- "start-date": "2006-09-21",
- "end-date": null,
- "employment-type": "employee",
- "employment-contract": "full_time",
- "location-id": "5",
- "department-id": "3",
- "job-title-id": "12"
}, - "relationships": {
- "employee": {
- "links": {
}, - "data": {
- "type": "employees",
- "id": "1"
}
}, - "manager": {
- "links": {
}, - "data": {
- "type": "employees",
- "id": "8"
}
}, - "job-title": {
- "links": {
}, - "data": {
- "type": "job-titles",
- "id": "12"
}
}, - "role": {
- "links": {
}, - "data": {
- "type": "roles",
- "id": "12"
}
}, - "level": {
- "links": {
}, - "data": {
- "type": "levels",
- "id": "8"
}
}, - "department": {
- "links": {
}, - "data": {
- "type": "departments",
- "id": "3"
}
}, - "location": {
- "links": {
}, - "data": {
- "type": "locations",
- "id": "5"
}
}
}
}
}Update a position's mutable attributes and relationships.
start-dateemployment-contract — full_time, part_time.role, level, department, location, manager — each related record
must belong to your company; referencing an id that isn't visible to your
company returns 404 Not Found. (job-title is a deprecated alias of
role, still accepted for backward compatibility.) level is a company
level (levels) that must be one of the role's levels.employment-type — read-only; derived from the employee's current employment
terms (worker type + employment form), readable through the
/v1/employment-terms endpoints.location-id, department-id, job-title-id — read-only; set the corresponding
relationship instead.employee — a position cannot be reassigned to another employee after creation.Sending a non-writable attribute returns 400 Bad Request.
| id required | string Example: 1 Position ID |
object |
{- "data": {
- "type": "positions",
- "id": "1",
- "attributes": {
- "start-date": "2026-07-01"
}, - "relationships": {
- "role": {
- "data": {
- "type": "roles",
- "id": "15"
}
}
}
}
}{- "data": {
- "id": "1",
- "type": "positions",
- "attributes": {
- "start-date": "2022-01-01",
- "end-date": null,
- "employment-type": "employee",
- "employment-contract": "full_time",
- "location-id": "1",
- "department-id": "1",
- "job-title-id": "1"
}, - "relationships": {
}
}
}Retrieve a paginated list of salaries
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "salaries",
- "attributes": {
- "currency": "USD",
- "start-date": "2005-03-24",
- "pay-period": "yearly",
- "amount-in-cents": "67000000"
}, - "relationships": {
- "employee": {
- "links": {
}, - "data": {
- "type": "employees",
- "id": "2"
}
}
}
}
],
}Create a new salary for an employee.
Each employee keeps a history of salaries; the record with the latest start date on or before today is the employee's current salary. An employee can only have one salary per start date.
The employee relationship can be set on create but never moved on update.
Referencing an employee that does not exist (or belongs to another company)
returns 404.
object |
{- "data": {
- "type": "salaries",
- "attributes": {
- "currency": "SEK",
- "start-date": "2026-08-01",
- "pay-period": "monthly",
- "amount-in-cents": 4200000
}, - "relationships": {
- "employee": {
- "data": {
- "type": "employees",
- "id": "1"
}
}
}
}
}{- "data": {
- "id": "1",
- "type": "salaries",
- "attributes": {
- "currency": "USD",
- "start-date": "2022-01-01",
- "pay-period": "yearly",
- "amount-in-cents": 8500000
}, - "relationships": {
}
}
}Retrieve salary details by ID
| id required | string Example: 1 Salary ID |
{- "data": {
- "id": "1",
- "type": "salaries",
- "attributes": {
- "currency": "USD",
- "start-date": "2005-03-24",
- "pay-period": "yearly",
- "amount-in-cents": 67000000
}, - "relationships": {
- "employee": {
- "links": {
}, - "data": {
- "type": "employees",
- "id": "2"
}
}
}
}
}Update a salary. The currency, start-date, pay-period and
amount-in-cents attributes are updatable.
The employee relationship cannot be moved — supplying a different
employee is rejected.
| id required | string Example: 1 Salary ID |
object |
{- "data": {
- "type": "salaries",
- "id": "1",
- "attributes": {
- "pay-period": "yearly",
- "amount-in-cents": 60000000
}
}
}{- "data": {
- "id": "1",
- "type": "salaries",
- "attributes": {
- "currency": "USD",
- "start-date": "2022-01-01",
- "pay-period": "yearly",
- "amount-in-cents": 8500000
}, - "relationships": {
}
}
}Delete a salary from an employee's salary history.
| id required | string Example: 1 Salary ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}Retrieve a paginated list of all bank details in the company
| page[limit] | integer <= 50 Default: 20 Example: page[limit]=20 Number of bank details to return per page |
| page[offset] | integer Default: 0 Number of bank details to skip |
{- "data": [
- {
- "id": "1",
- "type": "ibans",
- "attributes": {
- "account-number": "GB27BWXX85439131864698",
- "bank-name": "Bank of America",
- "account-type": "IBAN",
- "bic": ""
}, - "relationships": {
- "profile": {
- "links": {
}
}
}
}, - {
- "id": "2",
- "type": "swedens",
- "attributes": {
- "account-number": "12312412",
- "bank-name": "aoeu",
- "account-type": "Swedish bank account",
- "clearing-number": "123"
}, - "relationships": {
- "profile": {
- "links": {
}
}
}
}, - {
- "id": "3",
- "type": "us",
- "attributes": {
- "account-number": "1234567890",
- "bank-name": "Chase Bank",
- "account-type": "US bank account",
- "routing-number": "021000021"
}, - "relationships": {
- "profile": {
- "links": {
}
}
}
}
],
}Retrieve specific bank details by ID
| id required | string Example: 1 Bank details ID |
{- "data": {
- "id": "1",
- "type": "ibans",
- "attributes": {
- "account-number": "GB27BWXX85439131864698",
- "bank-name": "Bank of America",
- "account-type": "IBAN",
- "bic": ""
}, - "relationships": {
- "profile": {
- "links": {
}
}
}
}
}Retrieve a paginated list of departments
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "departments",
- "attributes": {
- "name": "Engineering"
}
}, - {
- "id": "2",
- "type": "departments",
- "attributes": {
- "name": "Sales"
}
}
],
}Create a department in the company.
object |
{- "data": {
- "type": "departments",
- "attributes": {
- "name": "Engineering"
}
}
}{- "data": {
- "id": "1",
- "type": "departments",
- "attributes": {
- "name": "Engineering"
}
}
}Update a department's name.
| id required | string Example: 1 Department ID |
object |
{- "data": {
- "type": "departments",
- "id": "1",
- "attributes": {
- "name": "Platform"
}
}
}{- "data": {
- "id": "1",
- "type": "departments",
- "attributes": {
- "name": "Engineering"
}
}
}Delete a department. A department that is still referenced by other records
(for example an upcoming hire) cannot be deleted and returns 409 Conflict
with code: "record_in_use".
| id required | string Example: 1 Department ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}⚠️ Deprecated — use Roles instead.
Job titles are the legacy name for roles and resolve to the same records. These endpoints remain only for backward compatibility and will be removed in a future version. New integrations should use the Roles endpoints.
Retrieve a paginated list of job titles
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "job-titles",
- "attributes": {
- "name": "Software Engineer"
}
}, - {
- "id": "2",
- "type": "job-titles",
- "attributes": {
- "name": "Product Manager"
}
}
],
}Create a job title in the company.
object |
{- "data": {
- "type": "job-titles",
- "attributes": {
- "name": "Staff Engineer"
}
}
}{- "data": {
- "id": "1",
- "type": "job-titles",
- "attributes": {
- "name": "Software Engineer"
}
}
}Update a job title's name.
| id required | string Example: 1 Job title ID |
object |
{- "data": {
- "type": "job-titles",
- "id": "1",
- "attributes": {
- "name": "Senior Software Engineer"
}
}
}{- "data": {
- "id": "1",
- "type": "job-titles",
- "attributes": {
- "name": "Software Engineer"
}
}
}Delete a job title. A job title that is still referenced by other records
(for example an employee position or an upcoming hire) cannot be deleted and
returns 409 Conflict with code: "record_in_use".
| id required | string Example: 1 Job title ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}Retrieve a paginated list of locations
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "locations",
- "attributes": {
- "name": "New York Office"
}
}, - {
- "id": "2",
- "type": "locations",
- "attributes": {
- "name": "London Office"
}
}
],
}Create a location in the company.
namecity, street-address, zip-code, country-code (ISO 3166-1 alpha-2)timezone — IANA time zone identifierlatitude, longitudeobject |
{- "data": {
- "type": "locations",
- "attributes": {
- "name": "New York Office",
- "city": "New York",
- "street-address": "1166 Avenue of the Americas",
- "zip-code": "10036",
- "country-code": "US",
- "timezone": "America/New_York",
- "latitude": 40.7589,
- "longitude": -73.9851
}
}
}{- "data": {
- "id": "1",
- "type": "locations",
- "attributes": {
- "name": "New York Office",
- "city": "New York",
- "street-address": "1166 Avenue of the Americas",
- "zip-code": "10036",
- "country-code": "US",
- "timezone": "America/New_York",
- "latitude": 40.7589,
- "longitude": -73.9851
}
}
}Retrieve location details by ID
| id required | string Example: 1 Location ID |
{- "data": {
- "id": "1",
- "type": "locations",
- "attributes": {
- "name": "New York Office",
- "city": "New York",
- "street-address": "1166 Avenue of the Americas",
- "zip-code": "10036",
- "country-code": "US",
- "timezone": "America/New_York",
- "latitude": 40.7589,
- "longitude": -73.9851
}
}
}Update a location's mutable attributes: name, city, street-address,
zip-code, country-code, timezone, latitude, longitude.
| id required | string Example: 1 Location ID |
object |
{- "data": {
- "type": "locations",
- "id": "1",
- "attributes": {
- "city": "Brooklyn"
}
}
}{- "data": {
- "id": "1",
- "type": "locations",
- "attributes": {
- "name": "New York Office",
- "city": "New York",
- "street-address": "1166 Avenue of the Americas",
- "zip-code": "10036",
- "country-code": "US",
- "timezone": "America/New_York",
- "latitude": 40.7589,
- "longitude": -73.9851
}
}
}Delete a location. A location that is still referenced by other records
(for example an upcoming hire) cannot be deleted and returns 409 Conflict
with code: "record_in_use".
| id required | string Example: 1 Location ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}Contractual employment forms (permanent, fixed term, ...) referenced by employment terms. Companies start with five system-default forms and can add custom ones.
Retrieve a paginated list of employment forms.
Employment forms describe the contractual shape of an employment (permanent,
fixed term, seasonal, ...). Every company starts with five system-default
forms (permanent, fixed_term, seasonal, casual_or_on_call, other)
and can add custom forms on top.
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "employment-forms",
- "attributes": {
- "name": "Permanent",
- "slug": "permanent",
- "system-default": true
}
}, - {
- "id": "2",
- "type": "employment-forms",
- "attributes": {
- "name": "Fixed term",
- "slug": "fixed_term",
- "system-default": true
}
}
],
}Create a custom employment form in the company.
Both name and slug are required. The slug must be unique within the
company and cannot be changed after creation; it is normalized to lowercase
letters, digits and underscores.
object |
{- "data": {
- "type": "employment-forms",
- "attributes": {
- "name": "Freelance",
- "slug": "freelance"
}
}
}{- "data": {
- "id": "1",
- "type": "employment-forms",
- "attributes": {
- "name": "Permanent",
- "slug": "permanent",
- "system-default": true
}
}
}Retrieve employment form details by ID
| id required | string Example: 1 Employment form ID |
{- "data": {
- "id": "1",
- "type": "employment-forms",
- "attributes": {
- "name": "Permanent",
- "slug": "permanent",
- "system-default": true
}
}
}Update a custom employment form's name.
slug cannot be changed after creation.permanent, fixed_term, seasonal,
casual_or_on_call, other) cannot be renamed.Both return 422 Unprocessable Entity.
| id required | string Example: 1 Employment form ID |
object |
{- "data": {
- "type": "employment-forms",
- "id": "6",
- "attributes": {
- "name": "Freelancer"
}
}
}{- "data": {
- "id": "1",
- "type": "employment-forms",
- "attributes": {
- "name": "Permanent",
- "slug": "permanent",
- "system-default": true
}
}
}Delete a custom employment form. Returns 409 Conflict with
code: "record_in_use" when the form cannot be deleted:
permanent, fixed_term, seasonal,
casual_or_on_call, other).| id required | string Example: 1 Employment form ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}The company's legal entities -- the employers of record that employments and hires are placed in. Every company has one default entity; companies with several assign each employment to one.
Retrieve a paginated list of the company's legal entities, in the display order configured in Aboard.
A legal entity is the employer of record for an employment -- for example
a subsidiary in another country. Every company has one default legal
entity, and companies with more than one assign each employment and hire
to a specific entity. The list includes archived entities (archived-at
set) so existing employments can still be resolved.
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "legal-entities",
- "attributes": {
- "name": "Dunder Mifflin AB",
- "organization-number": "556000-0001",
- "street-address": "Sveavägen 1",
- "zip-code": "11157",
- "city": "Stockholm",
- "country-code": "SE",
- "is-default": true,
- "archived-at": null
}
}, - {
- "id": "2",
- "type": "legal-entities",
- "attributes": {
- "name": "Dunder Mifflin Ltd",
- "organization-number": "12345678",
- "street-address": "1 Paper Street",
- "zip-code": "EC1A 1AA",
- "city": "London",
- "country-code": "GB",
- "is-default": false,
- "archived-at": null
}
}
],
}Create a legal entity in the company.
name is required and must be unique within the company. The other
attributes -- organization-number, street-address, zip-code, city,
country-code -- are optional.
is-default and archived-at are read-only; sending either returns
400 Bad Request. Manage the default entity and archiving from
Settings → Legal entities in Aboard.
object |
{- "data": {
- "type": "legal-entities",
- "attributes": {
- "name": "Dunder Mifflin Ltd",
- "organization-number": "12345678",
- "street-address": "1 Paper Street",
- "zip-code": "EC1A 1AA",
- "city": "London",
- "country-code": "GB"
}
}
}{- "data": {
- "id": "1",
- "type": "legal-entities",
- "attributes": {
- "name": "Dunder Mifflin AB",
- "organization-number": "556000-0001",
- "street-address": "Sveavägen 1",
- "zip-code": "11157",
- "city": "Stockholm",
- "country-code": "SE",
- "is-default": true,
- "archived-at": null
}
}
}Retrieve legal entity details by ID
| id required | string Example: 1 Legal entity ID |
{- "data": {
- "id": "1",
- "type": "legal-entities",
- "attributes": {
- "name": "Dunder Mifflin AB",
- "organization-number": "556000-0001",
- "street-address": "Sveavägen 1",
- "zip-code": "11157",
- "city": "Stockholm",
- "country-code": "SE",
- "is-default": true,
- "archived-at": null
}
}
}Update a legal entity's mutable attributes: name, organization-number,
street-address, zip-code, city, country-code.
is-default and archived-at are read-only; sending either returns
400 Bad Request. Manage the default entity and archiving from
Settings → Legal entities in Aboard.
| id required | string Example: 1 Legal entity ID |
object |
{- "data": {
- "type": "legal-entities",
- "id": "2",
- "attributes": {
- "name": "Dunder Mifflin UK Ltd"
}
}
}{- "data": {
- "id": "1",
- "type": "legal-entities",
- "attributes": {
- "name": "Dunder Mifflin AB",
- "organization-number": "556000-0001",
- "street-address": "Sveavägen 1",
- "zip-code": "11157",
- "city": "Stockholm",
- "country-code": "SE",
- "is-default": true,
- "archived-at": null
}
}
}Delete a legal entity. Returns 409 Conflict with code: "record_in_use"
when the entity cannot be deleted:
Unhandled hires do not block deletion; their legal-entity is cleared.
To retire an entity that still has employments, archive it from
Settings → Legal entities in Aboard instead.
| id required | string Example: 1 Legal entity ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}Read-only list of the company's termination reasons (resignation or termination). Integrations resolve a reason ID here before terminating an employment.
Retrieve a paginated list of the company's termination reasons.
Integrations resolve a termination reason ID here before terminating an
employment through POST /v1/employments/{employment_id}/termination.
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "termination-reasons",
- "attributes": {
- "name": "Relocation",
- "termination-type": "resignation"
}
}, - {
- "id": "2",
- "type": "termination-reasons",
- "attributes": {
- "name": "Redundancy",
- "termination-type": "termination"
}
}
],
}Retrieve termination reason details by ID
| id required | string Example: 1 Termination reason ID |
{- "data": {
- "id": "1",
- "type": "termination-reasons",
- "attributes": {
- "name": "Relocation",
- "termination-type": "resignation"
}
}
}Retrieve a paginated list of roles.
Roles are the job-architecture successor to job titles (same underlying
records). Prefer this over the deprecated GET /v1/job-titles.
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "roles",
- "attributes": {
- "name": "Software Engineer"
}
}, - {
- "id": "2",
- "type": "roles",
- "attributes": {
- "name": "Product Manager"
}
}
],
}Create a role in the company.
Besides name, a role can carry an optional code and description, and a
family relationship. The family must reference one of the company's
families (see GET /v1/families); an unknown family returns 404.
object |
{- "data": {
- "type": "roles",
- "attributes": {
- "name": "Staff Engineer",
- "code": "ENG",
- "description": "Builds and maintains the product."
}, - "relationships": {
- "family": {
- "data": {
- "type": "families",
- "id": "1"
}
}
}
}
}{- "data": {
- "id": "1",
- "type": "roles",
- "attributes": {
- "name": "Software Engineer",
- "code": "ENG",
- "description": "Builds and maintains the product."
}, - "relationships": {
}
}
}Update a role's name, code, description, or family relationship.
The family must reference one of the company's families (see
GET /v1/families); an unknown family returns 404.
| id required | string Example: 1 Role ID |
object |
{- "data": {
- "type": "roles",
- "id": "1",
- "attributes": {
- "name": "Senior Software Engineer",
- "code": "ENG",
- "description": "Builds and maintains the product."
}, - "relationships": {
- "family": {
- "data": {
- "type": "families",
- "id": "1"
}
}
}
}
}{- "data": {
- "id": "1",
- "type": "roles",
- "attributes": {
- "name": "Software Engineer",
- "code": "ENG",
- "description": "Builds and maintains the product."
}, - "relationships": {
}
}
}Delete a role. A role that is still referenced by other records (for example
an employee position or an upcoming hire) cannot be deleted and returns
409 Conflict with code: "record_in_use".
| id required | string Example: 1 Role ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}Retrieve the company levels connected to a role, in ladder order. Each entry
is addressed by the level id and carries a code and a name (the per-role
override, or the level's own name when not overridden). Use a returned level
id for a hire's or position's level relationship.
| role_id required | string Example: 1 Role ID |
{- "data": [
- {
- "id": "8",
- "type": "levels",
- "attributes": {
- "code": "L3",
- "name": "Senior"
}
}
]
}Connect a company level to a role. The id must be one of the company's
levels (see GET /v1/levels). Provide an optional per-role name override;
when omitted, the level's own name is used.
422 with code: "invalid_level" (no source pointer) when data.id is
not one of the company's levels.422 with code: "validation_error" and
source.pointer: "/data/attributes/level-id" when the level is already
connected to the role.| role_id required | string Example: 1 Role ID |
object |
{- "data": {
- "type": "levels",
- "id": "8",
- "attributes": {
- "name": "Senior"
}
}
}{- "data": {
- "id": "1",
- "type": "levels",
- "attributes": {
- "code": "L3",
- "name": "Senior"
}
}
}Update the per-role name override for a level connected to a role.
| role_id required | string Example: 1 Role ID |
| level_id required | string Example: 8 Level ID |
object |
{- "data": {
- "type": "levels",
- "id": "8",
- "attributes": {
- "name": "Principal"
}
}
}{- "data": {
- "id": "1",
- "type": "levels",
- "attributes": {
- "code": "L3",
- "name": "Senior"
}
}
}Disconnect a level from a role. A level that is still in use by a position
cannot be removed and returns 409 Conflict with code: "record_in_use".
| role_id required | string Example: 1 Role ID |
| level_id required | string Example: 8 Level ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}Retrieve a paginated list of the company's levels, in ladder order.
Levels are the company's seniority ladder. Connect them to roles via
/v1/roles/{id}/levels.
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "levels",
- "attributes": {
- "code": "L2",
- "name": "Mid",
- "description": "Established individual contributor."
}
}, - {
- "id": "2",
- "type": "levels",
- "attributes": {
- "code": "L3",
- "name": "Senior",
- "description": "Senior individual contributor."
}
}
],
}Create a level in the company. code is unique per company; a duplicate
returns 422.
object |
{- "data": {
- "type": "levels",
- "attributes": {
- "code": "L3",
- "name": "Senior",
- "description": "Senior individual contributor."
}
}
}{- "data": {
- "id": "1",
- "type": "levels",
- "attributes": {
- "code": "L3",
- "name": "Senior",
- "description": "What this level means."
}
}
}Retrieve a level by ID.
| id required | string Example: 1 Level ID |
{- "data": {
- "id": "1",
- "type": "levels",
- "attributes": {
- "code": "L3",
- "name": "Senior",
- "description": "Senior individual contributor."
}
}
}Update a level's code, name or description. code is unique per
company; a duplicate returns 422.
| id required | string Example: 1 Level ID |
object |
{- "data": {
- "type": "levels",
- "id": "1",
- "attributes": {
- "name": "Senior Engineer"
}
}
}{- "data": {
- "id": "1",
- "type": "levels",
- "attributes": {
- "code": "L3",
- "name": "Senior",
- "description": "What this level means."
}
}
}Delete a level. A level that is still in use by positions cannot be deleted
and returns 409 Conflict with code: "record_in_use".
| id required | string Example: 1 Level ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}Retrieve a paginated list of the company's job families.
Families are groupings of related roles. Assign a role to a family via the
family relationship on /v1/roles.
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "families",
- "attributes": {
- "name": "Engineering"
}
}, - {
- "id": "2",
- "type": "families",
- "attributes": {
- "name": "Sales"
}
}
],
}Create a job family in the company. name is unique per company; a
duplicate returns 422.
object |
{- "data": {
- "type": "families",
- "attributes": {
- "name": "Engineering"
}
}
}{- "data": {
- "id": "1",
- "type": "families",
- "attributes": {
- "name": "Engineering"
}
}
}Update a family's name. name is unique per company; a duplicate returns
422.
| id required | string Example: 1 Family ID |
object |
{- "data": {
- "type": "families",
- "id": "1",
- "attributes": {
- "name": "Product Engineering"
}
}
}{- "data": {
- "id": "1",
- "type": "families",
- "attributes": {
- "name": "Engineering"
}
}
}Delete a family.
| id required | string Example: 1 Family ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}Pre-activation employee records (e.g. from an ATS) that admins later turn into Aboard profiles. The first write endpoints in the public API.
Retrieve a paginated list of hires (pre-activation employees) for the company.
Hires are records created by integrations (e.g. an ATS) or by managers in advance of activating an Aboard Profile. Once a hire has been handled in Aboard, its handled attribute becomes true and the record becomes read-only via the API.
| filter[external-source] | string Example: filter[external-source]=teamtailor Filter by the name of the external system that created the hire (e.g. |
| filter[external-id] | string Example: filter[external-id]=tt-7421 Filter by the hire's ID in the external system. |
| filter[handled] | boolean Filter by whether the hire has been handled in Aboard.
Omitted: returns both. |
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of hires to return per page |
| page[offset] | integer Default: 0 Number of hires to skip |
{- "data": [
- {
- "id": "1",
- "type": "hires",
- "attributes": {
- "first-name": "Jane",
- "last-name": "Doe",
- "personal-email": "jane@example.com",
- "personal-phone-number": null,
- "birthday": null,
- "gender": null,
- "address-line-1": null,
- "address-line-2": null,
- "city": null,
- "zip-code": null,
- "country-code": null,
- "planned-start-date": "2026-06-01",
- "worker-type": "employee",
- "employment-type": "full_time",
- "employment-contract": "permanent",
- "probation-months": 6,
- "probation-end-date": "2026-11-30",
- "salary-amount-in-cents": null,
- "salary-currency": null,
- "salary-pay-period": null,
- "notes": null,
- "external-source": "teamtailor",
- "external-id": "tt-7421",
- "referred-by-email": "anna@example.com",
- "handled": false,
- "created-at": "2026-05-20T08:00:00Z",
- "updated-at": "2026-05-20T08:00:00Z"
}, - "relationships": {
- "role": {
- "links": {
}
}, - "level": {
- "links": {
}
}, - "job-title": {
- "links": {
}
}, - "department": {
- "links": {
}
}, - "location": {
- "links": {
}
}, - "manager": {
- "links": {
}
}, - "referred-by": {
- "links": {
}
}, - "onboarding-template": {
- "links": {
}
}, - "employment-form": {
- "links": {
}
}, - "legal-entity": {
- "links": {
}
}, - "time-off-policies": {
- "links": {
}
}
}
}
],
}Create a hire in the company.
Attributes — first-name, last-name, personal-email.
Relationships — department, location, and one of role / job-title.
role is canonical and job-title is its deprecated alias; they write
the same field, so provide role (preferred) or the deprecated
job-title — at least one, and not both. Sending both returns 422
with code: "conflicting_role".
An unknown relationship id, or one belonging to another company (role,
department, location, manager, etc.), returns 404 Not Found.
personal-phone-numberbirthdaygender — one of male, female, non_binary, other, prefer_not_to_sayaddress-line-1, address-line-2, city, zip-code, country-codeplanned-start-dateworker-type — classification of the worker; drives the employment terms created on activation. Defaults to employee.employment-type — deprecated, use worker-type and the employment-form relationship instead. Kept for backward compatibility; a legacy value is mapped onto worker-type / employment-form unless those are set explicitly.employment-contractprobation-months — probation length in whole months, 1 to 6. Omit or send null for no probation. The last day is worked out from planned-start-date and returned as probation-end-date.probation-end-date — deprecated, send probation-months instead. Still accepted and converted to the nearest whole month from planned-start-date, capped at 6. If both are sent, probation-months wins.salary-amount-in-cents, salary-currency, salary-pay-periodnotesexternal-source, external-id — pair them to make the hire findable via filter[external-source] / filter[external-id] on the list endpoint. The combination is unique per company. Immutable once set (no PATCH).created-by-name, created-by-email — name and email of the person who created the hire in the source system, when the creator is not an Aboard user. Immutable once set (no PATCH).referred-by-email — work email of the employee who referred the hire. Aboard resolves it to an active employee and sets referred-by. An address that matches no employee is kept, with referred-by left empty; a malformed one returns 422.level (levels) — the hire's level. Use a company level id that is one of the role's levels (see GET /v1/roles/{id}/levels). A hire can be created without one, but a per-level role can't be activated into an employee until a level is set.manager (employees)referred-by (employees) — the employee who referred the hire. Takes precedence over referred-by-email in the same request.onboarding-template (onboarding-templates)employment-form (employment-forms) — the form used for the employment terms created on activation.legal-entity (legal-entities) — the legal entity the employment created on activation is placed in. Omitted, the company's default legal entity is used. Referencing a legal entity from another company returns 404 Not Found.time-off-policies (time-off-policies, many)created-by, profile, handled, created-at, updated-at. Any values supplied for these are ignored.
object |
{- "data": {
- "type": "hires",
- "attributes": {
- "first-name": "Jane",
- "last-name": "Doe",
- "personal-email": "jane@example.com",
- "planned-start-date": "2026-06-01",
- "probation-months": 6,
- "external-source": "teamtailor",
- "external-id": "tt-7421",
- "referred-by-email": "anna@example.com"
}, - "relationships": {
- "role": {
- "data": {
- "type": "roles",
- "id": "12"
}
}, - "level": {
- "data": {
- "type": "levels",
- "id": "8"
}
}, - "department": {
- "data": {
- "type": "departments",
- "id": "3"
}
}, - "location": {
- "data": {
- "type": "locations",
- "id": "5"
}
}, - "manager": {
- "data": {
- "type": "employees",
- "id": "44"
}
}, - "legal-entity": {
- "data": {
- "type": "legal-entities",
- "id": "2"
}
}
}
}
}{- "data": {
- "id": "1",
- "type": "hires",
- "attributes": {
- "first-name": "Jane",
- "last-name": "Doe",
- "personal-email": "jane@example.com",
- "personal-phone-number": "+46701234567",
- "birthday": "1990-04-12",
- "gender": "female",
- "address-line-1": "Sveavägen 1",
- "address-line-2": null,
- "city": "Stockholm",
- "zip-code": "11157",
- "country-code": "SE",
- "planned-start-date": "2026-06-01",
- "worker-type": "employee",
- "employment-type": "full_time",
- "employment-contract": "permanent",
- "probation-months": 6,
- "probation-end-date": "2026-11-30",
- "salary-amount-in-cents": "5000000",
- "salary-currency": "SEK",
- "salary-pay-period": "monthly",
- "notes": "Joining the Backend team.",
- "external-source": "teamtailor",
- "external-id": "tt-7421",
- "created-by-name": "Alex Recruiter",
- "created-by-email": "alex@example.com",
- "referred-by-email": "anna@example.com",
- "handled": false,
- "avatar": {
}, - "created-at": "2026-05-20T08:00:00Z",
- "updated-at": "2026-05-20T08:00:00Z"
}, - "relationships": {
}
}
}Retrieve hire details by ID.
| id required | string Example: 1 Hire ID |
{- "data": {
- "id": "1",
- "type": "hires",
- "attributes": {
- "first-name": "Jane",
- "last-name": "Doe",
- "personal-email": "jane@example.com",
- "personal-phone-number": "+46701234567",
- "birthday": "1990-04-12",
- "gender": "female",
- "address-line-1": "Sveavägen 1",
- "address-line-2": null,
- "city": "Stockholm",
- "zip-code": "11157",
- "country-code": "SE",
- "planned-start-date": "2026-06-01",
- "worker-type": "employee",
- "employment-type": "full_time",
- "employment-contract": "permanent",
- "probation-months": 6,
- "probation-end-date": "2026-11-30",
- "salary-amount-in-cents": "5000000",
- "salary-currency": "SEK",
- "salary-pay-period": "monthly",
- "notes": "Joining the Backend team.",
- "external-source": "teamtailor",
- "external-id": "tt-7421",
- "created-by-name": "Alex Recruiter",
- "created-by-email": "alex@example.com",
- "referred-by-email": "anna@example.com",
- "handled": false,
- "avatar": {
}, - "created-at": "2026-05-20T08:00:00Z",
- "updated-at": "2026-05-20T08:00:00Z"
}, - "relationships": {
}
}
}Update a hire's mutable attributes and relationships.
first-name, last-namepersonal-email, personal-phone-numberbirthday, genderaddress-line-1, address-line-2, city, zip-code, country-codeplanned-start-dateemployment-type, employment-contractprobation-months — probation length in whole months, 1 to 6, or null for noneprobation-end-date — deprecated, converted to probation-months (see the Hire schema)salary-amount-in-cents, salary-currency, salary-pay-periodnotesreferred-by-email — resolved to an active employee by work email; null clears itmanagerreferred-by — the employee who referred the hire; wins over referred-by-email in the same requestrole, department, location (job-title is a deprecated alias of role)level — the hire's level; a company level (levels) that must be one of the role's levelsonboarding-templateemployment-formlegal-entity — the legal entity the employment created on activation is placed in. Referencing a legal entity from another company returns 404 Not Found.time-off-policiesexternal-source, external-id — settable on create, then frozen as the integration's lookup key.created-by-name, created-by-email — settable on create, then frozen.created-by, profile, handled, created-at, updated-at — server-managed.Values supplied for any of these are ignored.
A hire that has already been handled in Aboard (handled: true) cannot be modified — PATCH returns 409 Conflict with code: "hire_already_handled". The same applies to the relationship endpoints, e.g. PATCH or DELETE on /v1/hires/{id}/relationships/referred-by.
| id required | string Example: 1 Hire ID |
object |
{- "data": {
- "type": "hires",
- "id": "1",
- "attributes": {
- "first-name": "Janet",
- "planned-start-date": "2026-06-15"
}
}
}{- "data": {
- "id": "1",
- "type": "hires",
- "attributes": {
- "first-name": "Jane",
- "last-name": "Doe",
- "personal-email": "jane@example.com",
- "personal-phone-number": "+46701234567",
- "birthday": "1990-04-12",
- "gender": "female",
- "address-line-1": "Sveavägen 1",
- "address-line-2": null,
- "city": "Stockholm",
- "zip-code": "11157",
- "country-code": "SE",
- "planned-start-date": "2026-06-01",
- "worker-type": "employee",
- "employment-type": "full_time",
- "employment-contract": "permanent",
- "probation-months": 6,
- "probation-end-date": "2026-11-30",
- "salary-amount-in-cents": "5000000",
- "salary-currency": "SEK",
- "salary-pay-period": "monthly",
- "notes": "Joining the Backend team.",
- "external-source": "teamtailor",
- "external-id": "tt-7421",
- "created-by-name": "Alex Recruiter",
- "created-by-email": "alex@example.com",
- "referred-by-email": "anna@example.com",
- "handled": false,
- "avatar": {
}, - "created-at": "2026-05-20T08:00:00Z",
- "updated-at": "2026-05-20T08:00:00Z"
}, - "relationships": {
}
}
}Delete a hire that has not yet been handled in Aboard.
A hire that has already been handled (handled: true) cannot be deleted via the API — DELETE returns 409 Conflict with code: "hire_already_handled".
| id required | string Example: 1 Hire ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}Upload an avatar image for a hire by sending the bytes as multipart/form-data.
Re-uploading silently replaces any existing avatar. The response is the full Hire resource, including the populated avatar attribute with small, medium, and original URLs.
Binary uploads are the documented exception to the JSON:API-only write convention used elsewhere in this API. The request body is multipart/form-data with a single part:
file — the binary image file. Accepted content types match the supported image formats (image/jpeg, image/png, image/webp, image/gif, image/svg+xml).No JSON data part is required — the avatar has no other writable attributes.
A hire that has already been handled in Aboard (handled: true) cannot have its avatar modified — PUT returns 409 Conflict with code: "hire_already_handled". After activation, manage the avatar on the resulting employee profile instead.
PUT /v1/hires/42/avatar
Authorization: Bearer YOUR_TOKEN
Content-Type: multipart/form-data; boundary=----X
------X
Content-Disposition: form-data; name="file"; filename="avatar.jpg"
Content-Type: image/jpeg
<binary>
------X--
| id required | string Example: 42 ID of the hire |
| file required | string <binary> The image file to attach. |
{- "data": {
- "id": "1",
- "type": "hires",
- "attributes": {
- "first-name": "Jane",
- "last-name": "Doe",
- "personal-email": "jane@example.com",
- "personal-phone-number": "+46701234567",
- "birthday": "1990-04-12",
- "gender": "female",
- "address-line-1": "Sveavägen 1",
- "address-line-2": null,
- "city": "Stockholm",
- "zip-code": "11157",
- "country-code": "SE",
- "planned-start-date": "2026-06-01",
- "worker-type": "employee",
- "employment-type": "full_time",
- "employment-contract": "permanent",
- "probation-months": 6,
- "probation-end-date": "2026-11-30",
- "salary-amount-in-cents": "5000000",
- "salary-currency": "SEK",
- "salary-pay-period": "monthly",
- "notes": "Joining the Backend team.",
- "external-source": "teamtailor",
- "external-id": "tt-7421",
- "created-by-name": "Alex Recruiter",
- "created-by-email": "alex@example.com",
- "referred-by-email": "anna@example.com",
- "handled": false,
- "avatar": {
}, - "created-at": "2026-05-20T08:00:00Z",
- "updated-at": "2026-05-20T08:00:00Z"
}, - "relationships": {
}
}
}Detach the hire's current avatar and clear the cached URLs. Returns the updated Hire resource with avatar: null.
Returns 409 Conflict when the hire has already been handled in Aboard.
| id required | string Example: 42 ID of the hire |
{- "data": {
- "id": "1",
- "type": "hires",
- "attributes": {
- "first-name": "Jane",
- "last-name": "Doe",
- "personal-email": "jane@example.com",
- "personal-phone-number": "+46701234567",
- "birthday": "1990-04-12",
- "gender": "female",
- "address-line-1": "Sveavägen 1",
- "address-line-2": null,
- "city": "Stockholm",
- "zip-code": "11157",
- "country-code": "SE",
- "planned-start-date": "2026-06-01",
- "worker-type": "employee",
- "employment-type": "full_time",
- "employment-contract": "permanent",
- "probation-months": 6,
- "probation-end-date": "2026-11-30",
- "salary-amount-in-cents": "5000000",
- "salary-currency": "SEK",
- "salary-pay-period": "monthly",
- "notes": "Joining the Backend team.",
- "external-source": "teamtailor",
- "external-id": "tt-7421",
- "created-by-name": "Alex Recruiter",
- "created-by-email": "alex@example.com",
- "referred-by-email": "anna@example.com",
- "handled": false,
- "avatar": {
}, - "created-at": "2026-05-20T08:00:00Z",
- "updated-at": "2026-05-20T08:00:00Z"
}, - "relationships": {
}
}
}Files (contracts, IDs, signed offers, etc.) attached to a hire before activation. On activation, each HireDocument is copied to the resulting employee profile as a ProfileDocument.
Retrieve a paginated list of documents attached to a hire.
Documents are arbitrary files (contracts, IDs, signed offers, etc.) attached to a Hire by integrations before the hire is activated. When the hire is later activated in Aboard, each HireDocument becomes a ProfileDocument on the resulting employee profile.
| hire_id required | string Example: 42 ID of the parent hire |
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of documents to return per page |
| page[offset] | integer Default: 0 Number of documents to skip |
{- "data": [
- {
- "id": "1",
- "type": "hire-documents",
- "attributes": {
- "name": "Signed offer",
- "file-filename": "offer.pdf",
- "file-byte-size": 102400,
- "file-content-type": "application/pdf",
- "created-at": "2026-05-20T08:00:00Z",
- "updated-at": "2026-05-20T08:00:00Z"
}, - "relationships": {
- "profile-document-category": {
}
}
}
],
}Create a new document attached to a hire by uploading a file together with its metadata.
Binary uploads are the documented exception to the JSON:API-only write convention used elsewhere in this API. The request body is multipart/form-data with two parts:
data — a string containing the JSON:API document (attributes + relationships). Must declare type: "hire-documents" and include the profile-document-category relationship.file — the binary file part. Maximum size: 30 MB.If validation fails, the response is 422 and no record is created.
profile-document-categoryIntegrations resolve the category ID up front via GET /v1/profile-document-categories. The category carries over verbatim to the resulting ProfileDocument when the hire is activated.
A hire that has already been handled in Aboard (handled: true) cannot have new documents attached — POST returns 409 Conflict with code: "hire_already_handled".
POST /v1/hires/42/hire-documents
Authorization: Bearer YOUR_TOKEN
Content-Type: multipart/form-data; boundary=----X
------X
Content-Disposition: form-data; name="data"
Content-Type: application/json
{
"data": {
"type": "hire-documents",
"attributes": { "name": "Signed offer" },
"relationships": {
"profile-document-category": {
"data": { "type": "profile-document-categories", "id": "7" }
}
}
}
}
------X
Content-Disposition: form-data; name="file"; filename="offer.pdf"
Content-Type: application/pdf
<binary>
------X--
| hire_id required | string Example: 42 ID of the parent hire |
| data required | string JSON:API document, as a string. Must have |
| file required | string <binary> The file to attach. Maximum size 30 MB. |
{- "data": {
- "id": "1",
- "type": "hire-documents",
- "attributes": {
- "name": "Signed offer",
- "file-filename": "offer.pdf",
- "file-byte-size": 102400,
- "file-content-type": "application/pdf",
- "created-at": "2026-05-20T08:00:00Z",
- "updated-at": "2026-05-20T08:00:00Z"
}, - "relationships": {
- "profile-document-category": {
}
}
}
}Retrieve a single document attached to a hire, including a signed URL to download the file.
| hire_id required | string Example: 42 ID of the parent hire |
| id required | string Example: 1 Hire document ID |
{- "data": {
- "id": "1",
- "type": "hire-documents",
- "attributes": {
- "name": "Signed offer",
- "file-filename": "offer.pdf",
- "file-byte-size": 102400,
- "file-content-type": "application/pdf",
- "created-at": "2026-05-20T08:00:00Z",
- "updated-at": "2026-05-20T08:00:00Z"
}, - "relationships": {
- "profile-document-category": {
}
}
}
}Update a hire document's metadata.
name (attribute)profile-document-category (relationship)file-* attributes — replace the file by deleting the document and creating a new one.hire relationship — determined by the URL.created-at, updated-at — server-managed.A hire that has already been handled in Aboard (handled: true) cannot have its documents modified — PATCH returns 409 Conflict with code: "hire_already_handled".
| hire_id required | string Example: 42 ID of the parent hire |
| id required | string Example: 1 Hire document ID |
object |
{- "data": {
- "type": "hire-documents",
- "id": "1",
- "attributes": {
- "name": "Renamed document"
}, - "relationships": {
- "profile-document-category": {
- "data": {
- "type": "profile-document-categories",
- "id": "9"
}
}
}
}
}{- "data": {
- "id": "1",
- "type": "hire-documents",
- "attributes": {
- "name": "Signed offer",
- "file-filename": "offer.pdf",
- "file-byte-size": 102400,
- "file-content-type": "application/pdf",
- "created-at": "2026-05-20T08:00:00Z",
- "updated-at": "2026-05-20T08:00:00Z"
}, - "relationships": {
- "profile-document-category": {
}
}
}
}Delete a document attached to a hire.
A document attached to a hire that has already been handled (handled: true) cannot be deleted via the API — DELETE returns 409 Conflict with code: "hire_already_handled".
| hire_id required | string Example: 42 ID of the parent hire |
| id required | string Example: 1 Hire document ID |
{- "errors": [
- {
- "status": "401",
- "code": "unauthorized",
- "title": "Unauthorized",
- "detail": "You must provide a valid access token.",
- "source": {
- "pointer": "string"
}
}
]
}Read-only list of document categories used by both ProfileDocuments and HireDocuments. Integrations resolve a category ID here before posting a hire document.
Retrieve a paginated list of profile document categories for the company.
Profile document categories are the buckets used to classify ProfileDocuments (and HireDocuments before activation). Integrations resolve a category ID through this endpoint before posting a HireDocument.
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of categories to return per page |
| page[offset] | integer Default: 0 Number of categories to skip |
{- "data": [
- {
- "id": "1",
- "type": "profile-document-categories",
- "attributes": {
- "name": "Contracts",
- "visible-to-employee": true,
- "created-at": "2026-05-20T08:00:00Z",
- "updated-at": "2026-05-20T08:00:00Z"
}
}
],
}Retrieve a profile document category by ID.
| id required | string Example: 7 Profile document category ID |
{- "data": {
- "id": "1",
- "type": "profile-document-categories",
- "attributes": {
- "name": "Contracts",
- "visible-to-employee": true,
- "created-at": "2026-05-20T08:00:00Z",
- "updated-at": "2026-05-20T08:00:00Z"
}
}
}Retrieve a paginated list of company documents, sorted by name. Deleted documents are not included.
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of documents to return per page |
| page[offset] | integer Default: 0 Number of documents to skip |
{- "data": [
- {
- "id": "1",
- "type": "documents",
- "attributes": {
- "name": "Information security policy",
- "approval-type": "simple_read",
- "requires-acknowledgement": true,
- "approval-requested-at": "2026-09-01T08:00:00Z",
- "pending-employee-ids": [
- "12",
- "31"
], - "created-at": "2026-05-20T08:00:00Z",
- "updated-at": "2026-09-01T08:00:00Z"
}
}
],
}Retrieve a company document by ID.
| id required | string Example: 1 Document ID |
{- "data": {
- "id": "1",
- "type": "documents",
- "attributes": {
- "name": "Information security policy",
- "approval-type": "simple_read",
- "requires-acknowledgement": true,
- "approval-requested-at": "2026-09-01T08:00:00Z",
- "pending-employee-ids": [
- "12",
- "31"
], - "created-at": "2026-05-20T08:00:00Z",
- "updated-at": "2026-09-01T08:00:00Z"
}
}
}Read-only record of which employees have read or signed each company document. Useful for syncing policy acceptance to compliance tools.
Retrieve a paginated list of completed document acknowledgements. E-signature requests that have not been signed yet, and acknowledgements of deleted documents, are not included.
Use include=employee,document to fetch the related employee and document in the same request.
| filter[document_id] | string Example: filter[document_id]=1 Filter acknowledgements by document ID |
| filter[employee_id] | string Example: filter[employee_id]=1 Filter acknowledgements by employee ID |
| include | string Example: include=employee,document Comma-separated related resources to include |
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of acknowledgements to return per page |
| page[offset] | integer Default: 0 Number of acknowledgements to skip |
{- "data": [
- {
- "id": "1",
- "type": "document-acknowledgements",
- "attributes": {
- "acknowledged-at": "2026-09-02T10:15:00Z",
- "current": true,
- "created-at": "2026-09-02T10:15:00Z"
}, - "relationships": {
}
}
],
}Retrieve a document acknowledgement by ID.
| id required | string Example: 1 Document acknowledgement ID |
{- "data": {
- "id": "1",
- "type": "document-acknowledgements",
- "attributes": {
- "acknowledged-at": "2026-09-02T10:15:00Z",
- "current": true,
- "created-at": "2026-09-02T10:15:00Z"
}, - "relationships": {
}
}
}Retrieve a paginated list of onboarding templates for the company. Useful for resolving an onboarding template ID when creating hires through the API.
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "onboarding-templates",
- "attributes": {
- "title": "Engineering onboarding"
}
}, - {
- "id": "2",
- "type": "onboarding-templates",
- "attributes": {
- "title": "Sales onboarding"
}
}
],
}Retrieve onboarding template details by ID
| id required | string Example: 1 Onboarding template ID |
{- "data": {
- "id": "1",
- "type": "onboarding-templates",
- "attributes": {
- "title": "Engineering onboarding"
}
}
}Retrieve a paginated list of custom profile attributes defined for the company
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "profile-attributes",
- "attributes": {
- "name": "T-shirt Size",
- "multiple-choice": false
}, - "relationships": {
- "employees": {
- "links": {
}
}
}
}, - {
- "id": "2",
- "type": "profile-attributes",
- "attributes": {
- "name": "Skills",
- "multiple-choice": true
}, - "relationships": {
- "employees": {
- "links": {
}
}
}
}
],
}Retrieve profile attribute details by ID
| id required | string Example: 1 Profile attribute ID |
{- "data": {
- "id": "1",
- "type": "profile-attributes",
- "attributes": {
- "name": "T-shirt Size",
- "multiple-choice": false
}, - "relationships": {
- "employees": {
- "links": {
}
}
}
}
}Retrieve a paginated list of options for profile attributes
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "profile-attribute-options",
- "attributes": {
- "name": "Small"
}, - "relationships": {
- "profile-attribute": {
- "data": {
- "type": "profile-attributes",
- "id": "1"
}
}
}
}, - {
- "id": "2",
- "type": "profile-attribute-options",
- "attributes": {
- "name": "Medium"
}, - "relationships": {
- "profile-attribute": {
- "data": {
- "type": "profile-attributes",
- "id": "1"
}
}
}
}
],
}Retrieve profile attribute option details by ID
| id required | string Example: 1 Profile attribute option ID |
{- "data": {
- "id": "1",
- "type": "profile-attribute-options",
- "attributes": {
- "name": "Small"
}, - "relationships": {
- "profile-attribute": {
- "data": {
- "type": "profile-attributes",
- "id": "1"
}
}
}
}
}Retrieve a paginated list of profile attribute values assigned to employees
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "profile-attribute-values",
- "relationships": {
- "employee": {
- "links": {
}, - "data": {
- "type": "employees",
- "id": "1"
}
}, - "profile-attribute-option": {
- "data": {
- "type": "profile-attribute-options",
- "id": "2"
}
}
}
}
],
}Retrieve profile attribute value details by ID
| id required | string Example: 1 Profile attribute value ID |
{- "data": {
- "id": "1",
- "type": "profile-attribute-values",
- "relationships": {
- "employee": {
- "links": {
}, - "data": {
- "type": "employees",
- "id": "1"
}
}, - "profile-attribute-option": {
- "data": {
- "type": "profile-attribute-options",
- "id": "2"
}
}
}
}
}Retrieve a paginated list of time tracking entries with optional filtering
| filter[status] | string Enum: "active" "archived" Example: filter[status]=active Filter entries by status |
| filter[time_tracking_project_id] | string Example: filter[time_tracking_project_id]=1 Filter entries by project ID |
| filter[date] | string <date> Example: filter[date]=2025-01-15 Filter entries by exact date (YYYY-MM-DD format) |
| filter[from_date] | string <date> Example: filter[from_date]=2025-01-01 Filter entries starting on or after this date (YYYY-MM-DD format) |
| filter[to_date] | string <date> Example: filter[to_date]=2025-01-31 Filter entries ending on or before this date (YYYY-MM-DD format) |
| filter[from_time] | string <date-time> Example: filter[from_time]=2025-01-15T09:00:00Z Filter entries starting on or after this timestamp (ISO 8601 format) |
| filter[to_time] | string <date-time> Example: filter[to_time]=2025-01-15T18:00:00Z Filter entries ending on or before this timestamp (ISO 8601 format) |
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of entries to return per page |
| page[offset] | integer Default: 0 Number of entries to skip |
{- "data": [ ],
}Retrieve time tracking entry details by ID
| id required | string Example: 1 Time tracking entry ID |
{- "data": {
- "id": "1",
- "type": "time-tracking-entries",
- "attributes": {
- "duration-in-seconds": 3600,
- "start-time": "2025-01-15T09:00:00.000Z",
- "end-time": "2025-01-15T10:00:00.000Z",
- "status": "active"
}, - "relationships": {
- "employee": {
- "links": {
}, - "data": {
- "type": "employees",
- "id": "1"
}
}, - "time-tracking-project": {
- "data": {
- "type": "time-tracking-projects",
- "id": "1"
}
}
}
}
}Retrieve a paginated list of all time tracking projects
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of projects to return per page |
| page[offset] | integer Default: 0 Number of projects to skip |
{- "data": [
- {
- "id": "1",
- "type": "time-tracking-projects",
- "attributes": {
- "name": "Work",
- "status": "active"
}, - "relationships": {
- "employees": {
- "links": {
}
}
}
}, - {
- "id": "2",
- "type": "time-tracking-projects",
- "attributes": {
- "name": "Break",
- "status": "active"
}, - "relationships": {
- "employees": {
- "links": {
}
}
}
}
],
}Retrieve detailed information about a specific time tracking project by its ID
| id required | string Example: 1 Unique identifier for the time tracking project |
{- "data": {
- "id": "1",
- "type": "time-tracking-projects",
- "attributes": {
- "name": "Work",
- "status": "active"
}, - "relationships": {
- "employees": {
- "links": {
}
}
}
}
}Retrieve a paginated list of time-off requests with optional filtering
| filter[status] | string Enum: "pending" "approved" "declined" "cancelled" Example: filter[status]=approved Filter requests by status |
| filter[time_off_policy_id] | string Example: filter[time_off_policy_id]=1 Filter requests by policy ID |
| filter[time_off_policy_type_id] | string Example: filter[time_off_policy_type_id]=1 Filter requests by policy type ID |
| filter[date] | string <date> Example: filter[date]=2025-07-15 Filter requests that contain a specific date (YYYY-MM-DD format). Returns requests where the date falls between start_date and end_date. |
| filter[from_date] | string <date> Example: filter[from_date]=2025-07-01 Filter requests starting on or after this date (YYYY-MM-DD format) |
| filter[to_date] | string <date> Example: filter[to_date]=2025-07-31 Filter requests ending on or before this date (YYYY-MM-DD format) |
| filter[requested_at] | string <date> Example: filter[requested_at]=2025-06-01 Filter requests created on a specific date (YYYY-MM-DD format) |
| filter[requested_at_from] | string <date> Example: filter[requested_at_from]=2025-06-01 Filter requests created on or after this date (YYYY-MM-DD format) |
| filter[requested_at_to] | string <date> Example: filter[requested_at_to]=2025-06-30 Filter requests created on or before this date (YYYY-MM-DD format) |
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of requests to return per page |
| page[offset] | integer Default: 0 Number of requests to skip |
{- "data": [
- {
- "id": "1",
- "type": "time-off-requests",
- "attributes": {
- "start-date": "2025-07-07",
- "end-date": "2025-08-06",
- "status": "approved",
- "number-of-days": 23,
- "requested-at": "2025-09-09T12:07:02.440Z",
- "duration-in-minutes": 480,
- "duration-type": "full-day",
- "comment": "Parental leave for Alva"
}, - "relationships": {
- "employee": {
- "links": {
}
}, - "time-off-policy": {
- "links": {
}
}, - "time-off-policy-type": {
}
}
}
],
}Retrieve detailed information about a specific time-off request by its ID
| id required | string Example: 1 Unique identifier for the time-off request |
{- "data": {
- "id": "1",
- "type": "time-off-requests",
- "attributes": {
- "start-date": "2025-07-07",
- "end-date": "2025-08-06",
- "status": "approved",
- "number-of-days": 23,
- "requested-at": "2025-09-09T12:07:02.440Z",
- "duration-in-minutes": 240,
- "duration-type": "half-day",
- "comment": null
}, - "relationships": {
- "employee": {
- "links": {
}
}, - "time-off-policy": {
- "links": {
}
}, - "time-off-policy-type": {
}
}
}
}Retrieve a paginated list of time-off policy types
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of policy types to return per page |
| page[offset] | integer Default: 0 Number of policy types to skip |
{- "data": [
- {
- "id": "1",
- "type": "time-off-policy-types",
- "attributes": {
- "name": "Vacation"
}, - "relationships": {
- "employees": {
- "links": {
}
}
}
}, - {
- "id": "2",
- "type": "time-off-policy-types",
- "attributes": {
- "name": "Sick"
}, - "relationships": {
- "employees": {
- "links": {
}
}
}
}
],
}Retrieve detailed information about a specific time-off policy type by its ID
| id required | string Example: 1 Unique identifier for the time-off policy type |
{- "data": {
- "id": "1",
- "type": "time-off-policy-types",
- "attributes": {
- "name": "Vacation"
}, - "relationships": {
- "employees": {
- "links": {
}
}
}
}
}Retrieve a paginated list of time-off policies
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of policies to return per page |
| page[offset] | integer Default: 0 Number of policies to skip |
{- "data": [
- {
- "id": "1",
- "type": "time-off-policies",
- "attributes": {
- "name": "Sweden"
}, - "relationships": {
- "time-off-policy-type": {
}, - "employees": {
- "links": {
}
}
}
}
],
}Retrieve detailed information about a specific time-off policy by its ID
| id required | string Example: 1 Unique identifier for the time-off policy |
{- "data": {
- "id": "1",
- "type": "time-off-policies",
- "attributes": {
- "name": "Sweden"
}, - "relationships": {
- "time-off-policy-type": {
}, - "employees": {
- "links": {
}
}
}
}
}Read-only list of public holiday calendars. Integrations resolve a calendar ID here before assigning one to a hire.
Retrieve a paginated list of public holiday calendars for the company. Useful for resolving a holiday calendar ID when creating hires through the API.
| page[limit] | integer <= 100 Default: 20 Example: page[limit]=20 Number of records per page |
| page[offset] | integer Default: 0 Number of records to skip |
{- "data": [
- {
- "id": "1",
- "type": "holiday-calendars",
- "attributes": {
- "name": "Sweden",
- "country-code": "SE",
- "location": null,
- "display-name": "Sweden"
}
}, - {
- "id": "2",
- "type": "holiday-calendars",
- "attributes": {
- "name": null,
- "country-code": "US",
- "location": "California",
- "display-name": "United States (California)"
}
}
],
}Retrieve holiday calendar details by ID
| id required | string Example: 1 Holiday calendar ID |
{- "data": {
- "id": "1",
- "type": "holiday-calendars",
- "attributes": {
- "name": "Sweden",
- "country-code": "SE",
- "location": null,
- "display-name": "Sweden"
}
}
}Aboard's Zapier integration lets profile events trigger Zaps. Connect Aboard from within a Zap — a company superadmin authorizes the connection — and pick one of two triggers. Everything else is handled by the Zapier platform; there is nothing to call or configure on the Aboard API.
| Trigger | Fires when |
|---|---|
| New Profile | An employee profile is created |
| Updated Profile | A profile or its home address is created or updated |
Each event is delivered to the Zap as a JSON payload. Delivery is
at-least-once; Zapier deduplicates by the payload's top-level id. The
exact payload shapes are documented below so you know precisely what
data reaches Zapier.
Sensitive data never leaves Aboard: payloads exclude national IDs, bank details, dates of birth, and emergency contacts, and changes to those fields never fire a trigger.
POSTed to a subscribed Zap's catch URL when an employee profile is
created. Delivery is at-least-once — Zapier deduplicates by the
top-level id. Failed deliveries are retried on server errors,
rate limits, and timeouts.
| id | string <uuid> Delivery idempotency key — stable across retries of the same delivery, distinct per event and destination. Zapier deduplicates incoming hook payloads by this field; it is not meant to be mapped into Zap steps. |
| type | string Value: "new_profile" Identifies the trigger that fired. |
| occurredAt | string <date-time> When the profile was created (ISO 8601, always carries a zone). |
object Snapshot of the new employee profile — the non-sensitive fields of the new-employee form. |
{- "id": "00000000-0000-0000-0000-000000000000",
- "type": "new_profile",
- "occurredAt": "2026-01-01T00:00:00Z",
- "profile": {
- "firstName": "Michael",
- "lastName": "Scott",
- "workEmail": "michael.scott@example.com",
- "personalEmail": "michael.scott@example.net",
- "position": {
- "jobTitle": "Regional Manager",
- "startDate": "2026-01-15",
- "workerType": "employee",
- "employmentForm": "Permanent",
- "workplace": "Scranton",
- "manager": "Jan Levinson",
- "managerEmail": "jan.levinson@example.com",
- "department": "Management"
}
}
}POSTed to a subscribed Zap's catch URL when an employee profile is
updated or its home address is created/updated. Delivery is
at-least-once — Zapier deduplicates by the top-level id. Failed
deliveries are retried on server errors, rate limits, and timeouts.
| id | string <uuid> Delivery idempotency key — stable across retries of the same delivery, distinct per event and destination. Zapier deduplicates incoming hook payloads by this field; it is not meant to be mapped into Zap steps. |
| type | string Value: "updated_profile" Identifies the trigger that fired. |
| occurredAt | string <date-time> When the change happened (ISO 8601, always carries a zone). |
object Snapshot of the employee profile's non-sensitive contact fields. Phone numbers and ZIP codes are strings. Sensitive fields (national ID, bank details, date of birth, emergency contacts) are never included, and changes to them never fire this trigger. |
{- "id": "00000000-0000-0000-0000-000000000000",
- "type": "updated_profile",
- "occurredAt": "2026-01-01T00:00:00Z",
- "profile": {
- "firstName": "Michael",
- "lastName": "Scott",
- "workEmail": "michael.scott@example.com",
- "personalEmail": "michael.scott@example.net",
- "workPhone": "+15555700100",
- "personalPhone": "+15555700101",
- "address": {
- "streetAddress": "1725 Slough Avenue",
- "coAddress": "Suite 200",
- "city": "Scranton",
- "zipCode": "18505",
- "countryCode": "US"
}
}
}