# Editar en lote (/docs/developers/api-reference/employees/bulk-edit)

## Descripcion general [#descripcion-general]

Este endpoint aplica **actualizaciones parciales a varios empleados** en una sola solicitud. El cuerpo es un **arreglo de 1 a 100 objetos**, y cada objeto identifica al empleado con `employee_number` y lleva los mismos campos que [editar un empleado](/docs/developers/api-reference/employees/edit).

**Atómico (todo o nada).** Si **cualquier** fila falla la validación, **ningún** empleado se actualiza y la respuesta lista los problemas por fila para corregirlos en una sola pasada. Una solicitud exitosa devuelve `200` con un `summary` y el arreglo `updated` de empleados (objetos **planos**, mismo shape que [editar](/docs/developers/api-reference/employees/edit)).

**Mismas reglas que la edición individual, por fila:** resolución de códigos/números (LE-scoped para registro patronal, calendario y contrato), colisiones de RFC/CURP, invariante IMSS, datos fijos por historial de nómina, créditos que impiden reclasificar, banco requerido para una cuenta sin CLABE, preparación para nómina (`activate` / degradación automática), historial de sueldos al cambiar el sueldo y reconciliación de unidades organizacionales. En el lote, esas reglas llegan como problemas de la fila en la respuesta `400`, no como `409`. La excepción es el alta en periodos cerrados: sin `confirm_retro: true` en la fila, la respuesta es `409` con `RETRO_CONFIRMATION_REQUIRED` y `retro_periods` en esa fila, y ningún empleado se actualiza.

Para editar **un solo** empleado, usa [`PATCH /api/v1/employees/{employee_number}`](/docs/developers/api-reference/employees/edit) — este endpoint siempre espera un arreglo.

## Endpoint [#endpoint]

`PATCH https://app.integranom.com/api/v1/employees`

## Actualizar varios empleados [#actualizar-varios-empleados]

***

Envía un **arreglo** de hasta 100 objetos. Cada objeto necesita `employee_number` más los campos que quieras cambiar; el resto de cada empleado queda intacto. Si una fila falla, ninguna se aplica.

```json
[
  { "employee_number": 5, "department_code": "MKT", "job_position_code": null },
  { "employee_number": 7, "daily_base_salary": 666.67 }
]
```

**cURL**

```bash
curl -X PATCH "https://app.integranom.com/api/v1/employees" \
-H "Authorization: Bearer TU_API_KEY" \
-H "Content-Type: application/json" \
-d '[
  { "employee_number": 5, "department_code": "MKT", "job_position_code": null },
  { "employee_number": 7, "daily_base_salary": 666.67 }
]'
```

**Respuesta**

```json
{
"summary": { "total": 2, "updated": 2 },
"updated": [
  {
    "employee_number": 5,
    "status": "active",
    "department_code": "MKT",
    "job_position_code": null,
    "...": "resto de campos planos del empleado y su empleo"
  },
  {
    "employee_number": 7,
    "status": "active",
    "daily_base_salary": "666.6700",
    "...": "resto de campos planos del empleado y su empleo"
  }
]
}
```

## Cuerpo de la solicitud [#cuerpo-de-la-solicitud]

El cuerpo es un **arreglo** de 1 a 100 objetos. Cada objeto:

| Campo               | Tipo             | Notas                                                                                                                                                                                                                                                                                                   |
| ------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `employee_number`   | integer positivo | **Requerido.** Identifica al empleado a actualizar dentro de la organización.                                                                                                                                                                                                                           |
| *(resto de campos)* | —                | Idénticos a [`PATCH /api/v1/employees/{employee_number}`](/docs/developers/api-reference/employees/edit): datos personales, laborales, compensación, `organizational_units`, `activate`, `confirm_retro` y valores de campos personalizados inline. Omitir una clave la deja intacta; `null` la limpia. |

## Forma de las respuestas [#forma-de-las-respuestas]

### `200` — actualización exitosa [#200--actualización-exitosa]

La respuesta envuelve los resultados en `summary` + `updated[]`. Cada elemento de `updated` es el objeto **plano** del empleado (datos personales + los de su empleo actual), igual que la respuesta de [editar](/docs/developers/api-reference/employees/edit).

```json
{
  "summary": { "total": 2, "updated": 2 },
  "updated": [
    { "employee_number": 5, "...": "campos planos como en editar" },
    { "employee_number": 7, "...": "..." }
  ]
}
```

## Errores [#errores]

### `400` — validación fallida [#400--validación-fallida]

Reporte por fila. **Ningún** empleado del lote fue actualizado.

```json
{
  "message": "Validation failed for 1 employee(s). No employees were updated.",
  "summary": { "total": 2, "with_errors": 1 },
  "errors": [
    {
      "index": 1,
      "employee_number": 99,
      "issues": [
        {
          "field": "employee_number",
          "code": "EMPLOYEE_NOT_FOUND",
          "message": "No employee with number '99' in this organization."
        }
      ]
    }
  ]
}
```

* `index` — posición 0-based de la fila que falló dentro del arreglo enviado.
* `employee_number` — el número de empleado de esa fila, para identificarla sin contar.
* `issues[]` — todos los problemas de esa fila juntos.

También devuelve `400` (sin `errors[]` por fila) cuando el cuerpo no es un arreglo, está vacío o excede 100 elementos.

### `409` — condición de carrera [#409--condición-de-carrera]

Otra solicitud concurrente reclamó un RFC o CURP entre la validación y la escritura. La transacción completa hace rollback — ningún empleado es actualizado. Reintenta.

## Vocabulario de códigos de error [#vocabulario-de-códigos-de-error]

| Codigo                                                                                           | Significado                                                                                                                                                                                                                                                                   |
| ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `EMPLOYEE_NOT_FOUND`                                                                             | El `employee_number` no existe (o fue eliminado) en la organización.                                                                                                                                                                                                          |
| `DUPLICATE_EMPLOYEE_NUMBER_IN_BATCH`                                                             | El mismo `employee_number` aparece en más de una fila del lote.                                                                                                                                                                                                               |
| `NO_OPEN_EMPLOYMENT`                                                                             | Se enviaron campos laborales para un empleado dado de baja. Reactívalo primero.                                                                                                                                                                                               |
| `BELOW_MINIMUM_WAGE`                                                                             | El `daily_base_salary` efectivo es menor al salario mínimo diario vigente de la `minimum_wage_zone` efectiva. El mínimo se toma del catálogo `salario_minimo` de la organización y respeta el override de la razón social.                                                    |
| `ACCOUNT_NUMBER_TOO_LONG`                                                                        | El `account_number` efectivo excede los dígitos permitidos para el `bank` efectivo: 12 para BANREGIO, 11 para cualquier otro banco.                                                                                                                                           |
| `BANK_REQUIRED_FOR_ACCOUNT`                                                                      | El `account_number` efectivo no tiene `bank` ni una `clabe` válida; el recibo necesita nombrar el banco. Solo se revisa si la fila envía `bank`, `clabe` o `account_number`.                                                                                                  |
| `LOCKED_BY_PAYROLL_HISTORY`                                                                      | La fila cambia `worker_type`, `contributes_to_imss` o `employer_registration` de un empleado con una nómina cerrada en la que se le pagó o con su alta ante el IMSS ya presentada. Esos datos cambian con una baja y un reingreso.                                            |
| `LOCKED_BY_OPEN_PAYROLL`                                                                         | La fila cambia `payroll_calendar_number` mientras el empleado está en una nómina abierta. Ciérrala o cancélala primero.                                                                                                                                                       |
| `WORKER_TYPE_HAS_CREDITS`                                                                        | La fila cambia a un `subordinate` con créditos INFONAVIT o FONACOT activos o suspendidos a `asimilado` u `honorarios`.                                                                                                                                                        |
| `DUPLICATE_RFC` / `DUPLICATE_CURP`                                                               | El nuevo RFC/CURP colisiona con otro empleado de la organización.                                                                                                                                                                                                             |
| `DUPLICATE_RFC_IN_BATCH` / `DUPLICATE_CURP_IN_BATCH`                                             | El mismo RFC/CURP aparece en más de una fila del lote.                                                                                                                                                                                                                        |
| `JOB_POSITION_NOT_FOUND` / `BRANCH_NOT_FOUND` / `DEPARTMENT_NOT_FOUND` / `COST_CENTER_NOT_FOUND` | El código no coincide con un recurso activo.                                                                                                                                                                                                                                  |
| `EMPLOYER_REGISTRATION_NOT_FOUND` / `PAYROLL_CALENDAR_NOT_FOUND` / `CONTRACT_NOT_FOUND`          | El número no resuelve dentro de la razón social del empleo.                                                                                                                                                                                                                   |
| `ORGANIZATIONAL_UNIT_NOT_FOUND` / `ORGANIZATIONAL_UNIT_DUPLICATE_TYPE`                           | Unidad inexistente, o dos unidades del mismo tipo en `organizational_units`.                                                                                                                                                                                                  |
| `IMSS_REGISTRATION_REQUIRED`                                                                     | `contributes_to_imss` efectivo es `true` pero falta `employer_registration`.                                                                                                                                                                                                  |
| `WORKER_TYPE_IMSS_CONFLICT`                                                                      | `worker_type` efectivo no es `subordinate` pero `contributes_to_imss` efectivo es `true`.                                                                                                                                                                                     |
| `WORKER_REGIME_CONFLICT`                                                                         | El `regimen_fiscal` efectivo no corresponde al `worker_type` efectivo: `02` o `13` para `subordinate`, del `05` al `11` para `asimilado` y `honorarios`.                                                                                                                      |
| `WORKER_TYPE_FIELD_CONFLICT`                                                                     | El `worker_type` efectivo no es `subordinate` pero el `imss_number` o el `employer_registration` efectivo (el que indica `field`) no está vacío. Envíalo en `null` en la misma fila. La fecha de antigüedad no se valida: reclasificar a `asimilado` u `honorarios` la borra. |
| `ANNUAL_ISR_WORKER_TYPE_CONFLICT`                                                                | `receives_annual_isr_adjustment` es `true` pero el `worker_type` efectivo no es `subordinate`. Reemplaza a `ANNUAL_ISR_OPT_IN_CONFLICT`.                                                                                                                                      |
| `ACTIVATION_INCOMPLETE`                                                                          | `activate: true` en un empleado que no está listo para nómina.                                                                                                                                                                                                                |
| `RETRO_CONFIRMATION_REQUIRED`                                                                    | `activate: true` en un empleado cuya fecha de ingreso cae en periodos cerrados, sin `confirm_retro: true` (respuesta `409`).                                                                                                                                                  |
| `CUSTOM_FIELD_NOT_FOUND` / `CUSTOM_FIELD_INVALID_TYPE`                                           | Campo personalizado inexistente o de tipo incorrecto.                                                                                                                                                                                                                         |
| `INVALID_INPUT`                                                                                  | Falla genérica de validación de esquema (formato, tipo).                                                                                                                                                                                                                      |
| `CONCURRENT_MODIFICATION`                                                                        | Señal de reintento por condición de carrera (respuesta `409`).                                                                                                                                                                                                                |