---
title: "Recalculate payroll run"
description: "Recalculates in the background, from current employee data and tax rules, every receipt not yet sent to SAT, and adds or removes employees who joined or left the run. Read the run until calculating is false."
language: en
canonical_url: "https://exac.mx/docs/en/api/documents/payroll/recalculate-payroll-run"
md_url: "https://exac.mx/docs/en/api/documents/payroll/recalculate-payroll-run.md"
---

# Recalculate payroll run

Recalculates in the background, from current employee data and tax rules, every receipt not yet sent to SAT, and adds or removes employees who joined or left the run. Read the run until calculating is false.

## Request

`POST /v1/payroll/runs/{runId}/recalculate`

- **Authorization:** Required permission: `employees:manage`.

- **Environments:** Production and sandbox

- **Idempotency:** Required

## Canonical machine contract

This fragment is generated from the canonical operation and Zod contracts used by the route.

```json
{
  "method": "POST",
  "path": "/v1/payroll/runs/{runId}/recalculate",
  "operation": {
    "operationId": "recalculatePayrollRun",
    "tags": [
      "Payroll"
    ],
    "summary": "Recalculate payroll run",
    "description": "Recalculates in the background, from current employee data and tax rules, every receipt not yet sent to SAT, and adds or removes employees who joined or left the run. Read the run until calculating is false.",
    "security": [
      {
        "bearerAuth": []
      }
    ],
    "parameters": [
      {
        "name": "runId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 1,
          "description": "runId of a payroll run, as prepared or listed."
        }
      },
      {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200
        },
        "description": "Unique retry key for this exact operation. Reuse it only when retrying the same request."
      }
    ],
    "requestBody": {
      "required": false,
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {},
            "additionalProperties": false
          },
          "example": {}
        }
      }
    },
    "responses": {
      "200": {
        "description": "Operation completed.",
        "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": "Invalid request.\n\n`validation_error`",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "401": {
        "description": "Missing or invalid credential.\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": "Insufficient prepaid balance or an unmet billing requirement.\n\n`payment_required`",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "403": {
        "description": "The credential does not include the `employees:manage` permission.\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": "Resource not found.\n\n`not_found`",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "405": {
        "description": "Method not allowed.\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": "State, environment, or idempotency conflict. Use error.code to determine recovery.\n\nPossible codes: `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": "Too many requests.\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": "Internal server error.\n\n`internal`",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "503": {
        "description": "Service temporarily unavailable.\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": "Recommended action by code:\n\n- `validation_error` — Correct the request using error.message and, when present, details.issues paths and codes.\n- `unauthenticated` — Provide a valid API key or OAuth access token.\n- `forbidden` — Use a credential with the required permission.\n- `payment_required` — For details.reason = api_wallet_insufficient, add prepaid API/MCP credit using details.topUpUrl; balanceMinor is the balance in centavos. Otherwise review the billing requirement. Retry only after it is resolved.\n- `not_found` — Check the organization-scoped resource identifier.\n- `method_not_allowed` — Use the documented HTTP method.\n- `conflict` — Refresh the resource and resolve its current state.\n- `idempotency_conflict` — Use a new idempotency key for a changed request.\n- `operation_in_progress` — Wait for Retry-After, then repeat the exact request.\n- `recovery_required` — Do not retry automatically or change the idempotency key. Retrieve details.document.documentRef when present, verify the outcome, and contact support with Request-Id if it remains uncertain.\n- `migration_required` — Contact support to complete historical document migration; do not reissue the document.\n- `rate_limited` — Wait for Retry-After before retrying.\n- `provider_unavailable` — Retry only when the response marks the failure as retryable.\n- `internal` — A failed response does not prove that a write had no effect. Retry a read after backoff; retry a write only with its original idempotency key and unchanged request. Contact support with Request-Id if it persists."
          },
          "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)

## Equivalent MCP tools

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

Complete documentation: https://exac.mx/docs/en.md
Agent documentation index: https://exac.mx/docs/en/llms.txt
