# Absences

The v2 absence APIs let you create, look up, and delete absences for an employee at a Unit. This page is a complement to the OpenAPI reference — it covers the cross-cutting concepts (workflow, permissions, behavior-changing query parameters, agreement-driven defaults, validation errors, payroll-lock rules) that don't naturally fit on individual operations in the spec.

The actual paths and field reference live under the **Absences**, **Absence Schedules**, and **Absence Types** tags in the [API reference](/api/v2/specs/quinyx-public-api-v2).

## Permissions

To call any absence endpoint, your integration credentials need the **Absence** scope, with the relevant `Read` / `Create` / `Update` / `Delete` permission bits. Configure these in **Account Settings → Integration credentials**.

The `GET /v2/employees/{employeeId}` endpoint, used in the absence creation flow, requires the **People** scope (`Read`). The `Create`, `Update`, and `Delete` bits on the People scope have no effect today — there are no corresponding REST operations.

## Workflow

A typical absence creation looks like this:

1. **Resolve the employee's internal ID** via the [Mapping API](/api/v2/mapping) (`EMPLOYEE_ID`) if you only have an external ID or badge number.
2. **List valid absence types for this employee in this period** via `GET /v2/absence-types/groups/{groupId}/employees/{employeeId}` with `start` and `end`. The result is filtered by what's allowed under the employee's agreement template, so call this rather than maintaining a static list.
3. *(Optional)* **Look up absence schedules** via `GET /v2/absence-schedule/groups/{groupId}` if you need a non-default schedule.
4. **Create the absence** with `POST /v2/schedule/groups/{groupId}/absences` (full-time) or `POST /v2/schedule/groups/{groupId}/absences/part-time`.
5. *(Later, if needed)* **Delete the absence** with `DELETE /v2/schedule/groups/{groupId}/absences/{absenceId}`.


You can only create an absence at the **Unit** level. If you submit a District or Domain ID as `groupId` you'll get `GROUP_NOT_RESTAURANT_OR_SECTION`. If you submit a Section ID, the Section's parent Unit ID is applied automatically.

## Query parameters that change behavior

These apply to both `POST /absences` (full-time) and `POST /absences/part-time`.

### `overlapAbsences`

Controls what happens when an absence already exists in the requested period. The behavior depends on the **Allow overlapping absences** setting at the Unit:

- `true` — overlap any existing absence. If the Unit setting is `false`, this throws a warning rather than overlapping silently.
- `false` *(default if omitted)* — replace any existing absence in the period.


Quinyx supports a maximum of **two overlapping absences** in any period; beyond that you get `LEAVEAPP_MAX_TWO_OVERLAPPING_ABSENCE_IN_PERIOD`.

### `ignoreOverridableValidations`

Controls whether overridable validation warnings block the create or are bypassed:

- `true` — create the absence anyway when only overridable warnings are raised.
- `false` *(default if omitted)* — overridable warnings block the create like any other failure.


Non-overridable warnings (the vast majority — see the table below) are never bypassed; they will keep being returned until the underlying issue is resolved.

### Part-time only

Part-time absences take three additional parameters that don't apply to full-time:

- `absenceRate` — fraction of the shift taken as absence. Decimal between `0.0001` and `99.9999` with up to four decimals.
- `absenceRateDirection` — where the absence applies relative to the shift: `FROM_START`, `FROM_END`, or `WHOLE_SHIFT`.
- `splitType` — `Day` or `Shift`. Determines how `absenceRate` is computed across the period.


`splitType=Day` combined with `absenceRateDirection=WHOLE_SHIFT` is incompatible and will be rejected.

## Field defaults driven by agreement configuration

Several fields on the create request default based on the employee's agreement settings:

| Field | Default behavior when omitted |
|  --- | --- |
| `employeeAttested` | If the agreement's *auto attest for absences* is `true`, defaults to `true`; otherwise defaults to `false`. |
| `managerAttested` | Same rule as `employeeAttested`. |
| `absenceScheduleId` | If the chosen `absenceTypeId` has a default absence schedule configured, that schedule is applied. |
| `shiftsInThisPeriod` | Defaults to the *Absence type affects schedule* setting (unassign / delete) on the chosen absence type. |


## DELETE Absence

`DELETE /v2/schedule/groups/{groupId}/absences/{absenceId}` removes an absence. One query parameter changes behavior:

- `reassignBackShifts` — only relevant when the absence contains absence shifts (i.e. shifts that were converted/unassigned/reassigned at create time). When `true`, the original shifts are reassigned back to the employee on delete. When `false` (or when the absence has no absence shifts), nothing is reassigned. If the absence contains absence shifts and `reassignBackShifts` is not set at all, you'll get `DELETE_LEAVE_SHIFT_EXISTS`.


## Payroll lock

Absences that overlap a salary period that has been transferred to payroll are protected:

- Creation is blocked with `SHIFT_ALREADY_TRANSFERRED_TO_PAYROLL`, `SALARY_PERIOD_LOCKED`, `LEAVE_SHIFT_ALREADY_TRANSFERRED_TO_PAYROLL`, or `PUNCH_ALREADY_TRANSFERED_TO_PAYROL` depending on what specifically blocked it.
- Deletion follows the same rules — you can't delete an absence whose period is already locked.


There is no override; the salary period must be unlocked before the operation will succeed.

## Validation error catalog

Validation failures return an `err.msg` value identifying the cause. The full set returned by `POST /v2/schedule/groups/{groupId}/absences` and `POST /v2/schedule/groups/{groupId}/absences/part-time`:

| `msg` | Meaning | Overridable |
|  --- | --- | --- |
| `INVALID_ABSENCE_TYPE_OR_ABSENCE_SCHEDULE` | When fetching shifts: not all leave reasons or absence schedules belong to the same customer. | No |
| `INVALID_LEAVE_REASON` | The `absenceTypeId` is not valid for this domain. | No |
| `INVALID_ABSENCE_SCHEDULE` | The `absenceScheduleId` is not valid for this domain. | No |
| `INACTIVE_EMPLOYEE` | The employee's employment has ended; absences can't be created on terminated employees. | No |
| `INVALID_EMPLOYEE` | The employee has no role; absences require a role. | No |
| `MISSING_AGREEMENT` | The employee has no valid agreement. | No |
| `START_MUST_BE_BEFORE_END` | `begin` is not strictly before `end`. | No |
| `GROUP_NOT_RESTAURANT_OR_SECTION` | `groupId` is a District or Domain — absences can only be created at the Unit level. | No |
| `ABSENCE_LONGER_THAN_24_MONTH` | The requested period exceeds 24 months. | No |
| `LEAVEAPP_OVERLAPPING_ABSENCE_IN_PERIOD` | Overlap rejected (see `overlapAbsences`). | No |
| `LEAVEAPP_MAX_TWO_OVERLAPPING_ABSENCE_IN_PERIOD` | Quinyx supports at most two overlapping absences. | No |
| `LEAVEAPP_PRECEEDING_LEAVE_WITHOUT_WORK` | No work time has been registered after a preceding absence — back-to-back absences without intervening work are not allowed. | No |
| `LEAVE_PUNCH_EXISTS` | Unapproved punches in the leave period will be partially or fully deleted by this operation. | **Yes** |
| `PUNCH_APPROVED_AND_NOT_TRANSFERRED_TO_PAYROLL` | Approved (but not yet transferred) punches exist during the leave period. | No |
| `PUNCH_ALREADY_TRANSFERED_TO_PAYROL` | The period contains punches already transferred to payroll. | No |
| `SHIFT_ALREADY_TRANSFERRED_TO_PAYROLL` | A shift in the period has already been transferred to payroll and can't be changed. | No |
| `LEAVE_SHIFT_ALREADY_TRANSFERRED_TO_PAYROLL` | An absence shift in the period has already been transferred to payroll. | No |
| `SALARY_PERIOD_LOCKED` | The salary period covering the request is locked. | No |
| `EGENMELDING_FAIL_EGENMELDING_DAYS_USED_UP` | All self-certified sick leave days have been used. | No |
| `EGENMELDING_FAIL_AGP_USED_UP` | Self-certified sick days can only be used within the employer period. | No |
| `LEAVE_MAX_OCCASIONS` | Max occasions per absence type reached. | No |
| `LEAVE_MAX_DAYS_IN_PERIOD` | Max leave days for the period reached. | No |
| `LEAVE_MAX_CONSECUTIVE_DAYS` | Max consecutive days reached. | No |
| `LEAVE_MIN_DAYS_BETWEEN` | Less than the configured minimum gap between absence occasions. | No |
| `NO_ROLE_ON_ABSENCE_SCHEDULE_SHIFT` | The absence schedule has a shift on a group where the employee has no role. | No |
| `LEAVEAPP_NOT_ATTESTABLE_BY_EMPLOYEE` | The absence is not attestable by the employee under the current agreement. | No |
| `LEAVEAPP_NOT_ATTESTABLE_BY_MANAGER` | The absence is not attestable by the manager under the current agreement. | No |
| `ACCRUAL_BALANCE_EXCEEDED` | The employee's Time Tracker balance is below what the absence requires. Subject to configuration; the response's `Text` field names the relevant TimeTracker. | No |


`DELETE` adds three of its own:

| `msg` | Meaning |
|  --- | --- |
| `DELETE_ABSENCE_NOT_EXISTS` | The `absenceId` does not match an existing absence. |
| `ABSENCE_NOT_BELONG_TO_CUSTOMER` | The `absenceId` does not match an existing absence in this customer's account. |
| `DELETE_LEAVE_SHIFT_EXISTS` | The absence contains absence shifts but `reassignBackShifts` was not set on the request. |


## Validation errors on the look-up endpoints

`GET /v2/absence-schedule/groups/{groupId}` and `GET /v2/absence-types/groups/{groupId}/employees/{employeeId}` return `error.absenceReasonType.*` and `error.accessrights.*` style identifiers rather than the `LEAVE_*` / `LEAVEAPP_*` family above. Common ones:

- `error.accessrights.groupId.notDomainGroupId` — `groupId` is not a valid domain group.
- `error.absenceReasonType.startAfterEnd` — `start` is after `end`.
- `error.absenceReasonType.employeeId.notFound` — employee ID could not be found.
- `error.absenceReasonType.employeeId.notEmployed` — employee is not in **People → Status → Employed** at any time in the requested range.
- `error.absenceReasonType.employeeId.doesNotBelongToCustomer` — employee is not in the same customer/domain as the request.


## Next steps

- Resolve external IDs first via the [Mapping API](/api/v2/mapping).
- See the **Absences**, **Absence Schedules**, and **Absence Types** tags in the [API reference](/api/v2/specs/quinyx-public-api-v2) for full request/response shapes.