> ## 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.

# Labor rules

> Query and configure workdays, surcharges and tolerances, and copy the country templates

| Operation | Permission |
| - | - |
| Query rules, templates and current rules | `hr.labor_rules` |
| Create, copy from template and edit | `hr.labor_rules.write` |

Labor rules define the day/night bands, maximum workdays, surcharges and tolerances FileXpress uses to classify attendance. See [Labor rules](https://docs.filexpress.app/en/docs/rrhh/reglas-laborales.md) in the manual.

> [!WARNING]
>
> Country templates are a starting point. The company must validate them with its labor advisor before using them to pay.

## List company rules

```http theme={null}
GET /hr/labor-rules
```

**Required permission:** `hr.labor_rules`

Returns all of the company's effective periods (most recent first), which one applies today and the effective rules.

```json theme={null}
{
  "status": true,
  "data": {
    "rule_sets": [
      {
        "id": "uuid",
        "business_id": "uuid",
        "country_code": "SV",
        "name": "El Salvador – Código de Trabajo",
        "source_template_id": "uuid",
        "effective_from": "2026-01-01",
        "effective_to": null,
        "schema_version": 1,
        "params": { "timezone": "America/El_Salvador", "...": "ver Parámetros" },
        "is_active": true,
        "is_template": false
      }
    ],
    "current_id": "uuid",
    "effective": { "id": "uuid", "name": "El Salvador – Código de Trabajo", "is_template": false, "...": "..." }
  }
}
```

| Field | Description |
| - | - |
| `current_id` | The company's own effective period that applies today. `null` if the company has no current rules of its own. |
| `effective` | The rules that apply today: the company's own period or, if there is none, the country template (`is_template: true`). `null` if there is no template either. |

## List country templates

```http theme={null}
GET /hr/labor-rules/templates?country_code=CO
```

**Required permission:** `hr.labor_rules`

| Parameter | Required | Description |
| - | - | - |
| `country_code` | No | 2-letter ISO code (`SV`, `GT`, `CO`). Without the parameter it returns all of them. |

Returns a list of objects with the same format as `rule_sets` (with `business_id: null` and `is_template: true`). Colombia has several templates with successive effective periods.

## Query the rules in effect on a date

```http theme={null}
GET /hr/labor-rules/effective?date=2026-10-01
```

**Required permission:** `hr.labor_rules`

| Parameter | Required | Description |
| - | - | - |
| `date` | No | Date (`YYYY-MM-DD`). Defaults to today in the company's time zone. |

```json theme={null}
{
  "status": true,
  "data": {
    "date": "2026-10-01",
    "rule_set": { "id": "uuid", "name": "El Salvador – Código de Trabajo", "...": "..." },
    "source": "business",
    "params": { "timezone": "America/El_Salvador", "...": "ver Parámetros" }
  }
}
```

`source` indicates where the parameters come from: `business` (the company's own rules), `template` (the country template) or `default` (system defaults; `rule_set` is `null`).

## Copy from template

```http theme={null}
POST /hr/labor-rules/from-template
```

**Required permission:** `hr.labor_rules.write`

```json theme={null}
{ "template_id": "uuid", "effective_from": "2026-11-01" }
```

| Field | Required | Description |
| - | - | - |
| `template_id` | Yes | ID of a template (`GET /hr/labor-rules/templates`). |
| `effective_from` | Yes | Start of the effective period (`YYYY-MM-DD`). |

**Behavior**

* Creates a company effective period with the template's parameters and an indefinite duration.
* If the company has an open active period (no end date) that starts earlier, it is closed the day before `effective_from`.
* Queues the recalculation of the affected attendance.

**Response `201`**: the created rule set, with `recalculation_queued`.

| Code | Cause |
| - | - |
| `404` | The template does not exist. |
| `422` | Validation, or the period overlaps another active period of the company. |

## Create rules

```http theme={null}
POST /hr/labor-rules
```

**Required permission:** `hr.labor_rules.write`

```json theme={null}
{
  "country_code": "SV",
  "name": "Reglas 2027",
  "effective_from": "2027-01-01",
  "effective_to": null,
  "is_active": true,
  "params": {
    "timezone": "America/El_Salvador",
    "day_band": { "start": "06:00", "end": "19:00" },
    "mixed_rule": { "type": "night_if_night_minutes_gt", "threshold_minutes": 240 },
    "max_ordinary": {
      "daily": { "day": 480, "night": 420, "mixed": 480 },
      "weekly": { "day": 2640, "night": 2340, "mixed": 2640 }
    },
    "week_starts_on": 1,
    "default_rest_days": [7],
    "default_daily_minutes": { "1": 480, "2": 480, "3": 480, "4": 480, "5": 480, "6": 240, "7": 0 },
    "overtime": {
      "basis": ["daily", "weekly"],
      "daily_cap_minutes": null,
      "weekly_cap_minutes": null,
      "total_daily_cap_minutes": null,
      "requires_approval": false
    },
    "surcharges": {
      "ordinary_day": 0, "ordinary_night": 0.25,
      "overtime_day": 1.0, "overtime_night": 1.5,
      "rest_day": 0.5, "holiday": 1.0,
      "combination": "multiplicative"
    },
    "rest_day_compensatory": true,
    "breaks": { "paid": false, "min_minutes": 30, "auto_deduct_minutes": 0 },
    "tolerances": { "late_grace_minutes": 5, "early_leave_grace_minutes": 0, "absence_after_minutes": null },
    "rounding": { "unit_minutes": 1, "mode": "none" },
    "min_hourly_wage": 1.70,
    "currency": "USD",
    "leave": { "vacation_day_counting": "working", "other_day_counting": "calendar" }
  }
}
```

| Field | Required | Description |
| - | - | - |
| `country_code` | Yes | Country (2 letters). |
| `name` | Yes | Name (max. 255). |
| `effective_from` | Yes | Start of the effective period (`YYYY-MM-DD`). |
| `effective_to` | No | End of the effective period. `null` = indefinite. |
| `params` | Yes | Complete parameters (see below). |
| `is_active` | No | Defaults to `true`. Two active periods cannot overlap. |

### Parameters

All minutes are integers; surcharges are an **additional fraction** over the ordinary daytime hour (`0.25` = +25%).

| Parameter | Description |
| - | - |
| `timezone` | IANA time zone (e.g., `America/Guatemala`). |
| `day_band.start`, `day_band.end` | Daytime band `HH:MM`; the rest is nighttime. |
| `mixed_rule.type` | `night_if_night_minutes_gt` (night shift if the night minutes **exceed** the threshold), `night_if_night_minutes_gte` (if they **equal or exceed** it) or `per_hour` (no mixed shift: each hour according to its band). |
| `mixed_rule.threshold_minutes` | Threshold in minutes. Required except with `per_hour`. |
| `max_ordinary.daily.{day,night,mixed}` | Maximum ordinary minutes per day according to the shift class. |
| `max_ordinary.weekly.{day,night,mixed}` | Weekly maximum. |
| `week_starts_on` | Day the week starts (1 = Monday … 7 = Sunday). |
| `default_rest_days` | Rest days for employees without a schedule (1–7). |
| `default_daily_minutes` | Workday per day of the week (`"1"`…`"7"`) for employees without a schedule. |
| `overtime.basis` | `daily`, `weekly` or both. |
| `overtime.daily_cap_minutes`, `overtime.weekly_cap_minutes`, `overtime.total_daily_cap_minutes` | Caps that generate **warnings** (they do not trim hours). `null` = no cap. |
| `overtime.requires_approval` | If `true`, overtime is only paid once approved (see [overtime approval](https://docs.filexpress.app/en/docs/api/rrhh/resultados-asistencia.md#overtime-approval)). |
| `surcharges.{ordinary_day, ordinary_night, overtime_day, overtime_night, rest_day, holiday}` | Surcharges. |
| `surcharges.combination` | `additive`: `1 + surcharge + day surcharge`. `multiplicative`: `(1 + surcharge) × (1 + day surcharge)`. |
| `rest_day_compensatory` | Whether work on a rest day grants a compensatory day off. |
| `breaks.paid`, `breaks.min_minutes`, `breaks.auto_deduct_minutes` | Whether the break is paid, minimum, and automatic deduction. |
| `tolerances.late_grace_minutes`, `tolerances.early_leave_grace_minutes` | Check-in and check-out tolerances. |
| `tolerances.absence_after_minutes` | Lateness after which the day counts as an absence. `null` = does not apply. |
| `rounding.unit_minutes`, `rounding.mode` | Unit (1–60) and mode: `none`, `floor`, `ceil`, `nearest`. |
| `min_hourly_wage` | Minimum hourly wage (optional), for warnings. |
| `currency` | 3-letter ISO currency. |
| `leave.vacation_day_counting` | Vacation day counting: `calendar` or `working` (business days: excluding schedule rest days and holidays). Optional; if missing, the country's default is used (`working` in GT and CO, `calendar` elsewhere). |
| `leave.other_day_counting` | Counting for other leave: `calendar` (default) or `working`. |

**Response `201`**: the created rule set (same format as `rule_sets`) plus `recalculation_queued` (`true` if the recalculation of the affected attendance was queued).

| Code | Cause |
| - | - |
| `422` | Field or `params` validation (parameter errors come as `params.<key>`), end of period before the start, or a period that overlaps another active one. |

## Edit rules

```http theme={null}
PUT /hr/labor-rules/{id}
```

**Required permission:** `hr.labor_rules.write`

Send only the fields that change. If you send `params`, it must be **complete** (it replaces the previous ones). Only company periods can be edited, not templates.

```json theme={null}
{ "effective_to": "2026-12-31" }
```

**Behavior**

* If attendance has already been calculated in the period, it is recalculated (the last 90 days at most). Days included in processed or paid payrolls do not change.

**Response `200`**: the updated rule set, with `recalculation_queued`.


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