# Crear (/docs/developers/api-reference/payroll-calendars/create)

## Descripcion general [#descripcion-general]

Este endpoint crea calendarios de nómina dentro de tu organización. Cada objeto de creación lleva un arreglo `legal_entity_numbers` y **crea un calendario por cada razón social** de ese arreglo, cada uno con sus propios periodos generados automáticamente a partir de `frequency` y `year`. Por este comportamiento de fan-out, y a diferencia de otros endpoints, la respuesta **siempre** usa la envoltura `{ summary, created }` (nunca un objeto suelto), incluso cuando envías un solo objeto. Acepta **un objeto** o un **arreglo de objetos**; el total de calendarios resultantes —la suma de las longitudes de todos los `legal_entity_numbers`— no puede exceder 100.

## Endpoint [#endpoint]

`POST https://app.integranom.com/api/v1/payroll-calendars`

## Solicitud unica — fan-out por razon social [#solicitud-unica--fan-out-por-razon-social]

***

Envía un objeto con `legal_entity_numbers`. El ejemplo crea **dos** calendarios idénticos —uno para la razón social `1` y otro para la `2`—, cada uno con sus propios periodos.

Aunque envíes un solo objeto, la respuesta siempre es la envoltura `{ summary, created }`. `summary.total` es el número de calendarios que se intentaron crear (la suma de las longitudes de `legal_entity_numbers`) y `summary.created` cuántos se crearon.

```json
{
  "legal_entity_numbers": [1, 2],
  "name": "Quincenal 2026",
  "frequency": "semimonthly",
  "isr_tariff_frequency": "semimonthly",
  "year": 2026,
  "pay_day_offset": 3
}
```

**cURL**

```bash
curl -X POST "https://app.integranom.com/api/v1/payroll-calendars" \
-H "Authorization: Bearer TU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "legal_entity_numbers": [1, 2],
  "name": "Quincenal 2026",
  "frequency": "semimonthly",
  "isr_tariff_frequency": "semimonthly",
  "year": 2026,
  "pay_day_offset": 3
}'
```

**Respuesta**

```json
{
"summary": { "total": 2, "created": 2 },
"created": [
  {
    "payroll_calendar_number": 3,
    "legal_entity_number": 1,
    "name": "Quincenal 2026",
    "frequency": "semimonthly",
    "isr_tariff_frequency": "semimonthly",
    "applies_seventh_day_discount": true,
    "month_day_factor": 30,
    "anchor_date": "2026-01-01T00:00:00.000Z",
    "pay_day_offset": 3,
    "timezone": "America/Mexico_City",
    "is_active": true,
    "periods_count": 24,
    "created_at": "2026-01-01T00:00:00.000Z",
    "updated_at": "2026-01-01T00:00:00.000Z"
  },
  {
    "payroll_calendar_number": 4,
    "legal_entity_number": 2,
    "name": "Quincenal 2026",
    "frequency": "semimonthly",
    "isr_tariff_frequency": "semimonthly",
    "applies_seventh_day_discount": true,
    "month_day_factor": 30,
    "anchor_date": "2026-01-01T00:00:00.000Z",
    "pay_day_offset": 3,
    "timezone": "America/Mexico_City",
    "is_active": true,
    "periods_count": 24,
    "created_at": "2026-01-01T00:00:00.000Z",
    "updated_at": "2026-01-01T00:00:00.000Z"
  }
]
}
```

## Solicitud por lote [#solicitud-por-lote]

***

Envía un **arreglo** de objetos de creación. El fan-out se aplica a cada objeto por separado: el total de calendarios resultantes es la suma de las longitudes de todos los `legal_entity_numbers` y no puede exceder 100.

Si **cualquier** fila falla la validación, **ningún** calendario se crea y la respuesta lista los problemas por fila.

```json
[
  { "legal_entity_numbers": [1], "name": "Quincenal 2026", "frequency": "semimonthly",
  "isr_tariff_frequency": "semimonthly", "year": 2026, "pay_day_offset": 3 },
  { "legal_entity_numbers": [1], "name": "Semanal 2026", "frequency": "weekly",
  "isr_tariff_frequency": "weekly", "year": 2026, "pay_day_offset": 5 }
]
```

**cURL**

```bash
curl -X POST "https://app.integranom.com/api/v1/payroll-calendars" \
-H "Authorization: Bearer TU_API_KEY" \
-H "Content-Type: application/json" \
-d '[
  {
    "legal_entity_numbers": [1],
    "name": "Quincenal 2026",
    "frequency": "semimonthly",
    "isr_tariff_frequency": "semimonthly",
    "year": 2026,
    "pay_day_offset": 3
  },
  {
    "legal_entity_numbers": [1],
    "name": "Semanal 2026",
    "frequency": "weekly",
    "isr_tariff_frequency": "weekly",
    "year": 2026,
    "pay_day_offset": 5
  }
]'
```

**Respuesta**

```json
{
"summary": { "total": 2, "created": 2 },
"created": [
  {
    "payroll_calendar_number": 3,
    "legal_entity_number": 1,
    "name": "Quincenal 2026",
    "frequency": "semimonthly",
    "isr_tariff_frequency": "semimonthly",
    "applies_seventh_day_discount": true,
    "month_day_factor": 30,
    "anchor_date": "2026-01-01T00:00:00.000Z",
    "pay_day_offset": 3,
    "timezone": "America/Mexico_City",
    "is_active": true,
    "periods_count": 24,
    "created_at": "2026-01-01T00:00:00.000Z",
    "updated_at": "2026-01-01T00:00:00.000Z"
  },
  {
    "payroll_calendar_number": 4,
    "legal_entity_number": 1,
    "...": "..."
  }
]
}
```

## Reglas de los campos [#reglas-de-los-campos]

| Campo                          | Tipo                         | Requerido | Notas                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| ------------------------------ | ---------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `legal_entity_numbers`         | arreglo de enteros positivos | Sí        | Al menos un elemento (`≥ 1`). Una razón social por elemento; se crea un calendario para cada una.                                                                                                                                                                                                                                                                                                                                                                   |
| `name`                         | string                       | Sí        | 3–60 caracteres. Único por razón social.                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `frequency`                    | string                       | Sí        | Uno de `weekly` \| `biweekly` \| `semimonthly` \| `monthly`. **Inmutable** tras crear.                                                                                                                                                                                                                                                                                                                                                                              |
| `isr_tariff_frequency`         | string                       | No        | Tabla del SAT con la que se retiene el ISR. Si se omite, usa `monthly`. Sólo se admiten ese valor (cada periodo se calcula solo) o `monthly` (se acumula el mes y se descuenta lo ya retenido). Cualquier otro valor se rechaza.                                                                                                                                                                                                                                    |
| `applies_seventh_day_discount` | boolean                      | No        | Si las faltas y ausencias sin goce descuentan además un sexto del día de descanso (séptimo día proporcional). Si se omite, usa `true`. Un valor que no sea booleano se rechaza con `400`.                                                                                                                                                                                                                                                                           |
| `month_day_factor`             | number                       | No        | Días del mes del calendario: `30` o `30.4` (el número, no texto). Con ellos se convierte a diario el sueldo mensual, se fijan los días que paga una nómina mensual y se proyecta el mes en la tarifa mensual del ISR. Si se omite, cada calendario toma el valor por defecto de su razón social (el mes del catálogo `factor_dias_mes`, o `30` si no es 30 ni 30.4). Cualquier otro valor se rechaza con `400` y el mensaje `Los días del mes deben ser 30 o 30.4.` |
| `year`                         | integer                      | Sí        | Entre `2026` y `2100`. Año fiscal usado para generar los periodos; los parámetros fiscales de la plataforma empiezan en `2026`.                                                                                                                                                                                                                                                                                                                                     |
| `pay_day_offset`               | integer                      | Sí        | Entre `-15` y `15`. Días desde el fin del periodo hasta la fecha de pago; un valor negativo paga antes del cierre del periodo. Cada periodicidad tiene un mínimo para que el pago nunca caiga antes del inicio del periodo: `0` en `daily`, `-6` en `weekly`, `-7` en `decennial`, `-13` en `biweekly`, `-12` en `semimonthly` y `-15` en `monthly`. Un valor menor se rechaza con `400`.                                                                           |
| `first_period_start_day`       | string                       | No        | Fecha `AAAA-MM-DD` en que inicia el primer periodo. Solo para `weekly` y `biweekly`, entre el 1 de diciembre del año anterior a `year` y el 31 de enero de `year`. Si se omite, el primer periodo inicia el 1 de enero. Con otra periodicidad, o fuera de ese rango, se rechaza con `400`. El `anchor_date` de la respuesta es el inicio del primer periodo.                                                                                                        |
| `timezone`                     | string                       | No        | Por defecto `America/Mexico_City`. **Inmutable** tras crear.                                                                                                                                                                                                                                                                                                                                                                                                        |

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

### `201` — siempre la envoltura [#201--siempre-la-envoltura]

Sea el cuerpo **un objeto** o **un arreglo**, la respuesta siempre envuelve los resultados en `summary` + `created[]`.

```json
{
  "summary": { "total": 2, "created": 2 },
  "created": [
    { "payroll_calendar_number": 3, "legal_entity_number": 1, "...": "..." },
    { "payroll_calendar_number": 4, "legal_entity_number": 2, "...": "..." }
  ]
}
```

## Errores [#errores]

### `400` — validación fallida (objeto único) [#400--validación-fallida-objeto-único]

Para fallas de validación de campos, `errors` es un objeto indexado por campo:

```json
{
  "message": "Validation failed.",
  "errors": { "name": ["El nombre debe tener entre 3 y 60 caracteres."] }
}
```

### `400` — validación fallida (lote) [#400--validación-fallida-lote]

Reporte por fila. **Ningún** calendario del lote fue creado.

```json
{
  "message": "Validation failed.",
  "summary": { "total": 2, "with_errors": 1 },
  "errors": [
    {
      "index": 1,
      "payroll_calendar": { "name": "Semanal 2026" },
      "issues": [
        {
          "field": "legal_entity_numbers",
          "code": "LEGAL_ENTITY_NOT_FOUND",
          "message": "Legal entity '99' does not exist in the organization."
        }
      ]
    }
  ]
}
```

* `index` — posición 0-based de la fila que falló dentro del arreglo enviado.
* `payroll_calendar.name` — extraído de tu entrada para que identifiques la fila sin contar.
* `issues[]` — todos los problemas de esa fila listados juntos para corregirlos antes de reintentar.

### `400` — total excede el máximo [#400--total-excede-el-máximo]

Se devuelve cuando la suma de las longitudes de todos los `legal_entity_numbers` supera 100.

### `409` — nombre duplicado [#409--nombre-duplicado]

Se devuelve cuando el `name` ya existe para alguna de las razones sociales dadas.

```json
{
  "message": "A payroll calendar with this 'name' already exists for one of the given legal entities."
}
```

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

Estos códigos aparecen dentro de `issues[].code` (o como `code` en el cuerpo de error en single) y son estables — tu cliente puede ramificar lógica con base en ellos:

| Codigo                   | Significado                                                              |
| ------------------------ | ------------------------------------------------------------------------ |
| `INVALID_INPUT`          | Falla genérica de validación de campos (formato, longitud, tipo, rango). |
| `LEGAL_ENTITY_NOT_FOUND` | Un `legal_entity_number` no existe en la organización.                   |