---
title: "Preparar nómina"
description: "Devuelve la nómina de un periodo de pago y la crea si no existe: una por PeriodicidadPago e inicio de periodo. Una nómina conserva su periodo aunque cambie el calendario de pago y se encuentra por su propio inicio. Los recibos se calculan en segundo plano a partir del sueldo de cada empleado activo; consulta la nómina hasta que calculating sea false. Una fecha que no inicia un periodo devuelve 400 con el inicio del periodo que la contiene; un periodo que se cruza con otra nómina de la misma periodicidad devuelve 409 conflict con el periodo de esa nómina. El estado es 200 tanto si la nómina se creó como si ya existía."
language: es-MX
canonical_url: "https://exac.mx/docs/api/documents/payroll/prepare-payroll-run"
md_url: "https://exac.mx/docs/api/documents/payroll/prepare-payroll-run.md"
---

# Preparar nómina

Devuelve la nómina de un periodo de pago y la crea si no existe: una por PeriodicidadPago e inicio de periodo. Una nómina conserva su periodo aunque cambie el calendario de pago y se encuentra por su propio inicio. Los recibos se calculan en segundo plano a partir del sueldo de cada empleado activo; consulta la nómina hasta que calculating sea false. Una fecha que no inicia un periodo devuelve 400 con el inicio del periodo que la contiene; un periodo que se cruza con otra nómina de la misma periodicidad devuelve 409 conflict con el periodo de esa nómina. El estado es 200 tanto si la nómina se creó como si ya existía.

## Solicitud

`POST /v1/payroll/runs`

- **Autorización:** Permiso requerido: `employees:manage`.

- **Entornos:** Producción y prueba

- **Idempotencia:** Requerida

## Contrato canónico para máquinas

Este fragmento se genera desde la operación canónica y los contratos Zod que utiliza la ruta.

```json
{
  "method": "POST",
  "path": "/v1/payroll/runs",
  "operation": {
    "operationId": "preparePayrollRun",
    "tags": [
      "Payroll"
    ],
    "summary": "Preparar nómina",
    "description": "Devuelve la nómina de un periodo de pago y la crea si no existe: una por PeriodicidadPago e inicio de periodo. Una nómina conserva su periodo aunque cambie el calendario de pago y se encuentra por su propio inicio. Los recibos se calculan en segundo plano a partir del sueldo de cada empleado activo; consulta la nómina hasta que calculating sea false. Una fecha que no inicia un periodo devuelve 400 con el inicio del periodo que la contiene; un periodo que se cruza con otra nómina de la misma periodicidad devuelve 409 conflict con el periodo de esa nómina. El estado es 200 tanto si la nómina se creó como si ya existía.",
    "security": [
      {
        "bearerAuth": []
      }
    ],
    "parameters": [
      {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200
        },
        "description": "Clave estable para reintentar exactamente la misma solicitud sin duplicar efectos."
      }
    ],
    "requestBody": {
      "required": true,
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "frequency": {
                "type": "string",
                "enum": [
                  "10",
                  "02",
                  "03",
                  "04",
                  "05"
                ]
              },
              "periodStart": {
                "type": "string",
                "allOf": [
                  {
                    "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
                  },
                  {
                    "pattern": "^(19|20)"
                  }
                ],
                "description": "First day of the pay period."
              }
            },
            "required": [
              "frequency",
              "periodStart"
            ],
            "additionalProperties": false
          },
          "example": {
            "frequency": "02",
            "periodStart": "2026-09-21"
          }
        }
      }
    },
    "responses": {
      "200": {
        "description": "Operación completada.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/PayrollRun"
                }
              },
              "required": [
                "data"
              ],
              "additionalProperties": false
            },
            "example": {
              "data": {
                "runId": "payroll-run-example",
                "frequency": "02",
                "periodStart": "2026-09-21",
                "periodEnd": "2026-09-27",
                "paidOn": "2026-09-27",
                "calculating": true,
                "rows": {
                  "ready": {
                    "count": 2,
                    "net": 7834.56
                  },
                  "needs_attention": {
                    "count": 1,
                    "net": 0
                  },
                  "excluded": {
                    "count": 0,
                    "net": 0
                  },
                  "queued": {
                    "count": 0,
                    "net": 0
                  },
                  "stamping": {
                    "count": 0,
                    "net": 0
                  },
                  "stamped": {
                    "count": 0,
                    "net": 0
                  },
                  "rejected": {
                    "count": 0,
                    "net": 0
                  },
                  "canceled": {
                    "count": 0,
                    "net": 0
                  }
                },
                "missingSalary": 0,
                "createdAt": "2026-09-21T15:00:00.000Z"
              }
            }
          }
        }
      },
      "400": {
        "description": "Solicitud inválida.\n\n`validation_error`",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "401": {
        "description": "Credencial inválida o ausente.\n\n`unauthenticated`",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "WWW-Authenticate": {
            "$ref": "#/components/headers/WWWAuthenticate"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "402": {
        "description": "Saldo prepagado insuficiente o requisito de facturación pendiente.\n\n`payment_required`",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "403": {
        "description": "La credencial no incluye el permiso `employees:manage`.\n\n`forbidden`",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "WWW-Authenticate": {
            "$ref": "#/components/headers/WWWAuthenticate"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "404": {
        "description": "Recurso no encontrado.\n\n`not_found`",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "405": {
        "description": "Método no permitido.\n\n`method_not_allowed`",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Allow": {
            "$ref": "#/components/headers/Allow"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "409": {
        "description": "Conflicto de estado, entorno o idempotencia. Usa error.code para decidir cómo recuperarte.\n\nCódigos posibles: `conflict`, `idempotency_conflict`, `operation_in_progress`, `recovery_required`, `migration_required`.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "429": {
        "description": "Demasiadas solicitudes.\n\n`rate_limited`",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "500": {
        "description": "Error interno del servidor.\n\n`internal`",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "503": {
        "description": "Servicio temporalmente no disponible.\n\n`provider_unavailable`",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      }
    },
    "x-exac-environments": [
      "production",
      "sandbox"
    ]
  },
  "components": {
    "schemas": {
      "ApiError": {
        "type": "object",
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ProgrammaticError"
          }
        },
        "required": [
          "error"
        ],
        "additionalProperties": false
      },
      "ProgrammaticError": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "enum": [
              "validation_error",
              "unauthenticated",
              "forbidden",
              "payment_required",
              "not_found",
              "method_not_allowed",
              "conflict",
              "idempotency_conflict",
              "operation_in_progress",
              "recovery_required",
              "migration_required",
              "rate_limited",
              "provider_unavailable",
              "internal"
            ],
            "description": "Acción recomendada por código:\n\n- `validation_error` — Corrige la solicitud usando error.message y, cuando existan, los paths y códigos de details.issues.\n- `unauthenticated` — Proporciona una API key o un token de acceso OAuth válido.\n- `forbidden` — Usa una credencial con el permiso requerido.\n- `payment_required` — Si details.reason = api_wallet_insufficient, agrega saldo prepagado de API/MCP mediante details.topUpUrl; balanceMinor indica el saldo en centavos. En otros casos revisa el requisito de facturación. Reintenta solo después de resolverlo.\n- `not_found` — Verifica el identificador del recurso dentro de la organización.\n- `method_not_allowed` — Usa el método HTTP documentado.\n- `conflict` — Actualiza el recurso y resuelve su estado actual.\n- `idempotency_conflict` — Usa otra clave de idempotencia para una solicitud modificada.\n- `operation_in_progress` — Espera el tiempo de Retry-After y repite la misma solicitud.\n- `recovery_required` — No reintentes automáticamente ni cambies la clave de idempotencia. Consulta details.document.documentRef cuando exista, verifica el resultado y contacta a soporte con Request-Id si continúa incierto.\n- `migration_required` — Contacta a soporte para completar la migración histórica; no vuelvas a emitir el documento.\n- `rate_limited` — Espera el tiempo de Retry-After antes de reintentar.\n- `provider_unavailable` — Reintenta solo cuando la respuesta marque la falla como reintentable.\n- `internal` — Una respuesta fallida no demuestra que una escritura no tuvo efectos. Reintenta una lectura después de una espera; una escritura solo con su clave de idempotencia original y la solicitud sin cambios. Contacta a soporte con Request-Id si persiste."
          },
          "message": {
            "type": "string"
          },
          "details": {
            "type": "object",
            "properties": {
              "document": {
                "type": "object",
                "properties": {
                  "documentRef": {
                    "$ref": "#/components/schemas/DocumentRef"
                  },
                  "editable": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "documentRef",
                  "editable"
                ],
                "additionalProperties": false
              },
              "issues": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "path": {
                      "type": "array",
                      "items": {
                        "anyOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "number"
                          }
                        ]
                      }
                    },
                    "message": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "path",
                    "message"
                  ],
                  "additionalProperties": false
                }
              },
              "retryable": {
                "type": "boolean"
              },
              "retryAfterSeconds": {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              "reason": {
                "type": "string"
              },
              "balanceMinor": {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991
              },
              "topUpUrl": {
                "type": "string"
              }
            },
            "additionalProperties": false
          },
          "status": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          }
        },
        "required": [
          "code",
          "message",
          "status"
        ],
        "additionalProperties": false
      },
      "DocumentRef": {
        "type": "string",
        "pattern": "^(invoice|withholding|sales_receipt|declaration|tax_compliance_opinion|sales_receipt_refund):.+$"
      },
      "PayrollRun": {
        "type": "object",
        "properties": {
          "runId": {
            "type": "string"
          },
          "frequency": {
            "type": "string",
            "enum": [
              "10",
              "02",
              "03",
              "04",
              "05"
            ]
          },
          "periodStart": {
            "$ref": "#/components/schemas/CalendarDate"
          },
          "periodEnd": {
            "$ref": "#/components/schemas/CalendarDate"
          },
          "paidOn": {
            "$ref": "#/components/schemas/CalendarDate"
          },
          "calculating": {
            "type": "boolean",
            "description": "True while receipts are being calculated or recalculated."
          },
          "rows": {
            "type": "object",
            "properties": {
              "ready": {
                "$ref": "#/components/schemas/PayrollStateTotals"
              },
              "needs_attention": {
                "$ref": "#/components/schemas/PayrollStateTotals"
              },
              "excluded": {
                "$ref": "#/components/schemas/PayrollStateTotals"
              },
              "queued": {
                "$ref": "#/components/schemas/PayrollStateTotals"
              },
              "stamping": {
                "$ref": "#/components/schemas/PayrollStateTotals"
              },
              "stamped": {
                "$ref": "#/components/schemas/PayrollStateTotals"
              },
              "rejected": {
                "$ref": "#/components/schemas/PayrollStateTotals"
              },
              "canceled": {
                "$ref": "#/components/schemas/PayrollStateTotals"
              }
            },
            "required": [
              "ready",
              "needs_attention",
              "excluded",
              "queued",
              "stamping",
              "stamped",
              "rejected",
              "canceled"
            ],
            "additionalProperties": false
          },
          "missingSalary": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Receipts in needs_attention that lack a salary (issue salary_missing)."
          },
          "createdAt": {
            "$ref": "#/components/schemas/Instant"
          },
          "stampRequestedAt": {
            "$ref": "#/components/schemas/Instant"
          },
          "stampBlock": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "payment_required",
                  "interrupted",
                  "rules_pending_review"
                ]
              }
            },
            "required": [
              "code"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "runId",
          "frequency",
          "periodStart",
          "periodEnd",
          "paidOn",
          "calculating",
          "rows",
          "missingSalary",
          "createdAt"
        ],
        "additionalProperties": false
      },
      "Instant": {
        "type": "string",
        "format": "date-time",
        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
      },
      "PayrollStateTotals": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "net": {
            "type": "number"
          }
        },
        "required": [
          "count",
          "net"
        ],
        "additionalProperties": false
      },
      "CalendarDate": {
        "type": "string",
        "format": "date",
        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
      }
    }
  }
}
```

[OpenAPI 3.1](/openapi.json)

## Herramientas MCP equivalentes

- [`save_payroll`](/docs/mcp/tools/save_payroll.md)

Documentación completa: https://exac.mx/docs.md
Índice para agentes: https://exac.mx/docs/llms.txt
