> ## Documentation Index
> Fetch the complete documentation index at: https://docs.filexpress.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Attendance results

> Daily compliance (late arrivals, absences) and classified hours per employee

| Permission | Endpoints |
| - | - |
| `hr.attendance_results` | `GET /hr/attendance-results`, `GET /hr/attendance-results/summary`, `GET /hr/overtime-approvals` |
| `hr.overtime.approve` | `POST /hr/overtime-approvals/{id}/decide`, `POST /hr/overtime-approvals/bulk` |

FileXpress calculates one result per employee per day from attendance, the assigned schedule, holidays, and labor rules. See [Schedule compliance](https://docs.filexpress.app/en/docs/rrhh/cumplimiento.md) and [how hours are classified](https://docs.filexpress.app/en/docs/rrhh/reglas-laborales.md#how-hours-are-classified).

Results are recalculated automatically when you record attendance or when rules, schedules, assignments, or holidays change. Results are read-only; the only write operation is [overtime approval](#overtime-approval).

## Daily results

```http theme={null}
GET /hr/attendance-results?start_date=2026-10-01&end_date=2026-10-15
```

| Parameter | Required | Description |
| - | - | - |
| `start_date` | Yes | Start date. |
| `end_date` | Yes | End date (maximum range of 93 days). |
| `employee_id` | No | Filters by employee. |
| `status` | No | Filters by status (see table). |

```json theme={null}
{
  "status": true,
  "data": [
    {
      "id": "uuid",
      "business_id": "uuid",
      "employee_id": "uuid",
      "employee_name": "María López",
      "work_date": "2026-10-01",
      "attendance_id": "uuid",
      "work_schedule_id": "uuid",
      "labor_rule_set_id": "uuid",
      "day_type": "regular",
      "shift_kind": "day",
      "status": "late",
      "scheduled_minutes": 480,
      "worked_minutes": 590,
      "late_minutes": 10,
      "early_leave_minutes": 0,
      "ordinary_day_minutes": 480,
      "ordinary_night_minutes": 0,
      "overtime_day_minutes": 110,
      "overtime_night_minutes": 0,
      "breakdown": [
        { "category": "ordinary_day_regular", "minutes": 480, "multiplier": 1, "amount": 0 },
        { "category": "overtime_day_regular", "minutes": 110, "multiplier": 2, "amount": 15.58 }
      ],
      "warnings": [],
      "overtime_approval": null,
      "overtime_pending_minutes": 0,
      "overtime_rejected_minutes": 0,
      "is_locked": false,
      "calculated_at": "2026-10-02 06:00:12"
    }
  ]
}
```

| Field | Description |
| - | - |
| `work_date` | Start date of the workday (a night shift belongs to the day on which it starts). |
| `day_type` | `regular`, `rest_day`, or `holiday`. |
| `shift_kind` | `day`, `night`, or `mixed`. Can be `null` on days without work. |
| `scheduled_minutes`, `worked_minutes` | Scheduled and worked minutes. |
| `late_minutes`, `early_leave_minutes` | Minutes outside the tolerance. |
| `ordinary_*_minutes`, `overtime_*_minutes` | Minutes by class and time band (all day types). Overtime is the **calculated** amount, whether or not it is approved. |
| `breakdown` | **Payable** breakdown by category with multiplier and suggested amount according to the employee's pay type. With overtime approval, the `overtime_*` categories include only the approved minutes (proportional amounts). |
| `overtime_approval` | `{id, status, requested_minutes, approved_minutes, changed_after_decision}` if the day requires overtime approval; `null` if not. |
| `overtime_pending_minutes`, `overtime_rejected_minutes` | Overtime minutes pending a decision and rejected (outside the `breakdown`). `0` without approval. |
| `warnings` | Warning codes (see table). |
| `is_locked` | `true` if the day is in a processed or paid payroll; it is no longer recalculated. |
| `labor_rule_set_id` | Rules used; `null` if the default values were used. |

### Statuses

| `status` | Meaning |
| - | - |
| `compliant` | Worked with no late arrival or early leave. |
| `late` | Late arrival. |
| `early_leave` | Early leave. |
| `late_and_early_leave` | Both. |
| `absent` | Working day with a schedule, no punches, and no leave or holiday. |
| `incomplete` | Check-in without check-out or vice versa. |
| `on_leave` | Approved leave. |
| `holiday` | Holiday with no work. |
| `rest_day` | Rest day with no work. |
| `worked_on_rest_day` | Worked on a rest day. |
| `worked_on_holiday` | Worked on a holiday. |
| `no_schedule` | Worked without an assigned schedule (classified all the same). |

Days with no punches and no schedule do not generate a result, except for holidays.

### Breakdown categories

`category` has the form `{type}_{band}_{day}`:

| Part | Values |
| - | - |
| `type` | `ordinary`, `overtime` |
| `band` | `day` (daytime), `night` (nighttime) |
| `day` | `regular`, `rest_day`, `holiday` |

For example, `overtime_night_holiday` = night overtime on a holiday. `multiplier` is the factor over the ordinary daytime hour; `amount` is the suggested amount for those hours: for fixed salary, ordinary daytime hours are worth `0` (they are already in the salary) and, for the rest of the ordinary hours, only the additional surcharge is counted.

### Warnings

| Code | Meaning |
| - | - |
| `missing_check_out` | Check-out is missing. |
| `punches_outside_schedule` | Punches outside any shift. |
| `schedule_exceeds_legal_max` | The schedule exceeds the legal maximum workday. |
| `overtime_daily_cap_exceeded`, `overtime_weekly_cap_exceeded` | The overtime cap was exceeded. |
| `total_daily_cap_exceeded` | Ordinary + overtime exceed the total daily cap. |
| `overtime_requires_approval` | There is overtime and the rules require approval. |
| `overtime_pending_approval` | The day's overtime is pending approval (it is not included in the amount). |
| `overtime_changed_after_decision` | Overtime changed in a recalculation after it was decided; it went back to pending. |
| `below_min_wage` | The hourly rate is below the configured minimum. |

## Summary by employee

```http theme={null}
GET /hr/attendance-results/summary?start_date=2026-10-01&end_date=2026-10-31
```

| Parameter | Required | Description |
| - | - | - |
| `start_date` | Yes | Start date. |
| `end_date` | Yes | End date (maximum range of 370 days). |

```json theme={null}
{
  "status": true,
  "data": [
    {
      "employee_id": "uuid",
      "employee_name": "María López",
      "pay_type": "salaried",
      "days_worked": 21,
      "late_days": 3,
      "late_minutes": 42,
      "early_leave_minutes": 15,
      "absent_days": 1,
      "minutes": {
        "ordinary_day": 9600,
        "ordinary_night": 0,
        "overtime_day": 330,
        "overtime_night": 60,
        "rest_day": 0,
        "holiday": 0
      },
      "suggested_amount": 62.40,
      "overtime_pending_minutes": 0,
      "overtime_rejected_minutes": 0
    }
  ]
}
```

| Field | Description |
| - | - |
| `days_worked` | Days with worked minutes. |
| `late_days` | Days with a late arrival. |
| `minutes.ordinary_*`, `minutes.overtime_*` | Minutes by class and time band, across all day types. |
| `minutes.rest_day`, `minutes.holiday` | Minutes worked on rest days and holidays (already included in the previous four). |
| `suggested_amount` | Sum of the breakdown amounts for the range (with approval, only approved overtime). |
| `overtime_pending_minutes`, `overtime_rejected_minutes` | Overtime minutes in the range pending approval and rejected. |

## Overtime approval

If the current [labor rules](https://docs.filexpress.app/en/docs/api/rrhh/reglas-laborales.md) have `overtime.requires_approval: true`, each day with overtime generates an approval. While it is `pending`, the overtime is not included in the payable `breakdown`, in `suggested_amount`, or in payroll. See [Overtime approval](https://docs.filexpress.app/en/docs/rrhh/cumplimiento.md#overtime-approval) in the manual.

### Approval object

```json theme={null}
{
  "id": "uuid",
  "business_id": "uuid",
  "employee_id": "uuid",
  "employee_name": "Ana López",
  "work_date": "2026-10-06",
  "attendance_day_result_id": "uuid",
  "requested_minutes": 120,
  "approved_minutes": 60,
  "rejected_minutes": 60,
  "status": "partially_approved",
  "changed_after_decision": false,
  "decided_by": null,
  "decided_by_name": null,
  "decided_at": "2026-10-08 10:00:00",
  "comment": "Solo se autorizó una hora",
  "is_locked": false,
  "can_decide": true
}
```

| Field | Description |
| - | - |
| `requested_minutes` | Calculated overtime for the day (daytime + nighttime). |
| `approved_minutes` | Approved minutes; `null` while `pending`. |
| `rejected_minutes` | `requested_minutes - approved_minutes` if decided; `0` if pending. |
| `status` | `pending`, `approved`, `partially_approved`, or `rejected`. |
| `changed_after_decision` | `true` if it had been decided and a recalculation changed the minutes: it went back to `pending`. |
| `decided_by`, `decided_by_name` | FileXpress user who decided; `null` for decisions made through the API. |
| `is_locked` | `true` if the day is in a processed or paid payroll: it can no longer be decided. |
| `can_decide` | Always `true` in the external API. |

If the day no longer has overtime or the rules no longer require approval, the approval is deleted.

### List approvals

```http theme={null}
GET /hr/overtime-approvals?start_date=2026-10-01&end_date=2026-10-15&status=pending
```

**Required permission:** `hr.attendance_results`

| Parameter | Required | Description |
| - | - | - |
| `start_date`, `end_date` | Yes | Range (maximum 370 days). |
| `employee_id` | No | Filters by employee. |
| `status` | No | `pending`, `approved`, `partially_approved`, or `rejected`. |

Returns in `data` the list of [approvals](#approval-object) ordered by `work_date`.

### Decide a day

```http theme={null}
POST /hr/overtime-approvals/{id}/decide
```

**Required permission:** `hr.overtime.approve`

```json theme={null}
{ "status": "approved", "approved_minutes": 60, "comment": "Solo se autorizó una hora" }
```

| Field | Required | Description |
| - | - | - |
| `status` | Yes | `approved` or `rejected`. |
| `approved_minutes` | No | Integer greater than or equal to 0. With `approved` and without this field, everything is approved. Less than `requested_minutes` gives `partially_approved`; `0` gives `rejected`. |
| `comment` | No | Max. 1000 characters. |

In a partial approval, the approved minutes are taken in chronological order (daytime overtime first, then nighttime). The day is recalculated when you decide.

**`200` response**: the approval and the already recalculated [day result](#daily-results) (`result`, `null` if it doesn't exist).

```json theme={null}
{
  "status": true,
  "data": {
    "approval": { "id": "uuid", "status": "partially_approved", "requested_minutes": 120, "approved_minutes": 60, "rejected_minutes": 60 },
    "result": { "id": "uuid", "work_date": "2026-10-06", "overtime_pending_minutes": 0, "overtime_rejected_minutes": 60 }
  }
}
```

### Decide in bulk

```http theme={null}
POST /hr/overtime-approvals/bulk
```

**Required permission:** `hr.overtime.approve`

```json theme={null}
{ "ids": ["uuid-1", "uuid-2"], "status": "approved", "comment": "Cierre de quincena" }
```

| Field | Required | Description |
| - | - | - |
| `ids` | Yes | 1 to 500 approval IDs. |
| `status` | Yes | `approved` (approves the full amount for each day) or `rejected`. |
| `comment` | No | Max. 1000 characters. |

Each ID is processed separately: those that fail do not stop the others.

```json theme={null}
{
  "status": true,
  "data": {
    "updated": 1,
    "errors": [ { "id": "uuid-2", "message": "El día pertenece a una planilla procesada." } ]
  }
}
```

### Errors

| Code | Cause |
| - | - |
| `403` | The integration does not have the required permission. |
| `404` | `Overtime approval not found.` (nonexistent or from another business). |
| `422` | `Validation errors` (invalid fields), `El día pertenece a una planilla procesada.` or `Los minutos aprobados no pueden superar los solicitados.` |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.