{
  "openapi": "3.1.0",
  "info": {
    "title": "GroundIT — Pay & Tax",
    "version": "0.1.0",
    "license": {
      "name": "Proprietary — GroundIT/Sysmedac internal"
    },
    "description": "The controlled payroll-run lifecycle (draft → preview → approve → execute → publish) and the one multi-country statutory engine (India EPFO/ESIC/PT/TDS/gratuity · KSA GOSI/WPS/EOSB); immutable, config-version-stamped payslips with YTD; run-time earnings/deductions (arrears, bonus, variable pay); ESOP grant/vest/exercise; in-house salary advances & employee loans recovered through payroll; and full-&-final settlement (`pay.*`) — plus India-only investment-tax regime election, declarations (80C/80D/HRA/LTA/NPS), proof verification, and year-end Form 16/TDS (`tax.*`). See ../../api-docs/00-api-overview-and-conventions.md.\n"
  },
  "servers": [
    {
      "url": "/api/v1"
    }
  ],
  "security": [
    {
      "bearerJWT": []
    }
  ],
  "tags": [
    {
      "name": "pay",
      "description": "Payroll runs, statutory engine, payslips, ESOP, advances/loans, full-&-final settlement."
    },
    {
      "name": "tax",
      "description": "India-only investment-tax — regime, declarations, proofs, Form 16/TDS."
    },
    {
      "name": "payslip",
      "description": "Payslips, YTD, and the Finance-workspace read-model projections over them (PAY-S11, PAY-S16–S18, PAY-S20). Declared so the resource tag on those operations resolves; the remaining `pay`/`tax` resource tags in this file are still undeclared and back-filling them is a separate housekeeping pass.\n"
    }
  ],
  "x-reuse-anchors": {
    "parameters": {
      "path_id": {
        "$ref": "#/components/parameters/PathId"
      },
      "page_size": {
        "$ref": "#/components/parameters/PageSize"
      },
      "page_after": {
        "$ref": "#/components/parameters/PageAfter"
      },
      "page_before": {
        "$ref": "#/components/parameters/PageBefore"
      },
      "idempotency_key": {
        "$ref": "#/components/parameters/IdempotencyKey"
      },
      "if_match": {
        "$ref": "#/components/parameters/IfMatch"
      }
    },
    "responses": {
      "unauthorized": {
        "$ref": "#/components/responses/Unauthorized"
      },
      "forbidden": {
        "$ref": "#/components/responses/Forbidden"
      },
      "payment_required": {
        "$ref": "#/components/responses/PaymentRequired"
      },
      "not_found": {
        "$ref": "#/components/responses/NotFound"
      },
      "conflict": {
        "$ref": "#/components/responses/Conflict"
      },
      "unprocessable": {
        "$ref": "#/components/responses/UnprocessableEntity"
      },
      "locked": {
        "$ref": "#/components/responses/Locked"
      },
      "too_many": {
        "$ref": "#/components/responses/TooManyRequests"
      },
      "precondition_required": {
        "$ref": "#/components/responses/PreconditionRequired"
      },
      "precondition_failed": {
        "$ref": "#/components/responses/PreconditionFailed"
      }
    },
    "headers": {
      "etag": {
        "$ref": "#/components/headers/ETag"
      },
      "location": {
        "$ref": "#/components/headers/Location"
      },
      "idem_replayed": {
        "$ref": "#/components/headers/IdempotencyReplayed"
      }
    }
  },
  "paths": {
    "/payroll-runs": {
      "get": {
        "operationId": "pay.payroll_run.list",
        "summary": "List payroll runs (dashboard)",
        "description": "Finance's payroll home — the run pipeline with headline totals (PAY-S09, db 07 §1.1); the same run-level totals (gross/net/employer cost) also back the Finance workspace's cost-visibility KPI cards (PAY-S16).\n",
        "tags": [
          "pay",
          "payroll_run"
        ],
        "x-token": "pay.payroll_run.list",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S09",
          "PAY-S33",
          "PAY-S34"
        ],
        "x-touches-entities": [
          "pay.payroll_runs",
          "org.legal_entities"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "employee_no",
                "-employee_no",
                "employee_name",
                "-employee_name"
              ]
            },
            "description": "Sort whitelist; defaults to employee number."
          },
          {
            "name": "legal_entity_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/PayrollRunStatus"
            }
          },
          {
            "name": "run_type",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/RunType"
            }
          },
          {
            "name": "pay_period_start[from]",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/DateOnlyRef"
            }
          },
          {
            "name": "pay_period_start[to]",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/DateOnlyRef"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: `pay_period_start`, `-pay_period_start`, `pay_date`, `status`. Default `-pay_period_start`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of payroll runs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollRunPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "operationId": "pay.payroll_run.create",
        "summary": "Create a payroll run",
        "description": "Opens a `DRAFT` run for a legal entity + generated period; the entity drives market/currency/fiscal-year/pack (PAY-S09 **+ New Payroll Run**, db 07 §1.1). The optional `pay_group_id` defaults to the entity's effective DEFAULT group. Every non-`OFF_CYCLE` run must exactly match an existing generated period.\n\n**Period precondition ([ADR 0069](../../../architecture-docs/adr/0069-pay-cycle-single-surface-disbursement-ledger-release-batches.md) §(b)).** A `REGULAR` run may be created while its period is still `OPEN` or `CUTOFF_PASSED` — the **provisional draft**, so a cycle can be costed before its inputs lock — and creating one then **does not** touch the period. Only a period already `INPUTS_LOCKED` is advanced to `RUN_LINKED` and given its `INPUTS_LOCKED` readiness stage at create; otherwise the link happens at `pay.pay_period.lock_inputs`. A `CLOSED` period is `409`. **Every other run type is unchanged**: `SUPPLEMENTARY`, `ARREARS` and `FNF` still require `INPUTS_LOCKED`/`RUN_LINKED`/ `CLOSED`, because they pay facts a locked cycle has already decided.\n\nA provisional run must NOT link its period: `RUN_LINKED` is a member of the locked-period set that attendance, leave and the arrear-receipt service consult, so a linked-but-open period would spill every later fact into the next cycle for nothing.\n\nPrefer `pay.pay_period.ensure_run` from the cycle workspace — it derives every field here from the period and its pay group, and is idempotent.\n",
        "tags": [
          "pay",
          "payroll_run"
        ],
        "x-token": "pay.payroll_run.create",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S09",
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_runs",
          "pay.pay_periods",
          "org.pay_groups",
          "org.legal_entities"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayrollRunCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Run created in `DRAFT`.",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollRun"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}": {
      "get": {
        "operationId": "pay.payroll_run.get",
        "summary": "Get one payroll run",
        "description": "The run detail + lifecycle stage (PAY-S10 execution console; also the Finance/Manager mobile glance, PAY-S03, db 07 §1.1).",
        "tags": [
          "pay",
          "payroll_run"
        ],
        "x-token": "pay.payroll_run.get",
        "x-realizes-features": [
          "PAY-F01",
          "PAY-F02"
        ],
        "x-screens": [
          "PAY-S03",
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_runs"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "The payroll run, **with its readiness pipeline** — `stage_progress` is `pay.run_stage_progress` (ADR 0029 §(c)), which PAY-S21 renders. It is served here rather than behind a second operation and a second token because a stage row is run-shaped, is already inside this read's tenant scope, and the pipeline screen is loading the run anyway.\n",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollRunDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/preview": {
      "post": {
        "operationId": "pay.payroll_run.preview",
        "summary": "Compute a dry-run preview of the run",
        "description": "Engine dry-run on the jobs tier (XC-F08) — figures reviewable but not committed; `DRAFT → PREVIEW` (PAY-S10 **Preview**, db 07 §1.1).\n",
        "tags": [
          "pay",
          "payroll_run"
        ],
        "x-token": "pay.payroll_run.preview",
        "x-realizes-features": [
          "PAY-F01",
          "PAY-F02"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_runs",
          "pay.payslips",
          "pay.earnings",
          "pay.deductions"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "async",
        "x-emits-event": "pay.payroll_run.previewed",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "202": {
            "description": "Preview compute enqueued; poll `GET` or subscribe to `pay.payroll_run.previewed`.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollRun"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/submit-for-approval": {
      "post": {
        "operationId": "pay.payroll_run.submit_for_approval",
        "summary": "Submit a previewed run for maker-checker approval",
        "description": "Stamps `submitted_by`/`submitted_at`; stays `PREVIEW` pending the checker (PAY-S33, XC-F12, db 07 §1.1).\n\n**The lock gate ([ADR 0069](../../../architecture-docs/adr/0069-pay-cycle-single-surface-disbursement-ledger-release-batches.md) §(b)).** The run's pay period must be `INPUTS_LOCKED`, `RUN_LINKED` or `CLOSED`, else `409` with `type: urn:groundit:problem:pay:period-inputs-not-locked`. This is the requirement `pay.payroll_run.create` gave up when the provisional draft became legal: a cycle may be costed while its inputs are still moving, but nobody is asked to sign moving numbers. A period-less run (`OFF_CYCLE`) has no lock to wait on and passes.\n",
        "tags": [
          "pay",
          "payroll_run"
        ],
        "x-token": "pay.payroll_run.submit_for_approval",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_runs"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.payroll_run.submitted_for_approval",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submitted for approval.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollRun"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Not submittable from the run's current state, **or** the run's pay period has not locked its inputs. The lock refusal carries `type: urn:groundit:problem:pay:period-inputs-not-locked` with `code` still `STATE_TRANSITION_INVALID` (the platform code set is closed — `api-docs/03 §1`), and a `detail` naming the period's actual status. `PAY-S33` branches on the `type` to offer **Lock inputs** on the Inputs stage rather than an error toast: it is the one `409` on this operation whose remedy is a button the operator already has.\n",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "example": {
                  "type": "urn:groundit:problem:pay:period-inputs-not-locked",
                  "title": "Conflict",
                  "status": 409,
                  "code": "STATE_TRANSITION_INVALID",
                  "detail": "Lock inputs before submitting for approval — the pay period is CUTOFF_PASSED. Every figure on this run is provisional until the cycle's inputs are locked.",
                  "instance": "/api/v1/payroll-runs/018f2c7a-0000-7000-8000-0000000000b4/submit-for-approval",
                  "correlation_id": "018f2c7a-0000-7000-8000-0000000000c4"
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/approve": {
      "post": {
        "operationId": "pay.payroll_run.approve",
        "summary": "Approve a submitted run (checker)",
        "description": "Four-eyes checker clears `PREVIEW → APPROVED`, gating **Execute**; `submitted_by <> approved_by` enforced (PAY-S10, XC-F12, db 07 §1.1 check constraint).\n",
        "tags": [
          "pay",
          "payroll_run"
        ],
        "x-token": "pay.payroll_run.approve",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_runs"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.payroll_run.approved",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Approved; ready to execute.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollRun"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/execute": {
      "post": {
        "operationId": "pay.payroll_run.execute",
        "summary": "Execute an approved run (engine commit + config-version stamping)",
        "description": "The engine resolves earnings/deductions and **stamps** `pay_structure_version` + `compliance_pack_version` + `component_snapshot` (its resolved per-statute `statutory_config` version map + tenant-config version map) onto each `pay.payslips` row — frozen from here; `APPROVED → EXECUTED` (PAY-S10, PAY-F02, db 07 §1.2 `component_snapshot` shape). For an India run, the same jobs-tier execute chain registers the existing EPFO/ESIC engines after PT/TDS, stores the deterministic ECR/ESI-return artifact, and submits it only through the stubbed statutory-filing port before the run emits `pay.payroll_run.executed`. Runs on the jobs tier (XC-F08); async per this round's execute contract.\n",
        "tags": [
          "pay",
          "payroll_run"
        ],
        "x-token": "pay.payroll_run.execute",
        "x-realizes-features": [
          "PAY-F01",
          "PAY-F02"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_runs",
          "pay.payslips",
          "pay.earnings",
          "pay.deductions",
          "org.pay_structures",
          "org.compliance_packs",
          "org.statutory_config",
          "admin.tenant_config"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "async",
        "x-emits-event": "pay.payroll_run.executed",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "202": {
            "description": "Execute enqueued; poll `GET` or subscribe to `pay.payroll_run.executed`.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollRun"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/publish": {
      "post": {
        "operationId": "pay.payroll_run.publish",
        "summary": "Publish an executed run (freeze slips, release to employees)",
        "description": "`EXECUTED → PUBLISHED` — slips + earnings/deductions become **immutable** (`BEFORE UPDATE OR DELETE` trigger); emits the run-published event to `comply` for statutory filing (CMP-F01/F02) and to disbursement (WPS SIF for KSA via the `xc` interpay adapter) — cited in db/fsd as `payroll.published` (PAY-S10, PAY-F01). Async (jobs tier, XC-F08).\n",
        "tags": [
          "pay",
          "payroll_run"
        ],
        "x-token": "pay.payroll_run.publish",
        "x-realizes-features": [
          "PAY-F01",
          "PAY-F03"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_runs",
          "pay.payslips",
          "pay.earnings",
          "pay.deductions"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "async",
        "x-emits-event": "pay.payroll_run.published",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "202": {
            "description": "Publish enqueued; poll `GET` or subscribe to `pay.payroll_run.published`.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollRun"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/cancel": {
      "post": {
        "operationId": "pay.payroll_run.cancel",
        "summary": "Cancel a pre-publish run",
        "description": "Abandons the run from any pre-`PUBLISHED` state (PAY-S10, db 07 §1.1 lifecycle).",
        "tags": [
          "pay",
          "payroll_run"
        ],
        "x-token": "pay.payroll_run.cancel",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_runs"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.payroll_run.cancelled",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Cancelled.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollRun"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/pay-periods": {
      "get": {
        "operationId": "pay.pay_period.list",
        "summary": "List pay periods (the generated cycle instances with their cutoffs)",
        "description": "`pay.pay_periods` rows for a pay group, maintained on a rolling **12-month horizon** — written at pay-group activation by the `pay.generate_pay_periods_on_config` consumer (ADR 0070 §(a)), on operator request by `POST /pay-periods/generate`, and nightly by the `pay.generate_pay_periods` cron — idempotent against the `(pay_group_id, period_code)` unique key, so an operator can see next month's cutoff *before* it passes rather than after. Status **`OPEN → CUTOFF_PASSED → INPUTS_LOCKED → RUN_LINKED → CLOSED`**; only the first transition is made by the clock, the rest by operator action and the run lifecycle (ADR 0028 §(c)). Sort whitelist: `period_start`, `-period_start`, `period_code`. Default `-period_start`. When the `preview[...]` field set is present, this same read token returns a non-persisting 12-month draft horizon resolved by the server with the entity holiday calendar. Existing rows are returned unchanged with `is_existing=true`; only missing rows use the draft settings.\n",
        "tags": [
          "pay",
          "pay_period"
        ],
        "x-token": "pay.pay_period.list",
        "x-realizes-features": [
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33",
          "ORG-S11",
          "PAY-S34"
        ],
        "x-touches-entities": [
          "pay.pay_periods",
          "org.pay_groups"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "pay_group_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/PayPeriodStatus"
            }
          },
          {
            "name": "period_start[from]",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/DateOnlyRef"
            }
          },
          {
            "name": "period_end[to]",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/DateOnlyRef"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: `period_start`, `-period_start`, `period_code`. Default `-period_start`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "preview[legal_entity_id]",
            "in": "query",
            "required": false,
            "description": "Presence selects server-generated preview mode; all remaining required `preview[...]` fields must accompany it.",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "preview[pay_group_id]",
            "in": "query",
            "required": false,
            "description": "Existing pay-group version whose persisted periods are retained and marked `is_existing`; omit for create.",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "preview[attendance_cycle_anchor]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "CALENDAR_MONTH",
                "DAY_ANCHORED"
              ]
            }
          },
          {
            "name": "preview[anchor_day]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 28
            }
          },
          {
            "name": "preview[cutoff_day]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 28
            }
          },
          {
            "name": "preview[pay_day]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 31
            }
          },
          {
            "name": "preview[pay_date_shift_rule]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "PREVIOUS_WORKING_DAY",
                "NEXT_WORKING_DAY"
              ]
            }
          },
          {
            "name": "preview[timezone]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "IANA timezone."
            }
          },
          {
            "name": "preview[effective_from]",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/DateOnlyRef"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of pay periods.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PayPeriodPage"
                    },
                    {
                      "$ref": "#/components/schemas/PayPeriodPreviewPage"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/pay-periods/generate": {
      "post": {
        "operationId": "pay.pay_period.generate",
        "summary": "Generate (or refresh) the pay-period horizon for the tenant or one pay group",
        "description": "Asks the jobs tier to materialise the rolling **12-month pay-period horizon** — the same idempotent generator the nightly `pay.generate_pay_periods` cron and the `org.config.changed` consumer run, under the same per-tenant advisory lock and the same `(pay_group_id, period_code)` unique key, so a double press can never mint a second calendar. With `pay_group_id` the pass is restricted to that group's **effective-version family** (versions share a `pay_group_code`; the generator needs them together to pick the one effective on each period end) and advances only that group's passed cutoffs; without it the whole tenant's horizon is maintained.\n\n`202` with `{ accepted: true }`: the periods are written by **`pay.generate_pay_periods_on_request`** moments later — poll `GET /pay-periods`. An unknown `pay_group_id` is a `422` here rather than a silent worker no-op.\n",
        "tags": [
          "pay",
          "pay_period"
        ],
        "x-token": "pay.pay_period.generate",
        "x-realizes-features": [
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S34",
          "ORG-S11"
        ],
        "x-touches-entities": [
          "pay.pay_periods",
          "audit.audit_log",
          "xc.outbox",
          "xc.product_idempotency"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "async",
        "x-emits-event": "pay.pay_period.generate_requested",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "pay_group_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Restrict generation to this pay group's effective-version family."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Generation enqueued (or the stored idempotent response replayed); poll `GET /pay-periods`.",
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "accepted"
                  ],
                  "properties": {
                    "accepted": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/pay-periods/{id}": {
      "get": {
        "operationId": "pay.pay_period.get",
        "summary": "Get one pay period (windows, cutoff instant, pay date, status)",
        "description": "One period with both windows, its `cutoff_at` **`timestamptz` resolved in the pay group's own timezone** — a cutoff is an instant, not a fuzzy day — and the `pay_date` after `pay_date_shift_rule` was applied against the holiday calendar. Also carries the **spill ledger counts**: how many inputs from an earlier origin period are targeting this one. The spill ledger is a **pure read over the `(origin_period_id, target_period_id)` pair** (ADR 0028 §(e)) — no separate store, no reconciliation job, nothing to drift.\n",
        "tags": [
          "pay",
          "pay_period"
        ],
        "x-token": "pay.pay_period.get",
        "x-realizes-features": [
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.pay_periods",
          "pay.payroll_inputs",
          "org.pay_groups"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "The pay period.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayPeriodDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/pay-periods/{id}/lock-inputs": {
      "post": {
        "operationId": "pay.pay_period.lock_inputs",
        "summary": "Lock a cutoff-passed period against ordinary payroll inputs, and adopt its provisional run",
        "description": "Performs the operator-owned `CUTOFF_PASSED → INPUTS_LOCKED` transition. Later facts retain their origin period and target the next OPEN period; the action is CAS-protected, idempotent, and audit logged. Any other source status is `409`.\n\n**The lock is also where the provisional run becomes the cycle's run** ([ADR 0069](../../../architecture-docs/adr/0069-pay-cycle-single-surface-disbursement-ledger-release-batches.md) §(b)). If a `DRAFT` or `PREVIEW` `REGULAR` run exists for the period, the same transaction advances the period `INPUTS_LOCKED → RUN_LINKED`, records the run's `INPUTS_LOCKED` readiness stage against the staged input batch this lock closed, bumps the run's `version` (so a console holding a pre-lock ETag meets a `412` rather than submitting numbers computed before the lock), and emits a FULL `pay.payroll_run.populate_requested` — the moment the whole cycle is priced against its final input set. The response then carries `payroll_run_id` and `populate_requested: true`; with no such run both are `null`/`false` and the period rests at `INPUTS_LOCKED`. **`version` therefore moves by two** on the adopting path, and the returned `ETag` is the one to keep.\n",
        "tags": [
          "pay",
          "pay_period"
        ],
        "x-token": "pay.pay_period.lock_inputs",
        "x-realizes-features": [
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33",
          "ORG-S11"
        ],
        "x-touches-entities": [
          "pay.pay_periods",
          "pay.payroll_inputs",
          "pay.payroll_runs",
          "pay.run_stage_progress",
          "xc.job_runs",
          "audit.audit_log",
          "xc.product_idempotency"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.payroll_run.populate_requested",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Inputs locked (or the stored idempotent response replayed).",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayPeriodLockInputsResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/pay-periods/{id}/ensure-run": {
      "post": {
        "operationId": "pay.pay_period.ensure_run",
        "summary": "Find or create this cycle's REGULAR run and compute its estimate",
        "description": "**Compute estimate** on `PAY-S33`'s Inputs stage ([ADR 0069](../../../architecture-docs/adr/0069-pay-cycle-single-surface-disbursement-ledger-release-batches.md) §(b)). Holds the period row, finds its non-`CANCELLED` `REGULAR` run or creates one — the pay group supplies the legal entity and the pay frequency, that entity supplies the currency and the fiscal year, and the period supplies the three dates — and then, when that run is `DRAFT` or `PREVIEW`, emits `pay.payroll_run.populate_requested` with an `xc.job_runs` row the caller polls through `GET /payroll-runs/{id}.jobs[]`. It goes through the SAME create path as `pay.payroll_run.create`, so the frequency check, the period precondition, the one-REGULAR-run unique key and the audit row are identical.\n\n**Idempotent by nature and by key.** Calling it twice returns the same run; `Idempotency-Key` is required and replays the stored response. There is **no `If-Match`** — the caller may never have seen the run, which is the situation *ensure* exists to resolve. It answers `200` rather than `201` even when it creates: the contract is \"this cycle now has a run\", and `created` says which of the two happened without a client branching on a status code.\n\nA `CANCELLED` run is not adopted — cancelling is how an operator restarts a cycle — so a new one is created beside it. A run past `APPROVED` is returned with `populate_requested: false`: it is already committed to its numbers.\n\nMC-0: computing an estimate authorises nothing and moves no money. The four-eyes legs stay at `approve`, `execute` and `publish`.\n",
        "tags": [
          "pay",
          "pay_period"
        ],
        "x-token": "pay.pay_period.ensure_run",
        "x-realizes-features": [
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.pay_periods",
          "pay.payroll_runs",
          "pay.run_stage_progress",
          "xc.job_runs",
          "audit.audit_log",
          "xc.product_idempotency"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.payroll_run.populate_requested",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "The cycle's run (in the `GET /payroll-runs/{id}` shape, so a console can seed its poller from this response), with `created` and `populate_requested`. The `ETag` is the RUN's.\n",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayPeriodEnsureRunResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/populate": {
      "post": {
        "operationId": "pay.payroll_run.populate",
        "summary": "Generate the run's payslips from compensation, the attendance snapshot and staged inputs",
        "description": "**The calculation core the payroll module has always been described as having** (ADR 0029). Today a run is re-totalled from lines somebody typed; after populate, `pay.payslips`, `pay.earnings` and `pay.deductions` are **computed** by the pure, DB-free, decimal-string `packages/pay-calc` engine and written with their [ADR 0031](../../../architecture-docs/adr/0031-pay-explanations-as-data.md) explanation chains **in the same transaction** — the engine cannot emit a line without its chain, as a type-level guarantee rather than a review convention.\n\n**Legal from `DRAFT` or `PREVIEW`** (`409` from anything else). A `PREVIEW` run is **reopened** to `DRAFT` first — clearing `submitted_by`/`submitted_at`, because the numbers a maker submitted are the ones about to be replaced — so populate itself still only ever operates on a `DRAFT` run and ADR 0029 §(b)'s \"a step inside `DRAFT`\" is unamended ([ADR 0069](../../../architecture-docs/adr/0069-pay-cycle-single-surface-disbursement-ledger-release-batches.md) §(b): a cycle recomputes repeatedly against a moving input set, so refusing a second estimate would mean cancelling the run to get one). Populate is a *maker* activity; the checker still meets an assembled run at `submit_for_approval` exactly as today.\n\n**Every compute comes to rest at `PREVIEW`.** On success the populate job chains `pay.payroll_run.preview_requested` — the same guarded `DRAFT → PREVIEWING` move a human's *Preview* makes, with its own `xc.job_runs` row — unless a preview is already `QUEUED`/`RUNNING` for the run, or an open `HARD` validation finding blocks that edge (ADR 0029 §(f) is **not** bypassed by the chain), in which case the run rests at `DRAFT` with its findings.\n\nThe job resolves the pay group's population from open `pay.employee_compensation` rows, assembles each employee's input from structure + attendance-cycle finalization snapshot + staged `pay.payroll_inputs`, dispatches on `pay_model` ([ADR 0033](../../../architecture-docs/adr/0033-pay-models-daily-wage-and-piece-rate.md): `MONTHLY_SALARY` · `DAILY_WAGE` · `PIECE_RATE`), runs the **normative order of operations** — structure → segmentation → component evaluation → LOP → wage floor → additive inputs → statutory → netting — stamps `pay_structure_version` and `compliance_pack_version`, writes `paid_days`, `lop_days` and `component_snapshot.lop` **from the computation rather than from a keyboard**, marks the consumed inputs `APPLIED`, and computes validations and variances.\n\n**Re-populate supersedes.** Populating an already-populated `DRAFT` run **deletes the generated slips and lines and regenerates them** as one audited act, with superseded counts recorded. Delete-and-regenerate rather than merge: a partial merge is exactly how a payroll engine acquires irreproducible state. Manual lines added on top are preserved by origin flag and re-applied after regeneration; a manual line colliding with a generated component raises a validation finding rather than being silently overwritten.\n\n**`pay.payroll_run.preview` is unchanged** and stays a cheap re-total — generation is a distinct, idempotent, `DRAFT`-only act; preview remains the \"show me the current numbers\" operation it already is.\n\n**KSA scope has not been worked on at all in this wave** — `pay-calc` is market-neutral by construction and every statutory value is a pack value, so nothing here forecloses KSA, but GOSI, WPS/Mudad and EOSB integration into populate is explicitly future work.\n",
        "tags": [
          "pay",
          "payroll_run"
        ],
        "x-token": "pay.payroll_run.populate",
        "x-realizes-features": [
          "PAY-F01",
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_runs",
          "pay.payslips",
          "pay.earnings",
          "pay.deductions",
          "pay.payroll_inputs",
          "pay.pay_explanations",
          "pay.run_validations",
          "pay.run_variances",
          "pay.run_stage_progress",
          "pay.employee_compensation",
          "org.pay_structures"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "async",
        "x-emits-event": "pay.payroll_run.populate_requested",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayrollRunPopulateRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Population enqueued on the jobs tier (XC-F08); poll `GET /payroll-runs/{id}` or subscribe to `pay.payroll_run.populated`.\n",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollRun"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/validate": {
      "post": {
        "operationId": "pay.payroll_run.validate",
        "summary": "Re-run the completeness gate over a populated run",
        "description": "Recomputes `pay.run_validations` for the run (ADR 0029 §(f)) without regenerating anything — the operation an operator calls after fixing a bank account or a PAN, to see the queue shrink. Rule codes at launch: `BANK_MISSING` · `BANK_DUPLICATE` · `PAN_INVALID` · `UAN_DUPLICATE` · `UAN_AADHAAR_UNSEEDED` · `PT_STATE_MISSING` · `ESI_PERIOD_THRESHOLD_CROSSING` · `NEGATIVE_NET` · `WAGE_FLOOR_BREACH` · `MIN_WAGE_BREACH` · `COMP_ROW_MISSING` · `STRUCTURE_MISSING` · `ATTENDANCE_UNFINALIZED`; appended by migration `0218` (#1553, ADR 0070 §(d)): `OVERTIME_UNPROJECTED` (SOFT — attendance approved more overtime hours than reached payroll) and `PARTIAL_EXCEEDS_NET` (SOFT — a `PARTIALLY_PAY` instruction that no longer fits the recomputed slip; raised at populate and carried forward here verbatim).\n\n**This is a completeness gate, not an authority.** `HARD` findings block `DRAFT → PREVIEWING` **beside** maker≠checker rather than inside it — a run with an unbanked employee is not a permissions problem, it is an unfinished run — and the two gates must fail independently and legibly. It must stay that way, or it becomes a second place to hold permissions.\n\n**Synchronous by design, unlike `populate`.** This is a bounded re-check of already-computed slips against pay-local reference data — no engine run, no pack resolution, no payslip writes — so it returns `200` inline and emits no domain event (a `202` here would make an operator poll for an answer the request already has). The heavy statutory math that genuinely belongs on the jobs tier (XC-F08) stays in `populate`. The caller reads the refreshed findings through `pay.run_validation.list`.\n\n**It recomputes BOTH gates** (as built 2026-08-13, issue #570). Nine of the thirteen rules are re-derivable from pay-local and `people` data, which is what makes the operation worth calling; the four pack-dependent ones (`PT_STATE_MISSING`, `WAGE_FLOOR_BREACH`, `MIN_WAGE_BREACH`, `ESI_PERIOD_THRESHOLD_CROSSING`) are raised by `packages/pay-calc` at populate and **carried forward verbatim**, because this operation resolves no compliance pack and re-deciding them here would be a guess wearing the engine's authority. `pay.run_variances` is recomputed in the same act — the readiness pipeline renders the two gates side by side, and refreshing one while leaving the other stale is how a payroll manager comes to trust neither. It also satisfies the `VALIDATED` readiness stage, evidenced by the validation snapshot itself.\n",
        "tags": [
          "pay",
          "payroll_run"
        ],
        "x-token": "pay.payroll_run.validate",
        "x-realizes-features": [
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_runs",
          "pay.run_validations",
          "pay.run_variances",
          "pay.payslips",
          "pay.earnings",
          "pay.deductions",
          "pay.payroll_inputs",
          "pay.employee_compensation",
          "pay.pay_explanations",
          "pay.run_stage_progress",
          "org.pay_groups",
          "people.bank_accounts",
          "people.personal_info"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Findings recomputed. The blocking summary is inline; the per-employee detail is read through `pay.run_validation.list`.\n",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunValidationSummary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/inputs": {
      "get": {
        "operationId": "pay.payroll_input.list",
        "summary": "What this run is about to pay for, and where each item came from",
        "description": "`pay.payroll_inputs` for the run's target period — **the one staging surface** every cross-module fact lands in (ADR 0030 §(a)), written only by jobs-tier consumers of outbox events and read by the populate engine. This read is why the table is one table and not five: *\"what is this run about to pay for, and where did each item come from\"* is one query, not a union that grows with every future source.\n\nEvery row carries `source_module`, **`source_event_id` (unique — that column IS the idempotency guarantee)**, `source_ref` back to the owning module's row, and the **`origin_period_id`/`target_period_id`** pair. Filtering on `origin_period_id != target_period_id` **is the spill ledger**: *\"14 items from July are being paid in August, here they are.\"*\n\n`input_type` ∈ `ATTENDANCE_SUMMARY` · `OVERTIME` · `LEAVE_ENCASHMENT` · `TIMESHEET_HOURS` · `PIECE_RATE_UNITS` · `ARREAR` · `MANUAL_ADJUSTMENT` · `ADVANCE_RECOVERY` · `LOAN_EMI` (append-only). Sort whitelist: `created_at`, `-created_at`, `input_type`, `status`. Default `-created_at`.\n",
        "tags": [
          "pay",
          "payroll_input"
        ],
        "x-token": "pay.payroll_input.list",
        "x-realizes-features": [
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_inputs",
          "pay.pay_periods",
          "pay.payroll_runs"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "input_type",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/PayrollInputType"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/PayrollInputStatus"
            }
          },
          {
            "name": "spilled_only",
            "in": "query",
            "required": false,
            "description": "`true` returns only rows whose `origin_period_id` differs from their `target_period_id` — the spill ledger an operator reads before approving a run.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: `created_at`, `-created_at`, `input_type`, `status`. Default `-created_at`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of staged inputs for the run's target period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollInputPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/validations": {
      "get": {
        "operationId": "pay.run_validation.list",
        "summary": "The run's validation findings, per employee, per rule",
        "description": "`pay.run_validations` — one row per `(run, employee, rule_code)` with `severity` ∈ `HARD` | `SOFT`, per-employee detail and its resolution record (ADR 0029 §(f)). This is the operator-facing *\"what is blocking me\"* view the finalization gate needs on day one, when a tenant that has never cleared its regularization queue meets `ATTENDANCE_UNFINALIZED` for the first time.\n\n**Penny-drop bank verification** is a `fintech` port hook: the rule and its evidence slot exist now, the live integration is a later leg. `BANK_MISSING` and `BANK_DUPLICATE` are answerable from our own data today and are the ones that actually stop payrolls. Sort whitelist: `severity`, `rule_code`, `employee_id`. Default `severity`.\n",
        "tags": [
          "pay",
          "run_validation"
        ],
        "x-token": "pay.run_validation.list",
        "x-realizes-features": [
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.run_validations",
          "pay.payroll_runs",
          "pay.payslips"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "severity",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/RunValidationSeverity"
            }
          },
          {
            "name": "rule_code",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/RunValidationRuleCode"
            }
          },
          {
            "name": "unresolved_only",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: `severity`, `rule_code`, `employee_id`. Default `severity`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of validation findings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunValidationPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/validations/{validation_id}/acknowledge": {
      "post": {
        "operationId": "pay.run_validation.acknowledge",
        "summary": "Acknowledge a SOFT validation finding with a reason (audited)",
        "description": "**`SOFT` findings require an acknowledgement — actor + reason, audited — before the run can reach `APPROVED`** (ADR 0029 §(f)). A `HARD` finding cannot be acknowledged away: it is refused (`409`) and must be *fixed*, because a run with an unbanked employee is unfinished, not merely unreviewed. The reason is mandatory and is written to the append-only audit plane alongside the acknowledging actor.\n",
        "tags": [
          "pay",
          "run_validation"
        ],
        "x-token": "pay.run_validation.acknowledge",
        "x-realizes-features": [
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.run_validations",
          "audit.audit_logs"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "validation_id",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RunFindingAcknowledgeInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Finding acknowledged.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunValidation"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/variances": {
      "get": {
        "operationId": "pay.run_variance.list",
        "summary": "The variance gate — what moved, against what, and by how much",
        "description": "`pay.run_variances` — one row per `(run, employee, component)` carrying the current value, the **prior period**, the **same period last fiscal year**, both deltas, and a `flagged` boolean set against the pay group's `variance_flag_threshold_pct` (ADR 0030 §(e)). Computed **at the end of populate from pay-local history** — no cross-schema read, no new fetch.\n\nEvery flag carries an `explanation_id` resolving into the causal chain that explains it ([ADR 0031](../../../architecture-docs/adr/0031-pay-explanations-as-data.md)), so a payroll manager opening a flagged employee sees *\"net down ₹4,120 · LOP 3 d ← attendance finalization 2026-07 ← regularization #123 rejected\"* rather than a delta and a shrug. Triage without attribution is guesswork, and HR-side triage and employee-side self-service are the same attribution problem asked by two roles — built once, exposed twice.\n\nThe gate will be **noisy in a tenant's first cycles**; a threshold that flags nothing is theatre and one that flags everything is worse, which is why `variance_flag_threshold_pct` sits on the pay group where an operator can tune it per population. Sort whitelist: `delta_pct`, `-delta_pct`, `employee_id`. Default `-delta_pct`.\n",
        "tags": [
          "pay",
          "run_variance"
        ],
        "x-token": "pay.run_variance.list",
        "x-realizes-features": [
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.run_variances",
          "pay.pay_explanations",
          "pay.payslips",
          "pay.payroll_runs"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "flagged_only",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "unacknowledged_only",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: `delta_pct`, `-delta_pct`, `employee_id`. Default `-delta_pct`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of variance rows.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunVariancePage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/variances/{variance_id}/acknowledge": {
      "post": {
        "operationId": "pay.run_variance.acknowledge",
        "summary": "Acknowledge a flagged variance with a reason (blocking gate)",
        "description": "**A flagged row must be acknowledged with a reason before the run can reach `APPROVED`** (ADR 0030 §(e)), enforced in the payroll-run service **beside** the existing maker≠checker check rather than inside it: they are independent gates and must fail independently and legibly. The acknowledging actor and the reason are both recorded on the row.\n",
        "tags": [
          "pay",
          "run_variance"
        ],
        "x-token": "pay.run_variance.acknowledge",
        "x-realizes-features": [
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.run_variances",
          "audit.audit_logs"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "variance_id",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RunFindingAcknowledgeInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Variance acknowledged; the run's approval gate clears for this row.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunVariance"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/employee-actions": {
      "post": {
        "operationId": "pay.run_employee_action.set",
        "summary": "Set a per-employee run exception (PAY · HOLD · VOID · PARTIALLY_PAY · PAY_OUTSIDE_PAYROLL)",
        "description": "**The full per-employee exception vocabulary, made auditable** (ADR 0030 §(f), **re-pointed by ADR 0069 §(d)**). One row per `(run, employee)` in `pay.run_employee_actions`, with a **mandatory comment**, an actor and a timestamp. The vocabulary itself is the market's best exception primitive; the contribution here is the audit trail the incumbents mostly do not ship.\n\n**What each verb now writes — the disbursement ledger, and nothing else.** Payment state lives in `pay.payslip_disbursements` (db-docs/07 §1.10), one row per payslip, because a published payroll is frozen evidence and `net_pay_amount = gross − deductions` is a database CHECK. Four of the five verbs therefore touch no run row and no slip row at all:\n\n- **`PAY`** — un-hold: `HELD → PENDING`, or `PARTIAL` when money has already moved. Clears any\n  partial instruction, and un-cancels a payslip a prior `VOID` set aside (while the run is still\n  `DRAFT`/`PREVIEW`).\n\n- **`HOLD`** — `state = HELD`. **The slip and its inputs are untouched.** *(Changed 2026-09-02:\n  `HOLD` no longer re-targets the employee's staged inputs to the next period and no longer cancels\n  the slip. The owner's decision is that an unpaid employee **stays in their own cycle** — July's\n  facts stay against July, and the next cycle shows the outstanding amount as a **balance due**.)*\n\n- **`VOID`** — the slip is removed from the run with a reason and the ledger row goes `VOID` with\n  `due_amount = 0`; the run's totals recompute without it. **Nothing is deleted.**\n\n- **`PARTIALLY_PAY`** — records `partial_release_amount`: the next release batch of *this* run pays\n  only that much. **No arrear receipt is raised** *(changed 2026-09-02 — the remainder IS the ledger\n  row's `remaining_amount`; `arrear_receipt_id` is deprecated and always `null`)*. **Normative\n  ordering: the full stack computes first** — proration, statutory, deductions — **and the fraction\n  applies after, to the net**, because statutory bases must be computed on the *earned* amount and\n  not the disbursed one. Its interaction with statutory minimums is **not modelled** and is a\n  compliance question the market packs must answer before the action is enabled in production\n  (ADR 0030 residue).\n\n- **`PAY_OUTSIDE_PAYROLL`** — `state = OUTSIDE_PAYROLL`, `due_amount = 0`: **included in statutory\n  computation, excluded from every bank file**, for the person paid by cheque or by an entity\n  outside payroll.\n\n\n**Legal statuses.** `PAY`, `HOLD`, `PARTIALLY_PAY` and `PAY_OUTSIDE_PAYROLL` are legal in `DRAFT`, `PREVIEW`, `EXECUTED` **and `PUBLISHED`** — after publish they write **only** the ledger row, never `pay.payroll_runs` or `pay.payslips`, which is exactly why the immutability trigger does not refuse them. `VOID` alone still cancels the payslip, so `VOID` alone stays `DRAFT`/`PREVIEW`; asking for it later is a `409` that names `HOLD` and `PAY_OUTSIDE_PAYROLL` as the alternatives. Every verb is refused in the transitional statuses (`PREVIEWING`, `EXECUTING`, `PUBLISHING`) and in `APPROVED` — a change between approval and execution needs re-approval, and the `409` says so. A ledger row that is already `RELEASED` is settled money and refuses every verb, and a verb other than `VOID` is refused on a **cancelled payslip** once the run has left `DRAFT`/`PREVIEW`: the slip cannot be restored from there, so the obligation the verb would mint is money no bank file could ever pay (raise it on a supplementary or arrears run instead).\n\n**`If-Match` after publish.** The precondition is still taken against the RUN's version in every status, so two operators triaging the same cycle cannot silently overwrite each other. On a `PUBLISHED` run the version is deliberately **not bumped** — bumping it would be an `UPDATE` the trigger refuses and a change to evidence nobody made — so `payroll_run_version` comes back unchanged and `disbursement_version` is the value that moved.\n\n**What moves in the run's rollups.** `net_pay_amount` on the run is the **cycle's net liability** (db-docs/07 §1.1, #1546) and does **not** move when someone is held or paid outside payroll: paying a person by cheque does not make the cycle cheaper. Who is actually paid, and how much, is the ledger's answer, surfaced by `pay.payslip_disbursement.list` and summarised on the run read. `PARTIALLY_PAY` needs a **generated payslip** — the partial is priced against the computed net — so it is a `409` before populate, where every other verb is legal.\n\n**KSA scope has not been worked on at all in this wave** — the disbursement classification of `PAY_OUTSIDE_PAYROLL` under WPS, and GOSI treatment of the resulting balances, are explicitly future pack work.\n",
        "tags": [
          "pay",
          "run_employee_action"
        ],
        "x-token": "pay.run_employee_action.set",
        "x-realizes-features": [
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.run_employee_actions",
          "pay.payslip_disbursements",
          "pay.payroll_runs",
          "pay.payslips",
          "audit.audit_logs"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RunEmployeeActionSetInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Action recorded; the run's totals reflect it.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunEmployeeAction"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "get": {
        "operationId": "pay.run_employee_action.list",
        "summary": "List the run's per-employee exceptions",
        "description": "Every recorded action on the run with its actor, timestamp and mandatory comment — the exception register a reviewer reads before approving, and the audit artifact afterwards. Sort whitelist: `created_at`, `-created_at`, `action`, `employee_id`. Default `-created_at`.\n",
        "tags": [
          "pay",
          "run_employee_action"
        ],
        "x-token": "pay.run_employee_action.list",
        "x-realizes-features": [
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.run_employee_actions"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "action",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/RunEmployeeActionType"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: `created_at`, `-created_at`, `action`, `employee_id`. Default `-created_at`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of per-employee run actions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunEmployeeActionPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/employee-actions/bulk": {
      "post": {
        "operationId": "pay.run_employee_action.set_bulk",
        "summary": "Apply one per-employee verb to a whole cohort, in one transaction",
        "description": "**Bulk is a first-class verb, not a loop in the browser** (ADR 0069 §(d)). Holding a department is ONE call, ONE transaction and ONE auditable decision.\n\nThe `cohort` is resolved **server-side against the run's own slips**: department ids, org-unit ids, pay models or an explicit employee list, ANDed together, or `{\"all\": true}` for the whole run. Placement (`department_id`, `org_unit_id`) is read from the employee's **current** record — the same basis as every other payroll cohort read, with #1132 tracking snapshotting it — while `pay_model` comes from the compensation row **effective at the run's `pay_period_end`**, because that is the row that priced the slip. A cohort naming a department this run does not pay resolves to the empty set and answers `applied: 0`; it is not an error.\n\nEvery eligible employee gets their own `pay.run_employee_actions` row **and their own `audit.audit_log` entry** — a bulk hold is not one decision about a department, it is *n* decisions about *n* people — plus one summary row recording the act as the operator performed it. An employee the verb cannot legally touch is **skipped and reported** in `skipped[]` with a machine-readable reason, never silently dropped and never a reason to fail the rest.\n\nStatus legality, the `If-Match` handshake and the post-`PUBLISHED` behaviour are exactly `pay.run_employee_action.set`'s, with **one deliberate difference: bulk NEVER restores a cancelled payslip.** The single-employee `PAY` un-cancels a slip a prior `VOID` set aside, because that is a deliberate act about one named person; doing it across a cohort would silently REVERSE every void in the selection, and the first anyone would know of it is the bank file. A `CANCELLED` slip is therefore skipped with `SLIP_CANCELLED` for **every** verb.\n\nA bulk `PARTIALLY_PAY` takes a **`partial_fraction` only**: \"half of everyone's net\" is a policy, while one flat amount applied to 200 different nets is an accident waiting to be reconciled. The cohort is capped at **2 000** resolved employees — a guard on the transaction, not on the operator's ambition — and the cap is enforced in the database (`LIMIT cap + 1`), so a mis-typed filter matching 40 000 people costs one bounded read rather than 40 000 rows marshalled in to be counted and thrown away; a wider selection is a `422` naming the cap.\n",
        "tags": [
          "pay",
          "run_employee_action"
        ],
        "x-token": "pay.run_employee_action.set_bulk",
        "x-realizes-features": [
          "PAY-F09",
          "PAY-F12"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.run_employee_actions",
          "pay.payslip_disbursements",
          "pay.payroll_runs",
          "pay.payslips",
          "people.employees",
          "pay.employee_compensation",
          "audit.audit_log"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RunEmployeeActionBulkInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The cohort was resolved and the verb applied to every eligible member.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunEmployeeActionBulkResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/disbursements": {
      "get": {
        "operationId": "pay.payslip_disbursement.list",
        "summary": "The cycle's payment ledger — per employee, this cycle and any balance due from earlier ones",
        "description": "**The release table's read** (ADR 0069 §(c)/(g), db-docs/07 §1.10), and the only place the whole payment picture of a cycle is assembled: this cycle's obligation per employee, the verb an operator last applied, whether the bank details are ready to receive money, and — from the **same ledger**, with no carry and no drift — every still-open obligation that employee has from an **earlier** cycle.\n\n`prior_obligations[]` is computed live: the same employee's ledger rows on **other PUBLISHED runs of the same pay group with an earlier period**, in state `PENDING`/`HELD`/`PARTIAL` with `remaining_amount > 0`, oldest period first. Nothing was ever carried forward, no `ARREAR` input was raised and no second row duplicates the amount — the obligation is simply still open, which is also why **a prior balance is never re-taxed**: it never re-enters gross. A `HELD` prior comes back with `held: true` and is **listed but not releasable** — releasing an amount a human deliberately held would silently overturn the hold.\n\n**A privileged `SALARY` read.** It lists every employee's net and what is still owed to them, so the service writes an `audit.access_log` `DATA_ACCESS` row in the same transaction as the query, on the same terms as the other per-employee money reads. `bank_account_ready` is deliberately a **boolean**: the operator needs to know a VERIFIED primary account exists, and never needs the account number to decide whether to release.\n\nA slip with no ledger row yet (a run populated before migration `0217`) reads as `PENDING` with zero amounts rather than being omitted — a payment table that silently drops people is worse than one that shows an unstarted row.\n",
        "tags": [
          "pay",
          "payslip_disbursement"
        ],
        "x-token": "pay.payslip_disbursement.list",
        "x-realizes-features": [
          "PAY-F12",
          "PAY-F11"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payslip_disbursements",
          "pay.payslips",
          "pay.payroll_runs",
          "pay.run_employee_actions",
          "people.employees",
          "people.bank_accounts",
          "org.departments",
          "pay.employee_compensation",
          "audit.access_log"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/DisbursementState"
            }
          },
          {
            "name": "department_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "pay_model",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "MONTHLY_SALARY",
                "DAILY_WAGE",
                "PIECE_RATE"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          }
        ],
        "responses": {
          "200": {
            "description": "Page of per-employee disbursement rows, ordered by employee number.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayslipDisbursementPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/cost-summary": {
      "get": {
        "operationId": "pay.payroll_run.cost_summary",
        "summary": "The cycle estimate — one run's cost grouped by department, cost centre, pay model, legal entity or org unit",
        "description": "**The estimate the cycle workspace is reached for** (ADR 0069 §(h), fsd-docs/06 §W12 `PAY-S33`, db-docs/07 §1.1): *\"pick the period, see the cost across departments, adjust heads.\"* It is legal on **any** run status **including a provisional `DRAFT`**, which is the whole reason it exists — an estimate that only appears after `EXECUTED` is not an estimate.\n\n**Why this is a second operation and not a parameter on `pay.payslip.cost_summary`.** That read counts `EXECUTED`/`PUBLISHED` runs only, deliberately: a *cost base* that moves when somebody re-previews is worthless. That rule is right there and exactly wrong here. Same axes, opposite status rule, run-scoped instead of selection-scoped — and operation IDs are append-only (`api-docs/00 §4`), so a live consumer's contract is never re-shaped to add a mode.\n\n**Five axes.** `department` · `cost_centre` (`org.departments.cost_center` — the accounting axis, the same one `pay.payslip.cost_centre_summary` has always known) · `pay_model` (the employee's `pay.employee_compensation.pay_model` effective on the run's `pay_period_end`, resolved through a LATERAL) · `legal_entity` · `org_unit`. `cost_centre` and `pay_model` return `id: null` and a `label` of `{\"en\": <key>}`: neither is an entity with an identity, and the surface localizes from `key` rather than the server inventing an Arabic name for a tenant's own cost-centre string.\n\n**`basis: CURRENT_EMPLOYEE_ASSIGNMENT`.** The axis is resolved from the employee's assignment **now**, not as at the pay period — a re-org between the period and the read moves the money to the new department. Same basis as `pay.payslip.cost_summary`, same open issue (**#1132**: a period-accurate snapshot needs an assignment history the schema does not keep). It is named in the payload so a consumer knows which question the numbers answer.\n\n**Nothing is quietly dropped, and no total is a fiction.** A payslip whose employee has no value on the chosen axis groups under an explicit `Unassigned` row. `excluded.cancelled_slips` counts what `VOID`/`HOLD` took off the run and `excluded.employees_without_slip` counts the pay group's population — the same predicate populate rosters from — that has no slip yet, which on a never-populated draft is *everybody* and is the honest answer to \"why is this zero\". Currencies are **never summed**: `totals` is per currency with no grand total, and `percent_of_total` is within one currency.\n\n**Disbursement figures come from the ledger** (`pay.payslip_disbursements`, §1.10) by LEFT JOIN, so a slip with no ledger row yet reads as `PENDING` at zero rather than vanishing. `prior_open_balance_*` is the same **live** read of still-open obligations on earlier PUBLISHED runs of the pay group that the release table uses — one query, so the estimate and the release table never disagree about what is still owed.\n\n**A privileged `SALARY` read.** It sums every employee's gross, employer cost and net for a whole run, so the service writes an `audit.access_log` `DATA_ACCESS` row in the same transaction as the query. Gated on its own token, on the same data class as `pay.payroll_run.get`.\n",
        "tags": [
          "pay",
          "payroll_run"
        ],
        "x-token": "pay.payroll_run.cost_summary",
        "x-realizes-features": [
          "PAY-F12",
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_runs",
          "pay.payslips",
          "pay.payslip_disbursements",
          "pay.employee_compensation",
          "pay.pay_periods",
          "people.employees",
          "org.departments",
          "org.org_units",
          "org.legal_entities",
          "audit.access_log"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "group_by",
            "in": "query",
            "required": true,
            "description": "The grouping axis. `cost_centre` and `pay_model` are offered HERE and not on `pay.payslip.cost_summary`: the first is the cost-centre axis that operation deliberately left to `pay.payslip.cost_centre_summary`, and the second is only meaningful against a single run's period.\n",
            "schema": {
              "$ref": "#/components/schemas/RunCostGroupBy"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The run's cost, grouped on the requested axis, with per-currency totals and the exclusions the figures depend on. No `ETag`: this is a derived aggregate, not a versioned resource.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunCostSummaryResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/release-batches": {
      "post": {
        "operationId": "pay.payroll_release_batch.create",
        "summary": "Release money — one batch, one bank advice, prior balances settled oldest first",
        "description": "**The only operation in GroundIT that declares money to have left** (ADR 0069 §(f), db-docs/07 §1.10). The run must be `PUBLISHED`: money is released only against payslips that are already evidence.\n\n**MC-2, and the run's submitter may not release it.** The kernel runs the step-up leg and then the maker≠checker leg against `payroll_runs.submitted_by`, exactly as `execute` and `publish` do, and writes the `PAYROLL_DECISION` evidence row on the same transaction — a release that produces no evidence never commits. The response is beneficiary-shaped, so the call also writes an `audit.access_log` `DATA_ACCESS` row with `data_class = BANK`.\n\n**What a batch pays, per employee in the cohort.** *This cycle:* `partial_release_amount ?? remaining_amount` of this run's ledger row when it is `PENDING`/`PARTIAL`; **zero** when it is `HELD`, `OUTSIDE_PAYROLL`, `VOID` or already `RELEASED`. *Prior balance:* per `prior_balance` — `NONE`, `ALL`, or a `CUSTOM` per-employee amount — drawn from that employee's still-open obligations on **other PUBLISHED runs of the same pay group with an earlier period**, allocated **oldest period first**, the last one partially. A `HELD` prior is never drawn on: releasing an amount a human deliberately held would silently overturn the hold. A `CUSTOM` amount greater than the employee's open prior balance is a `422`, never a clamp.\n\n**A zero line is a skip, never a row.** Every employee who receives no line comes back in `skipped[]` with the state that explains it (`HELD` · `OUTSIDE_PAYROLL` · `VOID` · `ALREADY_RELEASED` · `NO_LEDGER_ROW` · `NOTHING_PAYABLE`).\n\n**A hold suppresses the whole person, not just this cycle's figure.** An employee whose **this-cycle** row is `HELD` gets **no line at all** — skipped with reason `HELD` — *even under `prior_balance: ALL`/`CUSTOM` and even when they carry an open balance from an earlier cycle*. `HOLD` means *\"do not pay this person now\"*, and paying last month's arrears to somebody whose pay was deliberately stopped this month would route money around the hold. Only an explicit `PAY` (un-hold) makes them payable again. The other three non-releasable states are statements about **this cycle only** and do NOT suppress a prior settlement — `OUTSIDE_PAYROLL` (this month went out another way), `VOID` (this month's slip was cancelled) and `RELEASED` (this month is already paid; a second batch settling their prior balance is the normal case) — so such an employee may still receive a line carrying `this_cycle_amount: \"0.00\"` and a null `this_cycle_payslip_id`.\n\n**One transaction, and it reconciles or it refuses.** The batch, its lines, its settlements, the `SELECT … FOR UPDATE` ledger updates and the bank-advice file commit together. Σ lines = Σ settlements = `total_amount` is then **re-read from the database** — not re-summed over the objects that produced it — and a disagreement refuses with `409`: a bank file that does not equal its own ledger is never written. The advice reuses the existing machinery (the primary-`VERIFIED` account gate, the negative/zero rules, the deterministic CSV renderer, the in-transaction upload), so an unverified beneficiary refuses the whole release with `422` rather than paying it.\n\n`Idempotency-Key` replays the same batch and never a second payment; `If-Match` is the run's version.\n",
        "tags": [
          "pay",
          "payroll_release_batch"
        ],
        "x-token": "pay.payroll_release_batch.create",
        "x-realizes-features": [
          "PAY-F12",
          "PAY-F11"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_release_batches",
          "pay.payroll_release_batch_lines",
          "pay.payroll_release_settlements",
          "pay.payslip_disbursements",
          "pay.bank_advice_files",
          "pay.payroll_runs",
          "pay.payslips",
          "people.employees",
          "people.bank_accounts",
          "pay.employee_compensation",
          "xc.object_refs",
          "audit.audit_log",
          "audit.access_log",
          "audit.decision_artifacts"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.payroll_release_batch.released",
        "x-rls-scope": "tenant",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReleaseBatchCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The batch, its lines with the obligations each settled, the skipped employees and the cycle's refreshed disbursement summary.",
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReleaseBatchResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "get": {
        "operationId": "pay.payroll_release_batch.list",
        "summary": "The cycle's release batches, newest batch first",
        "description": "Every act of releasing money on this run, with the bank-advice file each produced (identity and hash only — a presigned handle is minted solely by `pay.bank_advice.download`, so every handout of a full-account-number file stays individually logged). Privileged `BANK` read: logged to `audit.access_log`.\n",
        "tags": [
          "pay",
          "payroll_release_batch"
        ],
        "x-token": "pay.payroll_release_batch.list",
        "x-realizes-features": [
          "PAY-F12",
          "PAY-F11"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_release_batches",
          "pay.bank_advice_files",
          "pay.payroll_runs",
          "audit.access_log"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "The run's release batches, newest batch number first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReleaseBatchList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/release-batches/{batchId}": {
      "get": {
        "operationId": "pay.payroll_release_batch.get",
        "summary": "One release batch — its lines, the obligations they settled, and its bank advice",
        "description": "The batch with `lines[]` (one per employee — this row **is** the bank-advice line) and `settlements[]` (one per line × obligation, carrying `is_prior_cycle` and the frozen `obligation_period_code`). This is how both cycles tell the truth: the batch can say which obligations it discharged, and the old cycle can say *\"paid in ‹period›\"*. Privileged `BANK` read: logged to `audit.access_log`.\n",
        "tags": [
          "pay",
          "payroll_release_batch"
        ],
        "x-token": "pay.payroll_release_batch.get",
        "x-realizes-features": [
          "PAY-F12",
          "PAY-F11"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payroll_release_batches",
          "pay.payroll_release_batch_lines",
          "pay.payroll_release_settlements",
          "pay.bank_advice_files",
          "people.employees",
          "audit.access_log"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "batchId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The batch, its lines and its settlements.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReleaseBatchDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/arrear-receipts": {
      "get": {
        "operationId": "pay.arrear_receipt.list",
        "summary": "My arrear receipts — \"3 Jun regularization → ₹412 in your August payslip\"",
        "description": "The employee's own `pay.arrear_receipts` (ADR 0030 §(d)), each carrying an **employee-visible receipt text** and a status of `PENDING → SCHEDULED → PAID`. Retroactivity stops being an unexplained delta and becomes something the person being paid can read.\n\nThe amount comes from the **diff engine**: the origin period is recomputed through `pay-calc` under the new facts and diffed against the **immutable published payslip**, then realized forward as `ARREARS` earning lines against their `arrear_period` — **never a re-run of the closed period, never an edit of a published slip**. `source_type` ∈ `REGULARIZATION_POST_LOCK` · `ATTENDANCE_AMENDMENT` · `COMP_REVISION_RETRO` · `STRUCTURE_RETRO`.\n",
        "tags": [
          "pay",
          "arrear_receipt"
        ],
        "x-token": "pay.arrear_receipt.list",
        "x-realizes-features": [
          "PAY-F09",
          "PAY-F03"
        ],
        "x-screens": [
          "PAY-S26",
          "PAY-S01"
        ],
        "x-touches-entities": [
          "pay.arrear_receipts",
          "pay.earnings",
          "pay.payslips"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/ArrearReceiptStatus"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: `created_at`, `-created_at`, `status`. Default `-created_at`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of the caller's own arrear receipts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArrearReceiptPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/arrear-receipts/admin": {
      "get": {
        "operationId": "pay.arrear_receipt.list_admin",
        "summary": "Tenant-wide arrear register (what retroactivity is queued against which run)",
        "description": "Finance's view of every `pay.arrear_receipts` row — filterable by target run, origin period, source type and status. Widened `x-rls-scope: tenant` relative to the self-scoped `pay.arrear_receipt.list`. This is where an operator answers *\"what is the next run carrying from previous months, and why\"* before approving it. Sort whitelist: `created_at`, `-created_at`, `computed_amount`, `status`.\n",
        "tags": [
          "pay",
          "arrear_receipt"
        ],
        "x-token": "pay.arrear_receipt.list_admin",
        "x-realizes-features": [
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.arrear_receipts",
          "pay.payroll_runs",
          "pay.pay_periods"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "target_run_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "origin_period_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "source_type",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/ArrearSourceType"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/ArrearReceiptStatus"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: `created_at`, `-created_at`, `computed_amount`, `status`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tenant-wide page of arrear receipts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArrearReceiptPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payslips/{id}/explanation": {
      "get": {
        "operationId": "pay.pay_explanation.get",
        "summary": "\"Why this number\" — the frozen causal chain behind my payslip and its lines",
        "description": "**ADR 0031.** The employee-side drill-in (`PAY-S26`): tap a line, get its derivation in the employee's own language. Returns the `pay.pay_explanations` chains for the payslip and every earning and deduction on it — an **ordered list of rule steps** mirroring the ADR 0029 §(d) order of operations (segment → component evaluation → LOP → wage floor → additive → statutory → netting). Read top to bottom it is a derivation; read bottom-up it is an explanation.\n\nEach step is `{ seq, rule_code, rule_label: { en, ar }, inputs: [{ kind, ref, value }], output_value }`. `rule_label` is **locale-keyed from day one** (ADR 0012), so a chain rendered for a KSA employee is Arabic without a translation pass over stored prose — though **no KSA rule codes and no Arabic rule-label content are delivered in this wave**. The last step's `output_value` equals the line's `amount`; that is checkable, and it is checked.\n\n**The chain is never re-derived.** By the time anyone asks, the compliance pack may be re-versioned, the structure superseded and the finalization amended — a re-run would answer *\"what would we compute today\"*, a different and dangerous question. The chain is the **frozen truth of what actually computed**, and it inherits the payslip's immutability trigger on publish.\n\nChains **reference upstream facts by id, never by embedding**, and never carry another employee's data: an employee-facing chain must be renderable to that employee with no redaction pass, which is the design constraint the `{ kind, ref, value }` shape enforces. Lines not produced by `pay-calc` (surviving manual adjustments, imported historical slips) carry a single-step `MANUAL_ENTRY` chain naming the actor and reason — honest, but thin.\n",
        "tags": [
          "pay",
          "pay_explanation"
        ],
        "x-token": "pay.pay_explanation.get",
        "x-realizes-features": [
          "PAY-F09",
          "PAY-F03"
        ],
        "x-screens": [
          "PAY-S26"
        ],
        "x-touches-entities": [
          "pay.pay_explanations",
          "pay.payslips",
          "pay.earnings",
          "pay.deductions"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "target_type",
            "in": "query",
            "required": false,
            "description": "Narrow the bundle to one class of explained row.",
            "schema": {
              "$ref": "#/components/schemas/ExplanationTargetType"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The payslip's explanation bundle.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayExplanationBundle"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payslips/admin/{id}/explanation": {
      "get": {
        "operationId": "pay.pay_explanation.get_admin",
        "summary": "HR-side attribution — the same chain, for variance triage",
        "description": "**One attribution layer, two surfaces** (ADR 0031 §(c)). The same `pay.pay_explanations` data the employee sees, read by a payroll manager triaging a flagged `pay.run_variances` row — the two surfaces differ in presentation and in classification-driven scoping, **not in data**, and building the attribution layer twice is how it drifts. Widened `x-rls-scope: tenant` relative to the self-scoped `pay.pay_explanation.get`, and accepts a `target_id` so a variance flag can drill straight to the line that moved.\n\n**This is a privileged read.** Explanations are `SALARY`-classified exactly like every other `pay.*` read (`security-docs/04 §4` — *\"every `pay.*` resource is compensation-bearing by construction\"*), so an HR user reading an employee's derivation **writes an access-log row with a catalogued `purpose`**.\n\nChains are queryable because `rule_code` is a **closed, versioned, append-only vocabulary**: *\"every employee whose net moved because of the wage-floor adjustment this month\"* is a filter, not a scan of prose. Together with `engine_version` and the pack version in `source_refs`, every chain is reproducible — the exact engine and the exact pack that produced a two-year-old payslip are named on the payslip itself.\n\n**Explicit scope cut: no LLM or natural-language surface ships in this wave** (ADR 0031 §(f)). No generated prose, no chat, no auto-suggested regularization. A language layer over unstructured explanation strings would be a plausible-sounding guess about money, which is the one thing a payroll system must never produce; the deferred NL layer consumes these chains as substrate precisely because they are structured, id-referenced and frozen.\n",
        "tags": [
          "pay",
          "pay_explanation"
        ],
        "x-token": "pay.pay_explanation.get_admin",
        "x-realizes-features": [
          "PAY-F09",
          "PAY-F03"
        ],
        "x-screens": [
          "PAY-S33",
          "PAY-S26"
        ],
        "x-touches-entities": [
          "pay.pay_explanations",
          "pay.payslips",
          "pay.earnings",
          "pay.deductions",
          "pay.run_variances",
          "audit.access_log"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "target_type",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/ExplanationTargetType"
            }
          },
          {
            "name": "target_id",
            "in": "query",
            "required": false,
            "description": "Drill straight to one explained row — the earning, deduction or variance a flag points at.",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The explanation bundle for the requested payslip (privileged read; access-logged).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayExplanationBundle"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-what-if": {
      "post": {
        "operationId": "pay.tax_what_if.compute",
        "summary": "Compare both tax regimes against unsaved declaration amounts, from one call",
        "description": "**The regime what-if (`TAX-S01`'s \"short comparison\", `TAX-S02`'s live editor).** Answers, for the caller's OWN employment, what taxable income · total tax · monthly TDS · monthly take-home look like under **both** the `OLD` and the `NEW` regime — computed by `packages/pay-calc` (`computeTaxRegimeWhatIf`), the same engine `pay.payroll_run.populate` runs, so the number a simulator shows and the number a payslip shows come from one arithmetic.\n\n**BOTH COLUMNS COME FROM ONE CALL, AGAINST ONE RESOLVED PACK.** That is the whole reason this is a single operation rather than a regime parameter: two calls could straddle a pack re-version and silently compare two different rulebooks. `pack_version` is therefore identical on both columns **by construction** (one `resolvePack`, one input record, only `statutoryProfile.incomeTax.regime` varies) and is additionally asserted server-side before the response is written — a mismatch is a 500-class engine invariant failure, never a rendered pair.\n\n**`declaration_items` is the LIVE, UNSAVED editor state.** Nothing is read from `tax.tax_declarations`: the point of a what-if is that it answers for what the employee is typing, not for what they last saved, and nothing here is persisted. Each item's typed `amount` is fed to the engine as both the eligible and the verified figure, so the answer cannot depend on a declaration window the caller never sent. A `section` the resolved pack does not permit under a regime simply contributes nothing to that column — which is exactly why a typed `SEC_80C` moves the `OLD` column and leaves `NEW` untouched.\n\n**`regime` is the caller's declared regime — an anchor, not a filter.** The response always carries both columns; the field states which one the employee is currently on so the request records the comparison's baseline. It does not narrow the response, and two requests differing only in `regime` return byte-identical bodies.\n\n**`projection_basis: ANNUALISED_CURRENT_STRUCTURE` is the only basis, and it is stated rather than assumed** so a future second basis cannot silently change what old numbers meant. It means: the pay structure and compensation in force **today**, run as one full, unprorated month with no loss of pay, annualised by twelve, with no year-to-date payroll history folded in (`remaining_payroll_months = 12`, `tax_deducted_to_date = 0`). Monthly TDS is therefore the annual liability spread evenly, not a catch-up figure. Any other value is a `422`.\n\n**Refusals are honest, never a fabricated column.** An employee on the `DAILY_WAGE` or `PIECE_RATE` pay-model axis (ADR 0033 §(a)) has no annual structure to annualise; an employee with no compensation row, no published pay structure, no bound compliance pack, or a pack carrying no `incomeTax` section (ADR 0005 config-not-code: the engine refuses rather than guessing a statutory rate) all answer `409`. `x-market` is `both` because the operation itself hardcodes nothing: which regimes exist, and whether income tax exists at all, is pack data — a KSA pack carries no `incomeTax` section and the operation refuses there, which is the config-gate rather than a jurisdiction branch.\n\n**Not idempotency-keyed, and not audited.** It is a pure computation over the caller's own data that writes nothing, so repeating it is free and an `Idempotency-Key` would be ceremony (`04 §1` keys retryable WRITES). Sensitivity tags are read-side only (`security-docs/04 §4`) and this `POST` is not one of the named exceptions, so it raises no `audit.access_log` row — the same treatment the employee's own `pay.payslip.get` receives.\n",
        "tags": [
          "pay",
          "tax_what_if"
        ],
        "x-token": "pay.tax_what_if.compute",
        "x-realizes-features": [
          "TAX-F01",
          "TAX-F02",
          "PAY-F02"
        ],
        "x-screens": [
          "TAX-S01",
          "TAX-S02"
        ],
        "x-touches-entities": [
          "pay.employee_compensation",
          "org.pay_structures",
          "org.pay_components",
          "org.compliance_packs",
          "org.legal_entities",
          "org.work_locations",
          "people.employees"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TaxWhatIfRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Both regime columns, computed against one pack version.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxWhatIfResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-what-if/admin": {
      "post": {
        "operationId": "pay.tax_what_if.compute_admin",
        "summary": "Project another employee's TDS impact for Finance proof verification",
        "description": "TAX-S06's privileged sibling of pay.tax_what_if.compute. It runs the same pay-calc engine and request semantics for the explicit employee_id, without widening the self operation. The read is SALARY-classified and writes audit.access_log evidence; declaration amounts are not copied into the audit record. A missing compensation, pack, or income-tax section returns 409 rather than fabricating a projection.\n",
        "tags": [
          "pay",
          "tax_what_if"
        ],
        "x-token": "pay.tax_what_if.compute_admin",
        "x-realizes-features": [
          "TAX-F03",
          "PAY-F02"
        ],
        "x-screens": [
          "TAX-S06"
        ],
        "x-touches-entities": [
          "pay.employee_compensation",
          "org.pay_structures",
          "org.pay_components",
          "org.compliance_packs",
          "people.employees",
          "audit.access_log"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdminTaxWhatIfRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Both regime columns plus the explicit projection metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminTaxWhatIfResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/employees/{employee_id}/compensation": {
      "get": {
        "operationId": "pay.employee_compensation.list",
        "summary": "Read an employee's effective-dated compensation history",
        "description": "The employee's whole compensation chain — the effective-dated series of CTC/basic/structure assignments the payroll engine resolves per employee per run (db 07 §1.1 `pay.employee_compensation`). At most one row is open (`effective_to = null`); every earlier row is closed, so the series reads as a continuous history with no gaps and no overlaps.\n\n**First surface for this table.** `pay.employee_compensation` shipped in migration `0032` and had no API at all: no operation in this corpus read or wrote it, which is exactly why the `PPL-S14` employee-360 **Compensation** tab had nothing behind it and rendered an explicit empty state pointing at the Pay workspace (design-docs/04 `G-20`①). This operation is the read half of closing that gap; the guided onboarding COMPENSATION stage and `pay.employee_compensation.create` are the write half.\n\n**Deliberately NOT cursor-paged.** An employee's compensation history is a small bounded series — one row per revision over a career, typically single digits — and it can only be read *correctly* as a whole: which row was effective on a given pay period is a question about the chain, not about any one row, so handing the caller an arbitrary window of it would invite exactly the wrong reading. Returned sorted by `effective_from` **descending** (current record first), with the employee's derived `currency_code` hoisted onto the envelope because a legal entity operates in a single currency and repeating it per row would imply it could vary.\n\n**The read is privileged and carries `SALARY` sensitivity** (security-docs/04 §4 — every `pay.*` read is compensation-bearing by construction, so the token is tagged and `is_privileged`). It is tenant-scoped rather than self-scoped: this is the HR/Finance view of somebody's pay, not the employee's own payslip surface, which lives on `pay.payslip.list`.\n",
        "tags": [
          "pay",
          "employee-compensation"
        ],
        "x-token": "pay.employee_compensation.list",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PPL-S20",
          "PPL-S14"
        ],
        "x-touches-entities": [
          "pay.employee_compensation"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "security": [
          {
            "bearerJWT": []
          }
        ],
        "parameters": [
          {
            "name": "employee_id",
            "in": "path",
            "required": true,
            "description": "UUIDv7 of the `people.employees` row whose compensation chain is being read.",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The employee's full compensation chain, current record first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeCompensationHistory"
                },
                "examples": {
                  "two_records": {
                    "summary": "A hire record closed by an annual revision",
                    "value": {
                      "employee_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a40",
                      "currency_code": "INR",
                      "records": [
                        {
                          "id": "018f4d90-1b22-7e60-8c11-9a3f2e5b7c02",
                          "employee_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a40",
                          "legal_entity_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a34",
                          "pay_structure_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a80",
                          "pay_structure_version": 4,
                          "effective_from": "2027-04-01",
                          "effective_to": null,
                          "ctc_amount": "1980000.00",
                          "basic_amount": "990000.00",
                          "currency_code": "INR",
                          "revision_reason": "ANNUAL_REVISION",
                          "notes": "FY27-28 increment cycle, 10%.",
                          "created_at": "2027-03-28T05:11:02.400Z",
                          "created_by": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a90",
                          "version": 0
                        },
                        {
                          "id": "018f4d90-1b22-7e60-8c11-9a3f2e5b7c01",
                          "employee_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a40",
                          "legal_entity_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a34",
                          "pay_structure_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a80",
                          "pay_structure_version": 3,
                          "effective_from": "2026-08-03",
                          "effective_to": "2027-03-31",
                          "ctc_amount": "1800000.00",
                          "basic_amount": "900000.00",
                          "currency_code": "INR",
                          "revision_reason": "HIRE",
                          "notes": "Offer-letter terms, band L4.",
                          "created_at": "2026-07-28T04:30:12.771Z",
                          "created_by": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a91",
                          "version": 1
                        }
                      ]
                    }
                  },
                  "none_yet": {
                    "summary": "An employee with no compensation record (pre-0064 hires)",
                    "value": {
                      "employee_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a41",
                      "currency_code": "SAR",
                      "records": []
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "operationId": "pay.employee_compensation.create",
        "summary": "Record a new compensation revision (closes the open row)",
        "description": "Open a new effective-dated compensation record for an employee, **closing the currently open one in the same transaction** (`effective_to = effective_from - 1 day`). This is the first writer this table has ever had — `pay.employee_compensation` shipped in migration `0032` and nothing wrote it, which is why the \"one open row per employee\" invariant db-docs/07 §1.1 has always specified only became a database fact in migration `0064`. Together with `pay.employee_compensation.list` this closes the write half of design-docs/04 gap `G-20`①.\n\n**Validation, precisely:**\n· **Money is a decimal STRING, never a float.** A JSON number cannot represent a rupee or a halala exactly, and a payroll figure that has been through a binary double is not the figure anyone agreed to (db-docs/00 §6). Both amounts must satisfy `^\\d+(\\.\\d{1,2})?$`.\n· `basic_amount <= ctc_amount` and both `>= 0` — the DB CHECKs from migration `0033`, surfaced as a `422` with rule `cross-field` rather than a 500.\n· **`currency_code` is derived from the employee's legal entity and is NOT accepted from the caller.** Supplying it is a `422`. A legal entity operates in exactly one currency (db-docs/00 §6), so accepting a currency on the wire would add no expressiveness and one catastrophic failure mode: an INR figure recorded as SAR. Deriving it makes that mix-up impossible rather than merely unlikely.\n· A supplied `pay_structure_id` must name an `org.pay_structures` row that is **`PUBLISHED`** and belongs to the **same legal entity** as the employee; its `version_no` is stamped into `pay_structure_version`, so a later structure version cannot silently re-interpret an existing assignment (the same version-stamping discipline payroll runs use on publish).\n· **`effective_from` must be strictly after the open row's `effective_from`.** Back-dating over the live record is a `422` with rule `cross-field`, not a silent overlap — a chain that overlaps cannot answer \"what was this employee's compensation for this period\", which is the only question the table exists to answer. Corrections to an already-closed period are a new `CORRECTION` record, never an edit.\n· The close-then-open pair is one transaction, so **at most one row is ever open**; the partial-unique index `employee_compensation_one_open_per_employee_key` (migration `0064`) is the backstop that turns that from a service convention into a database guarantee.\n\n**Maker-checker: `MC-0` today.** Bands attach to the approval-consuming token, never the `.create`/`.submit` side that raises the request (security-docs/04 §2) — so this operation is unbanded, while the analogous `engage.salary_revision.approve` picks up the `MC-1` default from the `approve` suffix rule. If the product owner wants dual control on the **hire-time** CTC (which reaches the ledger without ever passing an `approve` token, via the onboarding COMPENSATION stage), that needs a named `mc_rules` entry in `security-docs/seed/classification-rules.yaml` plus a §2.1 explicit-override row. Recorded here as an **open item**, not asserted as a decision.\n",
        "tags": [
          "pay",
          "employee-compensation"
        ],
        "x-token": "pay.employee_compensation.create",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PPL-S20",
          "PPL-S14"
        ],
        "x-touches-entities": [
          "pay.employee_compensation",
          "people.employees",
          "org.pay_structures"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "security": [
          {
            "bearerJWT": []
          }
        ],
        "parameters": [
          {
            "name": "employee_id",
            "in": "path",
            "required": true,
            "description": "UUIDv7 of the `people.employees` row this compensation record binds to.",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmployeeCompensationCreateInput"
              },
              "examples": {
                "hire": {
                  "summary": "Opening record at hire, structure assigned",
                  "value": {
                    "effective_from": "2026-08-03",
                    "ctc_amount": "1800000.00",
                    "basic_amount": "900000.00",
                    "revision_reason": "HIRE",
                    "pay_structure_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a80",
                    "notes": "Offer-letter terms, band L4."
                  }
                },
                "annual_revision": {
                  "summary": "Annual increment — closes the open row",
                  "value": {
                    "effective_from": "2027-04-01",
                    "ctc_amount": "1980000.00",
                    "basic_amount": "990000.00",
                    "revision_reason": "ANNUAL_REVISION",
                    "pay_structure_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a80",
                    "notes": "FY27-28 increment cycle, 10%."
                  }
                },
                "no_structure": {
                  "summary": "No published structure yet — CTC/basic only",
                  "value": {
                    "effective_from": "2026-09-01",
                    "ctc_amount": "240000.00",
                    "basic_amount": "144000.00",
                    "revision_reason": "HIRE",
                    "pay_structure_id": null
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new open compensation record, naming the row it closed.",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeCompensationCreated"
                },
                "examples": {
                  "revision": {
                    "summary": "A revision that closed the prior record",
                    "value": {
                      "id": "018f4d90-1b22-7e60-8c11-9a3f2e5b7c02",
                      "employee_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a40",
                      "legal_entity_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a34",
                      "pay_structure_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a80",
                      "pay_structure_version": 4,
                      "effective_from": "2027-04-01",
                      "effective_to": null,
                      "ctc_amount": "1980000.00",
                      "basic_amount": "990000.00",
                      "currency_code": "INR",
                      "revision_reason": "ANNUAL_REVISION",
                      "notes": "FY27-28 increment cycle, 10%.",
                      "created_at": "2027-03-28T05:11:02.400Z",
                      "created_by": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a90",
                      "version": 0,
                      "closed_previous_id": "018f4d90-1b22-7e60-8c11-9a3f2e5b7c01"
                    }
                  },
                  "first_record": {
                    "summary": "The employee's first-ever record — nothing to close",
                    "value": {
                      "id": "018f4d90-1b22-7e60-8c11-9a3f2e5b7c01",
                      "employee_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a40",
                      "legal_entity_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a34",
                      "pay_structure_id": null,
                      "pay_structure_version": null,
                      "effective_from": "2026-08-03",
                      "effective_to": null,
                      "ctc_amount": "1800000.00",
                      "basic_amount": "900000.00",
                      "currency_code": "INR",
                      "revision_reason": "HIRE",
                      "notes": null,
                      "created_at": "2026-07-28T04:30:12.771Z",
                      "created_by": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a91",
                      "version": 0,
                      "closed_previous_id": null
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/employees/{employee_id}/compensation/{compensation_id}": {
      "patch": {
        "operationId": "pay.employee_compensation.update",
        "summary": "Correct an existing compensation record (writes a revision-history row)",
        "description": "Correct a compensation record **in place**, recording what changed, from what, to what, and why. This is not `pay.employee_compensation.create` with a different verb: that operation is close-then-open, and everything it can express is \"**from this date**, the employee's pay is different\". A record committed with the wrong figure or the wrong start date is not a pay change — asserting one is a lie the payroll engine then believes, because it resolves the row effective on the period and would pay the wrong number for the periods between the mistake and the \"revision\". Until this operation a mistake had no remedy at all, and a **closed** row had none even in principle.\n\n**Why it exists now.** The bulk compensation import commits opening balances for a whole population in one transaction, which makes \"the figure we just committed is wrong\" an ordinary Monday rather than an edge case, and the correction path has to exist underneath it. Raises and promotions stay `pay.employee_compensation.create`; `engage.salary_revision.*` — the proposal-and-approval workflow — is a third, unrelated thing and none of the three substitutes for the others.\n\n**Every correction writes a `pay.employee_compensation_revisions` row** (migration `0175`) carrying the wire field names it changed and their `before`/`after` values, the caller's `correction_reason`, the acting principal and a per-record `revision_no`. That row and not `audit.audit_log` is where the figures go, deliberately: `db-docs/15 §1` bans raw salary figures from the audit plane and §5 exempts that plane from DPDP/PDPL erasure, so a CTC written there would outlive a deletion that emptied `pay` — while payroll still has to be able to answer \"what did we pay them under the wrong number\". `pay` **is** in scope for erasure, which is the whole point. The audit row is written too, as metadata only: who, when, on which record, under which revision number and which changed fields, against which `pay_structure_version` — never an amount, and never the free-text reason either, because free text about a pay change is precisely where somebody types the figure.\n\n**Validation, precisely:**\n· **Both write-safety headers are required.** `If-Match` first: a correction overwrites something a human read off a screen, and overwriting a version nobody saw is how two HR admins silently undo each other. Absent → `428`; stale or not a token this API issued → `412`. `Idempotency-Key` absent → `422` at `/headers/Idempotency-Key`. The asserted version is part of the replayed request, so the same key against a **different** version collides (`409`) rather than replaying.\n· **At least one correctable field, plus a `correction_reason`.** A PATCH that changes nothing is a caller bug, not a no-op success (`422` at `/`), and a corrected payroll figure with no stated reason is unauditable the following year (`422` at `/correction_reason`, 1–500 characters after trimming).\n· **`effective_from` may move only inside the window its neighbours leave it.** Strictly **after** the predecessor's `effective_from` — two rows claiming the same first day is an ambiguity no API should resolve on the caller's behalf — and **on or before** this record's own `effective_to` when it is closed. When it moves and a predecessor exists, that predecessor is **re-closed** at `effective_from - 1 day` in the same transaction, by the same expression the create path uses, so the chain stays gapless and overlap-free. `effective_to` on the corrected record itself is never written here: it is owned by whoever starts next.\n· **`basic_amount <= ctc_amount` is checked on the MERGED record**, supplied value else stored, as exact minor units and never as a JS float. Raising `basic_amount` past a `ctc_amount` the caller did not send is the mistake a partial update makes easy, and it is a `422` with rule `cross-field` rather than the 500 the `employee_compensation_amounts_valid` CHECK would otherwise produce.\n· **Refused by name, with the reason:** `currency_code` (derived from the legal entity — an INR figure recorded as SAR is the failure this prevents), `employee_id` and `legal_entity_id` (a record cannot be moved between people or entities), `version` (assert it in `If-Match`), and `pay_model` / `rate_card_id` / `piece_rate_catalog_id` (ADR 0033's dispatch axis, not writable over HTTP yet — issue #576 owns it, and the message says so rather than leaving the caller to guess).\n· **Only a `MONTHLY_SALARY` record is correctable here** — `422` at `/compensation_id` on a `DAILY_WAGE` or `PIECE_RATE` row. `employee_compensation_monthly_amounts_present` and `employee_compensation_pay_model_binding_valid` (migration `0124`) are the database's word on what those rows may hold, and this surface has no vocabulary for a rate card or a piece-rate catalogue.\n· A re-pointed `pay_structure_id` is re-resolved from scratch (`PUBLISHED`, same legal entity, `version_no` re-stamped); an explicit `null` clears both. `pay_group_id` is re-resolved against the record's **post-merge** effective date whenever either it or the date moves — a group is effective only across a window of its own, so a record sliding to a new start date can slide off it. Omitting `pay_group_id` keeps the record's own group rather than re-defaulting it, which is the one place this operation deliberately differs from `.create`.\n\n**Maker-checker: `MC-0` today, by default and not by decision.** No suffix rule reaches `update`, so the band resolves from `default_band` exactly as `pay.employee_compensation.create`'s does. Whether a correction to a committed payroll figure *should* be four-eyed is the same unanswered question `security-docs/06 §4` `SGAP-18` already carries for the create and for `people.onboarding.complete` — and it is arguably sharper here, since a correction rewrites a number payroll may already have paid against. It is recorded as an **open item on that row**, not decided by this operation: closing it means a named `mc_rules` entry, a regeneration and a `security-docs/04 §2.1` row saying who decided, and the standing caveat holds — no code reads `mc_band` today (`SGAP-03`/`SGAP-15`), so declaring `MC-1` would assert a control that does not run. What is true in the meantime is that an unbanded correction is not a silent one: the revision row is mandatory, carries the before/after values, and names the principal, so every correction is findable and readable after the fact.\n",
        "tags": [
          "pay",
          "employee-compensation"
        ],
        "x-token": "pay.employee_compensation.update",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PPL-S20",
          "PPL-S14"
        ],
        "x-touches-entities": [
          "pay.employee_compensation",
          "pay.employee_compensation_revisions",
          "people.employees",
          "org.pay_structures",
          "org.pay_groups"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "security": [
          {
            "bearerJWT": []
          }
        ],
        "parameters": [
          {
            "name": "employee_id",
            "in": "path",
            "required": true,
            "description": "UUIDv7 of the `people.employees` row the compensation record belongs to.",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "compensation_id",
            "in": "path",
            "required": true,
            "description": "UUIDv7 of the `pay.employee_compensation` row being corrected. A record belonging to a different employee is a `404`, not a cross-employee edit — both rows are visible to the same tenant, so nothing below the API would have caught it.\n",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmployeeCompensationCorrectionInput"
              },
              "examples": {
                "amount_correction": {
                  "summary": "The committed figure was wrong — correct both amounts",
                  "value": {
                    "ctc_amount": "2080000.00",
                    "basic_amount": "1040000.00",
                    "correction_reason": "Import committed the offer-letter figure one lakh short; corrected against the signed offer."
                  }
                },
                "date_amendment": {
                  "summary": "The increment was effective from March, not April — re-closes the predecessor",
                  "value": {
                    "effective_from": "2027-03-01",
                    "correction_reason": "Increment approved with effect from 1 March; recorded from April in error."
                  }
                },
                "structure_repoint": {
                  "summary": "Bound to the wrong published structure",
                  "value": {
                    "pay_structure_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a80",
                    "correction_reason": "Assigned the L3 structure; band is L4."
                  }
                },
                "clear_structure": {
                  "summary": "Clear the structure binding and the stamped version with it",
                  "value": {
                    "pay_structure_id": null,
                    "notes": null,
                    "correction_reason": "Structure was assigned before the band was agreed; unbinding until it is."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The corrected record, with its new version and its correction count.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeCompensationCorrected"
                },
                "examples": {
                  "amount_correction": {
                    "summary": "Amounts corrected — nothing re-closed, because the start date did not move",
                    "value": {
                      "id": "018f4d90-1b22-7e60-8c11-9a3f2e5b7c02",
                      "employee_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a40",
                      "legal_entity_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a34",
                      "pay_group_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a70",
                      "pay_model": "MONTHLY_SALARY",
                      "pay_structure_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a80",
                      "pay_structure_version": 4,
                      "rate_card_id": null,
                      "piece_rate_catalog_id": null,
                      "effective_from": "2027-04-01",
                      "effective_to": null,
                      "ctc_amount": "2080000.00",
                      "basic_amount": "1040000.00",
                      "currency_code": "INR",
                      "revision_reason": "ANNUAL_REVISION",
                      "notes": "FY27-28 increment cycle, 10%.",
                      "created_at": "2027-03-28T05:11:02.400Z",
                      "created_by": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a90",
                      "version": 1,
                      "revision_count": 1,
                      "closed_previous_id": null
                    }
                  },
                  "date_amendment": {
                    "summary": "Start date moved back — the predecessor was re-closed at 2027-02-28",
                    "value": {
                      "id": "018f4d90-1b22-7e60-8c11-9a3f2e5b7c02",
                      "employee_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a40",
                      "legal_entity_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a34",
                      "pay_group_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a70",
                      "pay_model": "MONTHLY_SALARY",
                      "pay_structure_id": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a80",
                      "pay_structure_version": 4,
                      "rate_card_id": null,
                      "piece_rate_catalog_id": null,
                      "effective_from": "2027-03-01",
                      "effective_to": null,
                      "ctc_amount": "1980000.00",
                      "basic_amount": "990000.00",
                      "currency_code": "INR",
                      "revision_reason": "ANNUAL_REVISION",
                      "notes": "FY27-28 increment cycle, 10%.",
                      "created_at": "2027-03-28T05:11:02.400Z",
                      "created_by": "018f3a2b-7c41-7c9e-8a10-2b6f5d9e1a90",
                      "version": 2,
                      "revision_count": 2,
                      "closed_previous_id": "018f4d90-1b22-7e60-8c11-9a3f2e5b7c01"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/earnings": {
      "get": {
        "operationId": "pay.earning.list",
        "summary": "List a run's pending earnings additions",
        "description": "The per-run additions grid — ad-hoc components, arrears, bonus, variable pay before execute (PAY-S12, db 07 §1.2).",
        "tags": [
          "pay",
          "earning"
        ],
        "x-token": "pay.earning.list",
        "x-realizes-features": [
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.earnings",
          "pay.payslips",
          "org.pay_components"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "earning_type",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/EarningType"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: `created_at`, `-created_at`, `earning_type`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of pending earnings lines on the run.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EarningPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "operationId": "pay.earning.create",
        "summary": "Add a run-time earning line (ad-hoc / arrears / bonus / variable pay)",
        "description": "Places a line on the named employee's payslip within this run — allowed only while the run is pre-execute (`DRAFT`/`PREVIEW`); frozen once `EXECUTED`/`PUBLISHED`, a later change is a supplementary/arrears run (PAY-S12, PAY-F04, db 07 §1.2). Pay-structure / component **definitions** are configured in `org` (`01-org-admin`), not here — this places run-time lines only.\n",
        "tags": [
          "pay",
          "earning"
        ],
        "x-token": "pay.earning.create",
        "x-realizes-features": [
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.earnings",
          "pay.payslips",
          "org.pay_components"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EarningCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Earning line created on the employee's (resolved) payslip for this run.",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Earning"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/earnings/{earning_id}": {
      "patch": {
        "operationId": "pay.earning.update",
        "summary": "Edit a run-time earning line",
        "description": "Edits amount/taxable/prorated on an open (pre-execute) run's line (PAY-S12, db 07 §1.2).",
        "tags": [
          "pay",
          "earning"
        ],
        "x-token": "pay.earning.update",
        "x-realizes-features": [
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.earnings"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "earning_id",
            "in": "path",
            "required": true,
            "description": "UUIDv7 of the `pay.earnings` line.",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EarningUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated earning line.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Earning"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "delete": {
        "operationId": "pay.earning.delete",
        "summary": "Remove a run-time earning line",
        "description": "Soft-deletes a `MANUAL` line on an open (`DRAFT`/`PREVIEW`) run and recomputes the payslip and run totals (PAY-S33, PAY-F04, db 07 §1.2). **`GENERATED` lines answer 409**: the engine wrote them, the payslip's derivation chain (ADR 0031) is written against them, and a re-populate would write them again — the operator's intent there is to hold or void the employee, or to record `PAY_OUTSIDE_PAYROLL`.\n",
        "tags": [
          "pay",
          "earning"
        ],
        "x-token": "pay.earning.delete",
        "x-realizes-features": [
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.earnings",
          "pay.payslips",
          "pay.payroll_runs"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "earning_id",
            "in": "path",
            "required": true,
            "description": "UUIDv7 of the `pay.earnings` line.",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "204": {
            "description": "Line removed; the payslip and run totals have been recomputed.",
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/deductions": {
      "post": {
        "operationId": "pay.deduction.create",
        "summary": "Add a run-time ad-hoc deduction line",
        "description": "Places an `ADHOC`/`OTHER` recovery line on the named employee's payslip within this run (pre-execute only); statutory lines (`EPF`/`TDS`/`GOSI`/…) are engine-resolved, never client-supplied (PAY-S12 note, PAY-F04, db 07 §1.2).\n",
        "tags": [
          "pay",
          "deduction"
        ],
        "x-token": "pay.deduction.create",
        "x-realizes-features": [
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.deductions",
          "pay.payslips",
          "org.pay_components"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeductionCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Deduction line created.",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Deduction"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/deductions/{deduction_id}": {
      "delete": {
        "operationId": "pay.deduction.delete",
        "summary": "Remove a run-time deduction line",
        "description": "Soft-deletes a `MANUAL` recovery line on an open (`DRAFT`/`PREVIEW`) run and recomputes the payslip and run totals (PAY-S33, PAY-F04, db 07 §1.2). `GENERATED` lines — every statutory head — answer 409 for the reason given on `pay.earning.delete`.\n",
        "tags": [
          "pay",
          "deduction"
        ],
        "x-token": "pay.deduction.delete",
        "x-realizes-features": [
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.deductions",
          "pay.payslips",
          "pay.payroll_runs"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "deduction_id",
            "in": "path",
            "required": true,
            "description": "UUIDv7 of the `pay.deductions` line.",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "204": {
            "description": "Line removed; the payslip and run totals have been recomputed.",
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/adjustments": {
      "get": {
        "operationId": "pay.run_adjustment.list",
        "summary": "List the run's cohort head adjustments",
        "description": "The live instructions behind this run's cohort-applied heads, newest first (PAY-S33, PAY-F04, db 07 §1.2). Each row carries the cohort as the operator stated it, the amount-or-percent form, the mandatory reason and `applied_count` — how many payslip lines the fan-out actually wrote.\n",
        "tags": [
          "pay",
          "run-adjustment"
        ],
        "x-token": "pay.run_adjustment.list",
        "x-realizes-features": [
          "PAY-F04",
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.run_adjustments",
          "pay.payroll_runs"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "The run's live cohort adjustments.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunAdjustmentList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "operationId": "pay.run_adjustment.create",
        "summary": "Apply a head across a cohort of the run's payslips",
        "description": "One operator act: a head (earning or deduction) applied to every payslip in a cohort — a department, an org unit, a set of pay models, an explicit selection, or the whole run — as a flat `amount` per employee or a `percent` of each slip's `GROSS`, `NET` or `BASIC` line (PAY-S33, PAY-F04, ADR 0069 §(c)).\n\nThe percentage is **materialised in exact decimal at apply time**, half-up to the minor unit, and written onto each payslip as an ordinary `MANUAL` line carrying `run_adjustment_id` back to this row; it is never re-derived on read, so a published register adds up the same way twice. The lines survive a re-populate, exactly as per-person manual lines do (ADR 0029 §(b)).\n\nOpen runs only (`DRAFT`/`PREVIEW`); `If-Match` is taken against **the run**, because the head is priced against the slips as they stand. Deduction adjustments are restricted to `ADHOC`/`OTHER` (statutory heads are engine-resolved), and `ARREARS` earnings are refused because an arrears line names a per-employee period — that is a supplementary or arrears run. A cohort that would reach nobody is refused (422) rather than recorded as an adjustment that did nothing; employees skipped for a representable reason come back in `skipped`.\n",
        "tags": [
          "pay",
          "run-adjustment"
        ],
        "x-token": "pay.run_adjustment.create",
        "x-realizes-features": [
          "PAY-F04",
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.run_adjustments",
          "pay.earnings",
          "pay.deductions",
          "pay.payslips",
          "pay.payroll_runs"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RunAdjustmentCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Adjustment recorded and fanned out. `ETag` is the RUN's new version — the precondition for whatever the operator does next.\n",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunAdjustmentApplied"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/adjustments/{adjustment_id}": {
      "delete": {
        "operationId": "pay.run_adjustment.delete",
        "summary": "Take a cohort head adjustment back",
        "description": "Soft-deletes the adjustment **and every payslip line still pointing at it**, then recomputes the affected slips and the run in one transaction (PAY-S33, PAY-F04, db 07 §1.2). Being able to reverse one operator act as one act — rather than as an N-step undo — is why the instruction is a row at all. Open runs only; `If-Match` against the run.\n",
        "tags": [
          "pay",
          "run-adjustment"
        ],
        "x-token": "pay.run_adjustment.delete",
        "x-realizes-features": [
          "PAY-F04",
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.run_adjustments",
          "pay.earnings",
          "pay.deductions",
          "pay.payslips",
          "pay.payroll_runs"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "adjustment_id",
            "in": "path",
            "required": true,
            "description": "UUIDv7 of the `pay.run_adjustments` row.",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Adjustment and its lines removed; totals recomputed.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunAdjustmentRemoved"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payslips": {
      "get": {
        "operationId": "pay.payslip.list",
        "summary": "List my payslips",
        "description": "The employee's own payslips by period — only `PUBLISHED` slips are listed (PAY-S01, db 07 §1.2). A MUSTER worker in a tenant with `muster_ess_restricted` is refused 403 TOKEN_DENIED, `type: urn:groundit:problem:pay:payslips-not-offered`. The detail is safe to show verbatim.\n",
        "tags": [
          "pay",
          "payslip"
        ],
        "x-token": "pay.payslip.list",
        "x-realizes-features": [
          "PAY-F03",
          "PAY-F12"
        ],
        "x-screens": [
          "PAY-S01"
        ],
        "x-touches-entities": [
          "pay.payslips",
          "pay.payslip_disbursements",
          "pay.payroll_runs",
          "org.pay_groups"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "fiscal_year",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ISSUED",
                "PENDING"
              ]
            }
          },
          {
            "name": "pay_period_start[from]",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/DateOnlyRef"
            }
          },
          {
            "name": "pay_period_start[to]",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/DateOnlyRef"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: `pay_period_start`, `-pay_period_start`. Default `-pay_period_start`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of the caller's own published payslips.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayslipPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payslips/{id}": {
      "get": {
        "operationId": "pay.payslip.get",
        "summary": "Get one payslip (full detail)",
        "description": "Employer/employee header (by projection, never a join), earnings, deductions, employer contributions (shown, never netted), paid/LOP days, and YTD from published runs only. A restricted MUSTER worker is refused 403 `pay:payslips-not-offered` before any slip is read. (PAY-S02, PAY-F03/F04/F02, db 07 §1.2).\n",
        "tags": [
          "pay",
          "payslip"
        ],
        "x-token": "pay.payslip.get",
        "x-realizes-features": [
          "PAY-F03",
          "PAY-F04",
          "PAY-F02",
          "PAY-F12"
        ],
        "x-screens": [
          "PAY-S02"
        ],
        "x-touches-entities": [
          "pay.payslips",
          "pay.earnings",
          "pay.deductions",
          "people.employees",
          "org.legal_entities",
          "org.designations",
          "pay.payslip_disbursements",
          "pay.payroll_runs",
          "org.pay_groups",
          "pay.payroll_release_batches",
          "pay.payroll_release_batch_lines",
          "pay.payroll_release_settlements"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "The payslip with embedded earnings/deductions lines and header projections.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayslipDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payslips/{id}/download": {
      "get": {
        "operationId": "pay.payslip.download",
        "summary": "Download the payslip PDF",
        "description": "Mints a time-limited presigned URL for the rendered slip PDF; integrity by `pdf_content_hash` SHA-256 (PAY-S02 Download, XC-F07, db 07 §1.2). A restricted MUSTER worker is refused 403 `type: urn:groundit:problem:pay:payslips-not-offered` before a URL is minted.\n",
        "tags": [
          "pay",
          "payslip"
        ],
        "x-token": "pay.payslip.download",
        "x-realizes-features": [
          "PAY-F03"
        ],
        "x-screens": [
          "PAY-S02"
        ],
        "x-touches-entities": [
          "pay.payslips"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "Presigned download handle for the payslip PDF.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileDownloadRef"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payslips/admin": {
      "get": {
        "operationId": "pay.payslip.list_admin",
        "summary": "Payroll register — every slip on a run",
        "description": "Finance's per-run register, drillable, with statutory totals and config-version stamps; `DRAFT` slips appear while the run is pre-publish (recomputable) (PAY-S11, db 07 §1.2). Widened `x-rls-scope: tenant` relative to the self-scoped `pay.payslip.list`.\n",
        "tags": [
          "pay",
          "payslip"
        ],
        "x-token": "pay.payslip.list_admin",
        "x-realizes-features": [
          "PAY-F03",
          "PAY-F02",
          "PAY-F12"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.payslips",
          "pay.earnings",
          "pay.deductions",
          "pay.payslip_disbursements",
          "pay.payroll_runs",
          "org.pay_groups"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "payroll_run_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/PayslipStatus"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: `employee_id`, `net_pay_amount`, `status`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tenant-wide page of payslips (register).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayslipPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payslips/admin/exports": {
      "post": {
        "operationId": "pay.payslip.export",
        "summary": "Export payroll register or Finance cost views",
        "description": "Generates a filtered CSV/PDF export of a run's register (PAY-S11 **Export**, XC-F08). The `grouping` field on `PayslipExportRequest` selects which of the Finance workspace's grouped shapes this same mechanism produces: the cost-centre-grouped export (PAY-S17, preview via `pay.payslip.cost_centre_summary`) or the GL-account-grouped export (PAY-S18, preview via `pay.payslip.gl_summary`) — one export operation, one grouping parameter, never a forked endpoint per shape. `ORG_UNIT`, `LEGAL_ENTITY` and `DEPARTMENT` export the exact filtered PAY-S20 grid as CSV; their selection fields mirror `pay.payslip.cost_summary`.\n",
        "tags": [
          "pay",
          "payslip"
        ],
        "x-token": "pay.payslip.export",
        "x-realizes-features": [
          "PAY-F03",
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33",
          "PAY-S17",
          "PAY-S18",
          "PAY-S20"
        ],
        "x-touches-entities": [
          "pay.payslips",
          "org.departments",
          "org.pay_components"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayslipExportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Presigned download handle for the generated export.",
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileDownloadRef"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/bank-advice": {
      "get": {
        "operationId": "pay.bank_advice.list",
        "summary": "Bank-advice files generated for a run",
        "description": "The Release stage's artifact read — every advice file cut for this run. *(rev. 2026-09-02, #1555)* One per `(batch, layout)` since ADR 0069 §(f), so each row carries `release_batch_id` and the owning batch's `batch_no`: a cycle released in three batches has three files, and an operator must be able to tell them apart. The pre-2026-09 run-wide rows come back with both `null`. Rows are append-only evidence (db 07 §1.9): `content_hash` is the sha256 of the exact bytes handed to the bank. Privileged BANK read — logged to `audit.access_log`.\n",
        "tags": [
          "pay",
          "bank_advice"
        ],
        "x-token": "pay.bank_advice.list",
        "x-realizes-features": [
          "PAY-F11",
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.bank_advice_files",
          "pay.payroll_release_batches",
          "pay.payroll_runs",
          "audit.access_log"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The run's generated advice files, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankAdviceFileList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "operationId": "pay.bank_advice.generate",
        "summary": "Re-issue the bank-advice file for a release batch",
        "description": "*(rev. 2026-09-02, #1555, ADR 0069 §(f) — SCOPE CHANGED.)* An advice file is cut **per release batch**, inside the batch's own transaction, by `pay.payroll_release_batch.create` — the file and the ledger that says what it pays must commit together. This operation therefore no longer MINTS a run's file: it **re-issues the file of an existing batch**, and the run-wide mode is deprecated with a `422` naming its replacement. A body without `release_batch_id` is that refusal.\n\nWhat survives is the half that mattered: a batch is immutable and the generator is byte-deterministic, so `(batch, layout)` is a natural key — a re-issue returns the EXISTING artifact with a fresh presigned URL, and a re-issue in a NEW layout renders the same batch's own lines through that layout. The lines are read from `pay.payroll_release_batch_lines`; the file is a rendering of the ledger, never a second computation over the run that could disagree with it. This **supersedes** #1551's re-pointing of the run-wide predicate at `pay.payslip_disbursements` (which fixed a real double-payment: `HOLD` became legal on a `PUBLISHED` run without cancelling the slip, so the old `status <> 'CANCELLED'` + five-verb `CASE` predicate paid held employees and re-paid partly-released ones). Reading a batch's own persisted lines makes that class unrepresentable rather than merely fixed. The file is refused unless its lines sum to the batch's `total_amount` (`409`), and **an advice never pays an unverified account** — a payee whose primary account is missing or not `VERIFIED` refuses with the employees named (`422`), never a skip, because `people.bank_account.update` resets a mutated account to `PENDING` while leaving it primary and this is the last gate against a post-publish bank-detail swap (security-docs 05, SGAP-04).\n\nDeterministic bytes (same batch, same layout → same sha256 — the #640 tamper-evidence bar); CSV is CRLF, BOM-less, formula-neutralized, and a TAB/CR/LF inside any field REFUSES generation rather than escaping it. Writes the append-only `pay.bank_advice_files` evidence row and an `audit.access_log` DATA_ACCESS(BANK) row in the same transaction.\n",
        "tags": [
          "pay",
          "bank_advice"
        ],
        "x-token": "pay.bank_advice.generate",
        "x-realizes-features": [
          "PAY-F11",
          "PAY-F12"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.bank_advice_files",
          "pay.payroll_release_batches",
          "pay.payroll_release_batch_lines",
          "pay.payroll_runs",
          "people.bank_accounts",
          "people.employees",
          "xc.object_refs",
          "audit.audit_log",
          "audit.access_log"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BankAdviceGenerateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Presigned download handle for the re-issued (or already-existing) advice file.",
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankAdviceFile"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll-runs/{id}/bank-advice/{fileId}/download": {
      "get": {
        "operationId": "pay.bank_advice.download",
        "summary": "Re-download a previously generated bank-advice file",
        "description": "Mints a time-limited presigned URL for an existing advice artifact; integrity by `content_hash` sha256 (the `comply.statutory_filing.download_artifact` shape). Privileged BANK read — every download is individually logged to `audit.access_log` with a catalogued purpose, because each handout of a full-account-number file is its own accountable act.\n",
        "tags": [
          "pay",
          "bank_advice"
        ],
        "x-token": "pay.bank_advice.download",
        "x-realizes-features": [
          "PAY-F11"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "pay.bank_advice_files",
          "pay.payroll_release_batches",
          "xc.object_refs",
          "audit.access_log"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "fileId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Presigned download handle for the stored artifact.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileDownloadRef"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payslips/admin/cost-centre-summary": {
      "get": {
        "operationId": "pay.payslip.cost_centre_summary",
        "summary": "Cost-centre allocation summary (Finance workspace)",
        "description": "Aggregates published payslips' gross/employer cost by cost centre — `pay.payslips.employee_id` resolved to `org.departments.cost_center` via `ref→people.employees.department_id` (by projection, never a join); payslips whose employee has no department `cost_center` group under `\"Unassigned\"` (PAY-S16 bar chart, PAY-S17 grid; db 07 §1.2, db 02 §1.2). Read-model projection (XC-F15) — **no budget/target figure is returned**; `org.departments` carries no budget entity, so budget-vs-actual stays a raised DB gap (design-docs/04 G-14④), not invented here.\n\n**Privileged read.** Catalogued `isPrivileged: true` (tenant-wide `SALARY`-classified aggregate) — every call commits a `DATA_ACCESS` row to `audit.access_log`, in the same transaction as the read (XC-F06).\n",
        "tags": [
          "pay",
          "payslip"
        ],
        "x-token": "pay.payslip.cost_centre_summary",
        "x-realizes-features": [
          "PAY-F04",
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S33",
          "PAY-S17"
        ],
        "x-touches-entities": [
          "pay.payslips",
          "org.departments",
          "people.employees"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "payroll_run_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "fiscal_year",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cost-centre allocation summary (actual only) for the scoped run/period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CostCentreAllocationResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payslips/admin/cost-summary": {
      "get": {
        "operationId": "pay.payslip.cost_summary",
        "summary": "Workforce cost summary grouped by org unit, legal entity or department",
        "description": "The BOS round's grouped workforce-cost read (PAY-S20 workforce cost explorer, now at /pay/costs/explorer under the Payroll > Costs tab). Rev. 2026-09-02: PAY-S19, the console this was also surfaced on as a tile + drill, is withdrawn by ADR 0069 (i); the read itself is unchanged and its tokens are untouched (ADR 0026 §(a)'s authority split is preserved by gating the Costs tab on the cost tokens, never the run tokens). The cycle workspace's own estimate is a different, run-scoped read (pay.payroll_run.cost_summary), legal on a DRAFT run - this one still aggregates payslips from `EXECUTED`/`PUBLISHED` runs only — an uncommitted draft/preview run is not a cost — over a caller-chosen `group_by` axis. **No new entity:** every figure is an aggregate over `pay.payslips`, regrouped; the group label is resolved from `pay.payslips.employee_id → people.employees` in the same tenant transaction. Grouping uses the employee's current assignment; same-transaction org label joins are allowed for this live reference data. Payslips whose employee has no value on the chosen axis group under `\"Unassigned\"` — shown as its own row rather than dropped, so a total is never quietly short.\n\n**Additive beside `pay.payslip.cost_centre_summary`, which is untouched.** That operation knows exactly one axis (`org.departments.cost_center`) and still backs PAY-S16/PAY-S17 unchanged; this one adds the three axes Finance asked for. Two operations, not a forked one — operation IDs are append-only and a live consumer's contract is never re-shaped to add a parameter (00 §4, 06 §2). A caller wanting the cost-centre axis calls the older operation; a caller wanting org unit / legal entity / department calls this one.\n\n**Currencies are never summed across.** Totals are returned **per currency** with no grand total, because a selection spanning legal entities in INR and SAR has no meaningful sum (fsd 06 PAY-S20). `percent_of_total` is of the **selection**, not of the tenant, and within one currency.\n\nTenant-scoped, on Finance's own token: a division manager does not reach this read (`ADM-S08` states that cost lives here, deliberately behind Finance's tokens rather than on the division console). The CSV of exactly this grid, as grouped and filtered, comes from `pay.payslip.export`, audited as a privileged read.\n",
        "tags": [
          "pay",
          "payslip"
        ],
        "x-token": "pay.payslip.cost_summary",
        "x-realizes-features": [
          "PAY-F08"
        ],
        "x-screens": [
          "PAY-S33",
          "PAY-S20"
        ],
        "x-touches-entities": [
          "pay.payslips",
          "pay.payroll_runs",
          "org.org_units",
          "org.legal_entities",
          "org.departments",
          "people.employees"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "group_by",
            "in": "query",
            "required": true,
            "description": "The grouping axis. `org_unit` rolls up the org tree (`ref→org.org_units`), `legal_entity` groups by `ref→org.legal_entities`, `department` by `ref→org.departments`. The cost-centre axis is deliberately NOT offered here — it remains `pay.payslip.cost_centre_summary`'s.\n",
            "schema": {
              "type": "string",
              "enum": [
                "org_unit",
                "legal_entity",
                "department"
              ]
            }
          },
          {
            "name": "payroll_run_id",
            "in": "query",
            "required": false,
            "description": "Narrow to one run. Mutually exclusive with `fiscal_year` / the period range.",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "fiscal_year",
            "in": "query",
            "required": false,
            "description": "Narrow to a fiscal year, per the entity's pack calendar (IN Apr–Mar / KSA Jan–Dec, XC-F01).",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "period_start",
            "in": "query",
            "required": false,
            "description": "Start of an explicit pay-period range (`pay.payroll_runs.pay_period_start`), inclusive.",
            "schema": {
              "$ref": "#/components/schemas/DateOnlyRef"
            }
          },
          {
            "name": "period_end",
            "in": "query",
            "required": false,
            "description": "End of that range (`pay.payroll_runs.pay_period_end`), inclusive.",
            "schema": {
              "$ref": "#/components/schemas/DateOnlyRef"
            }
          },
          {
            "name": "legal_entity_id",
            "in": "query",
            "required": false,
            "description": "Optional narrowing; also the currency anchor for the selection.",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Grouped workforce-cost lines for the selection, with per-currency totals.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkforceCostSummaryResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payslips/admin/gl-summary": {
      "get": {
        "operationId": "pay.payslip.gl_summary",
        "summary": "GL-account export preview (Finance workspace)",
        "description": "Aggregates one run's earnings/deductions by `org.pay_components.gl_account_code` (via `pay.earnings.component_id` / `pay.deductions.component_id`, soft ref) — the preview grid behind PAY-S18's **Export**, which reuses `pay.payslip.export` for the actual file (db 07 §1.2, db 02 §1.4). Components with no mapped `gl_account_code` group under `\"Unmapped\"`.\n\n**Privileged read.** Catalogued `isPrivileged: true` (a `SALARY`-classified aggregate scoped to one run) — every call commits a `DATA_ACCESS` row to `audit.access_log`, in the same transaction as the read (XC-F06).\n",
        "tags": [
          "pay",
          "payslip"
        ],
        "x-token": "pay.payslip.gl_summary",
        "x-realizes-features": [
          "PAY-F03",
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S18"
        ],
        "x-touches-entities": [
          "pay.earnings",
          "pay.deductions",
          "org.pay_components"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "payroll_run_id",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "GL-account-grouped preview lines for the run.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GlExportSummaryResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/esop-grants": {
      "get": {
        "operationId": "pay.esop_grant.list",
        "summary": "My ESOP grants",
        "description": "The employee's equity grants with running vested/exercised/forfeited balances (PAY-S04, db 07 §1.3).",
        "tags": [
          "pay",
          "esop_grant"
        ],
        "x-token": "pay.esop_grant.list",
        "x-realizes-features": [
          "PAY-F05"
        ],
        "x-screens": [
          "PAY-S04"
        ],
        "x-touches-entities": [
          "pay.esop_grants"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": "pay.esop",
        "x-provisional": null,
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/EsopGrantStatus"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: grant_date, -grant_date, status.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of the caller's own ESOP grants.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EsopGrantPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/esop-grants/{id}": {
      "get": {
        "operationId": "pay.esop_grant.get",
        "summary": "Get one ESOP grant (with vesting tranches)",
        "description": "Grant detail plus its embedded per-tranche vesting schedule (PAY-S04, db 07 §1.3).",
        "tags": [
          "pay",
          "esop_grant"
        ],
        "x-token": "pay.esop_grant.get",
        "x-realizes-features": [
          "PAY-F05"
        ],
        "x-screens": [
          "PAY-S04"
        ],
        "x-touches-entities": [
          "pay.esop_grants",
          "pay.vesting_schedules"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": "pay.esop",
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "The grant with its vesting tranches.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EsopGrantDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/esop-grants/admin": {
      "get": {
        "operationId": "pay.esop_grant.list_admin",
        "summary": "Grant administration — all ESOP grants",
        "description": "Finance's tenant-wide grant grid (PAY-S13, db 07 §1.3). Widened x-rls-scope tenant relative to pay.esop_grant.list.",
        "tags": [
          "pay",
          "esop_grant"
        ],
        "x-token": "pay.esop_grant.list_admin",
        "x-realizes-features": [
          "PAY-F05"
        ],
        "x-screens": [
          "PAY-S13"
        ],
        "x-touches-entities": [
          "pay.esop_grants"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": "pay.esop",
        "x-provisional": null,
        "parameters": [
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/EsopGrantStatus"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: grant_date, employee_id, status.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tenant-wide page of ESOP grants.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EsopGrantPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "operationId": "pay.esop_grant.create",
        "summary": "Issue an ESOP grant",
        "description": "Issues a grant and generates its vesting-tranche schedule (sum of vest_pct = 1) in one call (PAY-S13, db 07 §1.3).",
        "tags": [
          "pay",
          "esop_grant"
        ],
        "x-token": "pay.esop_grant.create",
        "x-realizes-features": [
          "PAY-F05"
        ],
        "x-screens": [
          "PAY-S13"
        ],
        "x-touches-entities": [
          "pay.esop_grants",
          "pay.vesting_schedules",
          "people.employees"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.esop_grant.issued",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": "pay.esop",
        "x-provisional": null,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EsopGrantCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Grant issued (status GRANTED), with its generated vesting tranches.",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EsopGrantDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/esop-valuations/admin": {
      "get": {
        "operationId": "pay.esop_valuation.list_admin",
        "summary": "List tenant ESOP fair-market valuations",
        "description": "Cursor-paginated, effective-dated Finance valuation evidence used by ESOP exercises.",
        "tags": [
          "pay",
          "esop_valuation"
        ],
        "x-token": "pay.esop_valuation.list_admin",
        "x-realizes-features": [
          "PAY-F05"
        ],
        "x-screens": [
          "PAY-S13"
        ],
        "x-touches-entities": [
          "pay.esop_valuations"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": "pay.esop",
        "x-provisional": null,
        "parameters": [
          {
            "name": "legal_entity_id",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "plan_name",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          }
        ],
        "responses": {
          "200": {
            "description": "Effective-dated valuation page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EsopValuationPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "operationId": "pay.esop_valuation.create",
        "summary": "Record an effective-dated ESOP fair-market valuation",
        "tags": [
          "pay",
          "esop_valuation"
        ],
        "x-token": "pay.esop_valuation.create",
        "x-realizes-features": [
          "PAY-F05"
        ],
        "x-screens": [
          "PAY-S13"
        ],
        "x-touches-entities": [
          "pay.esop_valuations"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.esop_valuation.recorded",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": "pay.esop",
        "x-provisional": null,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EsopValuationCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Valuation recorded.",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EsopValuation"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/esop-valuations/admin/{id}/complete": {
      "post": {
        "operationId": "pay.esop_valuation.complete",
        "summary": "Complete an ESOP valuation as the second Finance reviewer",
        "description": "MC-1 dual control on the FMV (`security-docs/04` §2.1, issue #1247). `pay.esop_valuation.create` records a `PENDING_REVIEW` submission that prices nothing; this operation is the second pair of eyes that turns it into the `EFFECTIVE` row `pay.esop_exercise.create` may read. The maker-checker kernel refuses a caller who is the valuation's own `submitted_by` with `MAKER_EQUALS_CHECKER`, and a valuation that is already `EFFECTIVE` is `409 STATE_TRANSITION_INVALID` — replay is by `Idempotency-Key`, not by a second completion (PAY-S13 §1.4, db 07 §1.3).\n",
        "tags": [
          "pay",
          "esop_valuation"
        ],
        "x-token": "pay.esop_valuation.complete",
        "x-realizes-features": [
          "PAY-F05"
        ],
        "x-screens": [
          "PAY-S13"
        ],
        "x-touches-entities": [
          "pay.esop_valuations"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.esop_valuation.effective",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": "pay.esop",
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Valuation completed by a second Finance reviewer and now effective.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EsopValuation"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/esop-valuations/admin/{id}/reject": {
      "post": {
        "operationId": "pay.esop_valuation.reject",
        "summary": "Reject a submitted ESOP valuation as the second Finance reviewer",
        "description": "The refusal half of the MC-1 dual control on the FMV (`security-docs/04` §2.1, issue #1247). A dual control whose checker can only say yes is half a control — and until migration `0235` made `esop_valuations_live_effective_key` partial on `status <> 'REJECTED'`, a wrong submission also held its effective date, so the corrected valuation could not be recorded for the same day. A `reason` is REQUIRED: the maker has to be able to read why, and a refusal with none is not evidence. The kernel refuses a caller who is the valuation's own `submitted_by` with `MAKER_EQUALS_CHECKER`; only `PENDING_REVIEW` rows may be rejected (anything else is `409 STATE_TRANSITION_INVALID` — an effective price is superseded by a new effective-dated valuation, never un-made here). PAY-S13 §1.4, db 07 §1.3.\n",
        "tags": [
          "pay",
          "esop_valuation"
        ],
        "x-token": "pay.esop_valuation.reject",
        "x-realizes-features": [
          "PAY-F05"
        ],
        "x-screens": [
          "PAY-S13"
        ],
        "x-touches-entities": [
          "pay.esop_valuations"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.esop_valuation.rejected",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": "pay.esop",
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EsopValuationReject"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Valuation refused by a second Finance reviewer; its effective date is free again.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EsopValuation"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/esop-exercises": {
      "post": {
        "operationId": "pay.esop_exercise.create",
        "summary": "Request to exercise vested ESOP units",
        "description": "Cost, FMV, and the taxable perquisite are server-derived and returned; Finance reviews India withholding after request creation. units must be less than or equal to vested_units minus exercised_units (PAY-S05, db 07 §1.3). KSA exercises carry withholding_amount = 0 (no personal income tax).\n",
        "tags": [
          "pay",
          "esop_exercise"
        ],
        "x-token": "pay.esop_exercise.create",
        "x-realizes-features": [
          "PAY-F05"
        ],
        "x-screens": [
          "PAY-S05"
        ],
        "x-touches-entities": [
          "pay.esop_exercises",
          "pay.esop_grants"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.esop_exercise.requested",
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": "pay.esop",
        "x-provisional": null,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EsopExerciseCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Exercise request created (status REQUESTED).",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EsopExercise"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/esop-exercises/admin": {
      "get": {
        "operationId": "pay.esop_exercise.list_admin",
        "summary": "ESOP exercise decision queue",
        "description": "Finance's queue of exercise requests to clear (PAY-S13, db 07 §1.3).",
        "tags": [
          "pay",
          "esop_exercise"
        ],
        "x-token": "pay.esop_exercise.list_admin",
        "x-realizes-features": [
          "PAY-F05"
        ],
        "x-screens": [
          "PAY-S13"
        ],
        "x-touches-entities": [
          "pay.esop_exercises"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": "pay.esop",
        "x-provisional": null,
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/EsopExerciseStatus"
            }
          },
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: exercise_date, -exercise_date, status.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of ESOP exercise requests.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EsopExercisePage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/esop-exercises/admin/{id}": {
      "get": {
        "operationId": "pay.esop_exercise.get_admin",
        "summary": "Get one ESOP exercise request",
        "description": "The decision drawer's source row (PAY-S13, db 07 §1.3).",
        "tags": [
          "pay",
          "esop_exercise"
        ],
        "x-token": "pay.esop_exercise.get_admin",
        "x-realizes-features": [
          "PAY-F05"
        ],
        "x-screens": [
          "PAY-S13"
        ],
        "x-touches-entities": [
          "pay.esop_exercises"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": "pay.esop",
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "The ESOP exercise request.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EsopExercise"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/esop-exercises/admin/{id}/approve": {
      "post": {
        "operationId": "pay.esop_exercise.approve",
        "summary": "Approve an ESOP exercise request",
        "description": "Finance review transitions REQUESTED to APPROVED. India requires a reviewed withholding amount and reason; KSA is forced to zero withholding (PAY-S13, db 07 §1.3).",
        "tags": [
          "pay",
          "esop_exercise"
        ],
        "x-token": "pay.esop_exercise.approve",
        "x-realizes-features": [
          "PAY-F05"
        ],
        "x-screens": [
          "PAY-S13"
        ],
        "x-touches-entities": [
          "pay.esop_exercises",
          "pay.esop_grants"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.esop_exercise.approved",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": "pay.esop",
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EsopExerciseReviewInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Approved with Finance-reviewed withholding evidence.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EsopExercise"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/esop-exercises/admin/{id}/reject": {
      "post": {
        "operationId": "pay.esop_exercise.reject",
        "summary": "Reject an ESOP exercise request",
        "description": "Declines the exercise request (PAY-S13, db 07 §1.3).",
        "tags": [
          "pay",
          "esop_exercise"
        ],
        "x-token": "pay.esop_exercise.reject",
        "x-realizes-features": [
          "PAY-F05"
        ],
        "x-screens": [
          "PAY-S13"
        ],
        "x-touches-entities": [
          "pay.esop_exercises"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.esop_exercise.rejected",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": "pay.esop",
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rejected.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EsopExercise"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/salary-advances": {
      "post": {
        "operationId": "pay.salary_advance.create",
        "summary": "Request a salary advance",
        "description": "Employer-funded advance, recovered over one or more pay periods once approved and disbursed (PAY-S06, db 07 §1.4).",
        "tags": [
          "pay",
          "salary_advance"
        ],
        "x-token": "pay.salary_advance.create",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S06"
        ],
        "x-touches-entities": [
          "pay.salary_advances"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.salary_advance.requested",
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SalaryAdvanceCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Advance requested (status REQUESTED).",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalaryAdvance"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "get": {
        "operationId": "pay.salary_advance.list",
        "summary": "My advances",
        "description": "The employee's salary advances with running outstanding balance (PAY-S07, db 07 §1.4).",
        "tags": [
          "pay",
          "salary_advance"
        ],
        "x-token": "pay.salary_advance.list",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S07"
        ],
        "x-touches-entities": [
          "pay.salary_advances"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SalaryAdvanceStatus"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: request_date, -request_date, status.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of the caller's own salary advances.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalaryAdvancePage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/salary-advances/{id}": {
      "get": {
        "operationId": "pay.salary_advance.get",
        "summary": "Get one salary advance",
        "description": "Advance detail with its outstanding balance (PAY-S07, db 07 §1.4).",
        "tags": [
          "pay",
          "salary_advance"
        ],
        "x-token": "pay.salary_advance.get",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S07"
        ],
        "x-touches-entities": [
          "pay.salary_advances"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "The salary advance.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalaryAdvance"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/salary-advances/admin": {
      "get": {
        "operationId": "pay.salary_advance.list_admin",
        "summary": "Salary advance administration",
        "description": "Finance's tenant-wide advance grid (PAY-S14, db 07 §1.4). Widened x-rls-scope tenant relative to pay.salary_advance.list.",
        "tags": [
          "pay",
          "salary_advance"
        ],
        "x-token": "pay.salary_advance.list_admin",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S14"
        ],
        "x-touches-entities": [
          "pay.salary_advances"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SalaryAdvanceStatus"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: request_date, employee_id, status.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tenant-wide page of salary advances.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalaryAdvancePage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/salary-advances/admin/{id}/approve": {
      "post": {
        "operationId": "pay.salary_advance.approve",
        "summary": "Approve a salary advance (checker)",
        "description": "Maker-checker clears the request; submitted_by not equal to approved_by enforced (PAY-S14, XC-F12, db 07 §1.4).",
        "tags": [
          "pay",
          "salary_advance"
        ],
        "x-token": "pay.salary_advance.approve",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S14"
        ],
        "x-touches-entities": [
          "pay.salary_advances"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.salary_advance.approved",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Approved.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalaryAdvance"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/salary-advances/admin/{id}/reject": {
      "post": {
        "operationId": "pay.salary_advance.reject",
        "summary": "Reject a salary advance",
        "description": "Declines the request (PAY-S14, db 07 §1.4).",
        "tags": [
          "pay",
          "salary_advance"
        ],
        "x-token": "pay.salary_advance.reject",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S14"
        ],
        "x-touches-entities": [
          "pay.salary_advances"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.salary_advance.rejected",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rejected.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalaryAdvance"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/salary-advances/admin/{id}/disburse": {
      "post": {
        "operationId": "pay.salary_advance.disburse",
        "summary": "Disburse an approved salary advance",
        "description": "Pays out the advance; status APPROVED to DISBURSED, recovery begins from recovery_start_period (PAY-S14, db 07 §1.4).",
        "tags": [
          "pay",
          "salary_advance"
        ],
        "x-token": "pay.salary_advance.disburse",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S14"
        ],
        "x-touches-entities": [
          "pay.salary_advances"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.salary_advance.disbursed",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Disbursed.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalaryAdvance"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/salary-advances/admin/{id}/write-off": {
      "post": {
        "operationId": "pay.salary_advance.write_off",
        "summary": "Write off an outstanding salary advance balance",
        "description": "Approved concession closing the advance without full recovery; audited (PAY-S14, XC-F06, db 07 §1.4).",
        "tags": [
          "pay",
          "salary_advance"
        ],
        "x-token": "pay.salary_advance.write_off",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S14"
        ],
        "x-touches-entities": [
          "pay.salary_advances"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.salary_advance.written_off",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Written off.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalaryAdvance"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/employee-loans": {
      "post": {
        "operationId": "pay.employee_loan.create",
        "summary": "Request an employee loan",
        "description": "Employer-funded structured loan with tenure and (optional) interest, recovered through payroll EMIs once disbursed (PAY-S06, db 07 §1.4).",
        "tags": [
          "pay",
          "employee_loan"
        ],
        "x-token": "pay.employee_loan.create",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S06"
        ],
        "x-touches-entities": [
          "pay.employee_loans"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.employee_loan.requested",
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmployeeLoanCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Loan requested (status REQUESTED).",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeLoan"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "get": {
        "operationId": "pay.employee_loan.list",
        "summary": "My loans",
        "description": "The employee's employee loans with running outstanding principal (PAY-S07, db 07 §1.4).",
        "tags": [
          "pay",
          "employee_loan"
        ],
        "x-token": "pay.employee_loan.list",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S07"
        ],
        "x-touches-entities": [
          "pay.employee_loans"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/EmployeeLoanStatus"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: recovery_start_date, -recovery_start_date, status.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of the caller's own employee loans.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeLoanPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/employee-loans/{id}": {
      "get": {
        "operationId": "pay.employee_loan.get",
        "summary": "Get one employee loan",
        "description": "Loan detail with outstanding principal (PAY-S07, db 07 §1.4).",
        "tags": [
          "pay",
          "employee_loan"
        ],
        "x-token": "pay.employee_loan.get",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S07"
        ],
        "x-touches-entities": [
          "pay.employee_loans"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "The employee loan.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeLoan"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/employee-loans/{id}/loan-emis": {
      "get": {
        "operationId": "pay.loan_emi.list",
        "summary": "My EMI schedule for a loan",
        "description": "The instalment-by-instalment recovery schedule for the caller's own loan (PAY-S07, db 07 §1.4).",
        "tags": [
          "pay",
          "loan_emi"
        ],
        "x-token": "pay.loan_emi.list",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S07"
        ],
        "x-touches-entities": [
          "pay.loan_emis"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: installment_no.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of the loan's EMI schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoanEmiPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/employee-loans/admin": {
      "get": {
        "operationId": "pay.employee_loan.list_admin",
        "summary": "Employee loan administration",
        "description": "Finance's tenant-wide loan grid (PAY-S14, db 07 §1.4). Widened x-rls-scope tenant relative to pay.employee_loan.list.",
        "tags": [
          "pay",
          "employee_loan"
        ],
        "x-token": "pay.employee_loan.list_admin",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S14"
        ],
        "x-touches-entities": [
          "pay.employee_loans"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/EmployeeLoanStatus"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: recovery_start_date, employee_id, status.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tenant-wide page of employee loans.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeLoanPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/employee-loans/admin/{id}/loan-emis": {
      "get": {
        "operationId": "pay.loan_emi.list_admin",
        "summary": "EMI schedule for any loan (Finance)",
        "description": "The instalment-by-instalment recovery schedule for any employee's loan (PAY-S14, db 07 §1.4).",
        "tags": [
          "pay",
          "loan_emi"
        ],
        "x-token": "pay.loan_emi.list_admin",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S14"
        ],
        "x-touches-entities": [
          "pay.loan_emis"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: installment_no.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of the loan's EMI schedule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoanEmiPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/employee-loans/admin/{id}/approve": {
      "post": {
        "operationId": "pay.employee_loan.approve",
        "summary": "Approve an employee loan (checker)",
        "description": "Maker-checker clears the request; submitted_by not equal to approved_by enforced (PAY-S14, XC-F12, db 07 §1.4).",
        "tags": [
          "pay",
          "employee_loan"
        ],
        "x-token": "pay.employee_loan.approve",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S14"
        ],
        "x-touches-entities": [
          "pay.employee_loans"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.employee_loan.approved",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Approved.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeLoan"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/employee-loans/admin/{id}/reject": {
      "post": {
        "operationId": "pay.employee_loan.reject",
        "summary": "Reject an employee loan",
        "description": "Declines the request (PAY-S14, db 07 §1.4).",
        "tags": [
          "pay",
          "employee_loan"
        ],
        "x-token": "pay.employee_loan.reject",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S14"
        ],
        "x-touches-entities": [
          "pay.employee_loans"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.employee_loan.rejected",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rejected.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeLoan"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/employee-loans/admin/{id}/disburse": {
      "post": {
        "operationId": "pay.employee_loan.disburse",
        "summary": "Disburse an approved employee loan",
        "description": "Pays out the loan and generates the loan_emis schedule; status APPROVED to DISBURSED then ACTIVE (PAY-S14, db 07 §1.4).",
        "tags": [
          "pay",
          "employee_loan"
        ],
        "x-token": "pay.employee_loan.disburse",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S14"
        ],
        "x-touches-entities": [
          "pay.employee_loans",
          "pay.loan_emis"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.employee_loan.disbursed",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Disbursed; EMI schedule generated.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeLoan"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/employee-loans/admin/{id}/foreclose": {
      "post": {
        "operationId": "pay.employee_loan.foreclose",
        "summary": "Foreclose an employee loan (early settlement)",
        "description": "Settles the outstanding principal early; status to FORECLOSED, closed_at stamped (PAY-S14, db 07 §1.4).",
        "tags": [
          "pay",
          "employee_loan"
        ],
        "x-token": "pay.employee_loan.foreclose",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S14"
        ],
        "x-touches-entities": [
          "pay.employee_loans"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.employee_loan.foreclosed",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Foreclosed.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeLoan"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/employee-loans/admin/{id}/write-off": {
      "post": {
        "operationId": "pay.employee_loan.write_off",
        "summary": "Write off an outstanding employee loan balance",
        "description": "Approved concession closing the loan without full recovery; audited (PAY-S14, XC-F06, db 07 §1.4).",
        "tags": [
          "pay",
          "employee_loan"
        ],
        "x-token": "pay.employee_loan.write_off",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S14"
        ],
        "x-touches-entities": [
          "pay.employee_loans"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.employee_loan.written_off",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Written off.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeeLoan"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/loan-emis/admin/{id}/defer": {
      "post": {
        "operationId": "pay.loan_emi.defer",
        "summary": "Defer an EMI instalment",
        "description": "Skips/postpones one instalment (moratorium); status to DEFERRED, a transition never a delete; audited (PAY-S14, XC-F06, db 07 §1.4).",
        "tags": [
          "pay",
          "loan_emi"
        ],
        "x-token": "pay.loan_emi.defer",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S14"
        ],
        "x-touches-entities": [
          "pay.loan_emis"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.loan_emi.deferred",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Deferred.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoanEmi"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/loan-emis/admin/{id}/waive": {
      "post": {
        "operationId": "pay.loan_emi.waive",
        "summary": "Waive an EMI instalment",
        "description": "Approved concession waiving one instalment; status to WAIVED; audited (PAY-S14, XC-F06, db 07 §1.4).",
        "tags": [
          "pay",
          "loan_emi"
        ],
        "x-token": "pay.loan_emi.waive",
        "x-realizes-features": [
          "PAY-F06"
        ],
        "x-screens": [
          "PAY-S14"
        ],
        "x-touches-entities": [
          "pay.loan_emis"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.loan_emi.waived",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Waived.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoanEmi"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/full-final-settlements": {
      "get": {
        "operationId": "pay.full_final_settlement.list",
        "summary": "My full & final settlement(s)",
        "description": "The leaver's own settlement statement(s) — one live row per leaver (PAY-S08, db 07 §1.5).",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.list",
        "x-realizes-features": [
          "PAY-F07"
        ],
        "x-screens": [
          "PAY-S08"
        ],
        "x-touches-entities": [
          "pay.full_final_settlements"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: last_working_date, -last_working_date, status.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of the caller's own full-&-final settlements.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlementPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/full-final-settlements/{id}": {
      "get": {
        "operationId": "pay.full_final_settlement.get",
        "summary": "Get my full & final settlement statement",
        "description": "Pending salary, leave encashment (by event, LVE-F05), gratuity (IN) or EOSB (KSA) — exactly one applies, recoveries, tax, and net settlement (PAY-S08, db 07 §1.5).\n",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.get",
        "x-realizes-features": [
          "PAY-F07"
        ],
        "x-screens": [
          "PAY-S08"
        ],
        "x-touches-entities": [
          "pay.full_final_settlements",
          "exit.resignations",
          "exit.exit_clearances"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "The settlement statement, its governed overrides and its explanation chain.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlementDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/full-final-settlements/{id}/download": {
      "get": {
        "operationId": "pay.full_final_settlement.download",
        "summary": "Download the F&F payslip PDF",
        "description": "Presigned download of the settlement's payslip PDF once PUBLISHED (PAY-S08 Download, XC-F07, db 07 §1.5).",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.download",
        "x-realizes-features": [
          "PAY-F07"
        ],
        "x-screens": [
          "PAY-S08"
        ],
        "x-touches-entities": [
          "pay.full_final_settlements",
          "pay.payslips"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "Presigned download handle for the F&F payslip PDF.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileDownloadRef"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/full-final-settlements/admin": {
      "get": {
        "operationId": "pay.full_final_settlement.list_admin",
        "summary": "Full & final settlement administration",
        "description": "Finance's tenant-wide settlement grid (PAY-S15, db 07 §1.5). Widened x-rls-scope tenant relative to pay.full_final_settlement.list.",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.list_admin",
        "x-realizes-features": [
          "PAY-F07"
        ],
        "x-screens": [
          "PAY-S15"
        ],
        "x-touches-entities": [
          "pay.full_final_settlements"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/FullFinalSettlementStatus"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: last_working_date, employee_id, status.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tenant-wide page of full-&-final settlements.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlementPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "operationId": "pay.full_final_settlement.initiate",
        "summary": "Initiate a leaver's full & final settlement",
        "description": "Opens the settlement statement for a leaver's exit case; status INITIATED (PAY-S15, db 07 §1.5).",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.initiate",
        "x-realizes-features": [
          "PAY-F07"
        ],
        "x-screens": [
          "PAY-S15"
        ],
        "x-touches-entities": [
          "pay.full_final_settlements",
          "exit.resignations",
          "people.employees"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.full_final_settlement.initiated",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FullFinalSettlementInitiate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Settlement initiated.",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlement"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/full-final-settlements/admin/{id}": {
      "get": {
        "operationId": "pay.full_final_settlement.get_admin",
        "summary": "Get one full & final settlement (Finance) — row, governed overrides and the ADR 0031 chain",
        "description": "The reconciliation detail/wizard source row (PAY-S15, db 07 §1.5).\n\n**Two things ride back on this read that no other operation serves** (issue [#194](https://github.com/Sysmeadac/GroundIT/issues/194)):\n\n`overrides` — the settlement's governed manual overrides. `pay.full_final_settlement_overrides` is written by `.override` / `.override_approve` and had no read anywhere in the API, which left design-finance/02 §5's last rule unbuildable: an overridden line must lose its `View derivation →` and carry a permanent `Manual override — <reason>, approved by <checker>` badge, and the screen cannot render that without the override's reason and its checker.\n\n`explanation` — the settlement's ADR 0031 chain. `.recompute` has written a `FNF_LINE` chain per settlement since #591, but both explanation reads (`pay.pay_explanation.get` / `.get_admin`) scope with `WHERE payslip_id = $1`, a column the F&F insert leaves NULL because a settlement has no payslip (`settlement_payslip_id` stays null under the ADR 0034/0029 conflict recorded in db-docs/07 §1.5). The chain was written and unreadable.\n\n**Both are embedded rather than given routes of their own, and that is a contract decision, not a shortcut.** `operationId` **is** the permission token (ADR 0015), so a `GET .../{id}/overrides` or a `GET .../{id}/explanation` would either mint a new token for the same subject at the same `SALARY` classification — a second answer to a question this token already decides — or duplicate an `operationId`, which OpenAPI forbids and `apps/api/test/fnf-ops-coverage.spec.ts` asserts against. Neither sub-resource is addressable apart from the settlement it belongs to.\n\nBoth fields are present on **this** read only; `pay.full_final_settlement.list_admin` answers `SELECT f.*` and carries neither.\n",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.get_admin",
        "x-realizes-features": [
          "PAY-F07",
          "PAY-F09"
        ],
        "x-screens": [
          "PAY-S15"
        ],
        "x-touches-entities": [
          "pay.full_final_settlements",
          "pay.full_final_settlement_overrides",
          "pay.pay_explanations"
        ],
        "x-idempotent": false,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "The settlement statement.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlement"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/full-final-settlements/admin/{id}/recompute": {
      "post": {
        "operationId": "pay.full_final_settlement.recompute",
        "summary": "Reconcile / recompute the settlement",
        "description": "Engine reconciles earnings, recoveries, and gratuity/EOSB on the jobs tier; status to CALCULATING then PENDING_CLEARANCE (PAY-S15, PAY-F02, XC-F08, db 07 §1.5). Async.",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.recompute",
        "x-realizes-features": [
          "PAY-F07",
          "PAY-F02"
        ],
        "x-screens": [
          "PAY-S15"
        ],
        "x-touches-entities": [
          "pay.full_final_settlements"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "async",
        "x-emits-event": "pay.full_final_settlement.recomputed",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "202": {
            "description": "Recompute enqueued; poll GET or subscribe to pay.full_final_settlement.recomputed.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlement"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/full-final-settlements/admin/{id}/confirm-clearance": {
      "post": {
        "operationId": "pay.full_final_settlement.confirm_clearance",
        "summary": "Confirm no-dues clearance",
        "description": "Sets no_dues_cleared true against the exit clearance record; required before approval (PAY-S15, ref exit.exit_clearances EXT-F02, db 07 §1.5).",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.confirm_clearance",
        "x-realizes-features": [
          "PAY-F07"
        ],
        "x-screens": [
          "PAY-S15"
        ],
        "x-touches-entities": [
          "pay.full_final_settlements",
          "exit.exit_clearances"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.full_final_settlement.clearance_confirmed",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FullFinalSettlementClearanceInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Clearance confirmed.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlement"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/full-final-settlements/admin/{id}/submit-for-approval": {
      "post": {
        "operationId": "pay.full_final_settlement.submit_for_approval",
        "summary": "Submit the settlement for maker-checker approval",
        "description": "Stamps submitted_by; status to PENDING_APPROVAL (PAY-S15, XC-F12, db 07 §1.5).",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.submit_for_approval",
        "x-realizes-features": [
          "PAY-F07"
        ],
        "x-screens": [
          "PAY-S15"
        ],
        "x-touches-entities": [
          "pay.full_final_settlements"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.full_final_settlement.submitted_for_approval",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submitted for approval.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlement"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/full-final-settlements/admin/{id}/approve": {
      "post": {
        "operationId": "pay.full_final_settlement.approve",
        "summary": "Approve the settlement (checker)",
        "description": "Maker-checker clears the settlement; submitted_by not equal to approved_by enforced; status to APPROVED (PAY-S15, XC-F12, db 07 §1.5).",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.approve",
        "x-realizes-features": [
          "PAY-F07"
        ],
        "x-screens": [
          "PAY-S15"
        ],
        "x-touches-entities": [
          "pay.full_final_settlements"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.full_final_settlement.approved",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Approved.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlement"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/full-final-settlements/admin/{id}/reject": {
      "post": {
        "operationId": "pay.full_final_settlement.reject",
        "summary": "Reject the settlement",
        "description": "Declines the settlement; returns to reconciliation (PAY-S15, db 07 §1.5).",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.reject",
        "x-realizes-features": [
          "PAY-F07"
        ],
        "x-screens": [
          "PAY-S15"
        ],
        "x-touches-entities": [
          "pay.full_final_settlements"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.full_final_settlement.rejected",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rejected.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlement"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/full-final-settlements/admin/{id}/settle": {
      "post": {
        "operationId": "pay.full_final_settlement.settle",
        "summary": "Settle the F&F (produce the FNF payroll run + slip)",
        "description": "Produces the FNF payroll run and its settlement payslip; status APPROVED to SETTLED (PAY-S15, fk pay.payroll_runs/pay.payslips, XC-F08, db 07 §1.5). Async.",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.settle",
        "x-realizes-features": [
          "PAY-F07",
          "PAY-F02"
        ],
        "x-screens": [
          "PAY-S15"
        ],
        "x-touches-entities": [
          "pay.full_final_settlements",
          "pay.payroll_runs",
          "pay.payslips"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "async",
        "x-emits-event": "pay.full_final_settlement.settled",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "202": {
            "description": "Settle enqueued; poll GET or subscribe to pay.full_final_settlement.settled.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlement"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/full-final-settlements/admin/{id}/publish": {
      "post": {
        "operationId": "pay.full_final_settlement.publish",
        "summary": "Publish the settled F&F (freeze, release to the leaver)",
        "description": "Freezes the statement and its slip; status SETTLED to PUBLISHED, immutable from here — a correction is a supplementary F&F, never an edit (PAY-S15, db 07 §1.5). Async.",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.publish",
        "x-realizes-features": [
          "PAY-F07"
        ],
        "x-screens": [
          "PAY-S15"
        ],
        "x-touches-entities": [
          "pay.full_final_settlements",
          "pay.payslips"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "async",
        "x-emits-event": "pay.full_final_settlement.published",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "202": {
            "description": "Publish enqueued; poll GET or subscribe to pay.full_final_settlement.published.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlement"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/full-final-settlements/admin/{id}/override": {
      "post": {
        "operationId": "pay.full_final_settlement.override",
        "summary": "Request a governed manual F&F calculation override",
        "description": "Only for unavailable authoritative calculation inputs (PAY-S15, db 07 §1.5). The proposal records every failed prerequisite and a complete component snapshot; it requires a distinct Finance checker (`pay.full_final_settlement.override_approve`) before `pay.full_final_settlement.recompute` may apply it. This is the **maker** half of the override exception — a separate token from `.recompute`, which recalculates from authoritative inputs and grants no exception power of its own.\n",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.override",
        "x-realizes-features": [
          "PAY-F07"
        ],
        "x-screens": [
          "PAY-S15"
        ],
        "x-touches-entities": [
          "pay.full_final_settlement_overrides"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.full_final_settlement.override_requested",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FullFinalSettlementOverrideInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Override awaiting a distinct Finance checker.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlementOverride"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          }
        }
      }
    },
    "/full-final-settlements/admin/{id}/overrides/{overrideId}/approve": {
      "post": {
        "operationId": "pay.full_final_settlement.override_approve",
        "summary": "Approve a manual F&F calculation override",
        "description": "A checker distinct from the override maker approves the exception (PAY-S15, db 07 §1.5); only then can `pay.full_final_settlement.recompute` apply it. Distinct from `pay.full_final_settlement.approve`, which signs off the settlement statement itself — this token authorizes a manual departure from the calculated figures, so it carries the same **MC-2** regulated dual control (security-docs 04 §2).\n",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.override_approve",
        "x-realizes-features": [
          "PAY-F07"
        ],
        "x-screens": [
          "PAY-S15"
        ],
        "x-touches-entities": [
          "pay.full_final_settlement_overrides"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.full_final_settlement.override_approved",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "overrideId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Approved override.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlementOverride"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          }
        }
      }
    },
    "/full-final-settlements/admin/{id}/overrides/{overrideId}/reject": {
      "post": {
        "operationId": "pay.full_final_settlement.reject_override",
        "summary": "Refuse a manual F&F calculation override",
        "description": "The counterpart `pay` shipped the SCHEMA for and never the transition (#1649). `pay.full_final_override_status` has carried `REJECTED` together with `rejected_by`/`rejected_at` and a CHECK requiring both since migration `0039`, and nothing could write them — so a governed exception could be signed off and never turned down. Once #1649 put overrides on the approvals rail that became load-bearing: an `FNF_OVERRIDE` envelope had an approval and no refusal, so a rejected exception left a `PENDING` row with a live SLA clock for ever.\n\n**Its own token, not `.override_approve`.** #335 split the override grants from the settlement's precisely so one grant could never cover two decisions, and the same argument separates signing an exception off from refusing it. **MC-1**, not MC-2: refusing returns the settlement to exactly the figures the engine computed, which is the safe direction, while approving is the departure from them. Four-eyes still binds on both verbs — the requester may not refuse their own exception, or one person could walk an override round the loop unobserved.\n\nThe unified approvals drawer reaches this same transition through `ApprovalSourceActionRouter`, so a `REJECT` taken there and one taken here produce the same row.\n",
        "tags": [
          "pay",
          "full_final_settlement"
        ],
        "x-token": "pay.full_final_settlement.reject_override",
        "x-realizes-features": [
          "PAY-F07"
        ],
        "x-screens": [
          "PAY-S15"
        ],
        "x-touches-entities": [
          "pay.full_final_settlement_overrides"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "pay.full_final_settlement.override_rejected",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "overrideId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "note": {
                    "type": "string",
                    "maxLength": 1000,
                    "description": "Why the exception was refused. Recorded on the audit row and carried onto the envelope's `decision_note`, so the requester reads a reason rather than only a refusal.\n"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rejected override.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FullFinalSettlementOverride"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          }
        }
      }
    },
    "/tax-regime-choices": {
      "get": {
        "operationId": "tax.tax_regime_choice.list",
        "summary": "My tax regime elections",
        "description": "The employee's India regime elections by fiscal year, India-only (TAX-S01, db 07 §2.1).",
        "tags": [
          "tax",
          "tax_regime_choice"
        ],
        "x-token": "tax.tax_regime_choice.list",
        "x-realizes-features": [
          "TAX-F01"
        ],
        "x-screens": [
          "TAX-S01"
        ],
        "x-touches-entities": [
          "tax.tax_regime_choices"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "fiscal_year",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: fiscal_year, -fiscal_year.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of the caller's own regime elections.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxRegimeChoicePage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "operationId": "tax.tax_regime_choice.create",
        "summary": "Elect the income-tax regime for a fiscal year",
        "description": "One live choice per (employee, fiscal_year); drives payroll TDS (TAX-S01, PAY-F02, db 07 §2.1).",
        "tags": [
          "tax",
          "tax_regime_choice"
        ],
        "x-token": "tax.tax_regime_choice.create",
        "x-realizes-features": [
          "TAX-F01"
        ],
        "x-screens": [
          "TAX-S01"
        ],
        "x-touches-entities": [
          "tax.tax_regime_choices"
        ],
        "x-idempotent": true,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": "tax.tax_regime_choice.chosen",
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TaxRegimeChoiceCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Regime elected.",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxRegimeChoice"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-regime-choices/{id}": {
      "patch": {
        "operationId": "tax.tax_regime_choice.update",
        "summary": "Amend a regime election before lock",
        "description": "Change before is_locked is an in-place edit; once locked the FY's choice is fixed — a correction is a new-FY election, blocked with 409 otherwise (TAX-S01, db 07 §2.1).",
        "tags": [
          "tax",
          "tax_regime_choice"
        ],
        "x-token": "tax.tax_regime_choice.update",
        "x-realizes-features": [
          "TAX-F01"
        ],
        "x-screens": [
          "TAX-S01"
        ],
        "x-touches-entities": [
          "tax.tax_regime_choices"
        ],
        "x-idempotent": true,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": "tax.tax_regime_choice.changed",
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TaxRegimeChoiceUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated regime election.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxRegimeChoice"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-regime-choices/admin": {
      "get": {
        "operationId": "tax.tax_regime_choice.list_admin",
        "summary": "Regime elections (Finance view)",
        "description": "Finance's read view of employees' regime choices for audit and payroll alignment (TAX-S05, db 07 §2.1). Widened x-rls-scope tenant relative to tax.tax_regime_choice.list.",
        "tags": [
          "tax",
          "tax_regime_choice"
        ],
        "x-token": "tax.tax_regime_choice.list_admin",
        "x-realizes-features": [
          "TAX-F01"
        ],
        "x-screens": [
          "TAX-S05"
        ],
        "x-touches-entities": [
          "tax.tax_regime_choices"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "fiscal_year",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "regime",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/TaxRegime"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: fiscal_year, employee_id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tenant-wide page of regime elections.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxRegimeChoicePage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-declarations": {
      "post": {
        "operationId": "tax.tax_declaration.create",
        "summary": "Open an investment-declaration header",
        "description": "One per (employee, fiscal_year, window); regime snapshotted from the current election (TAX-S02, db 07 §2.1).",
        "tags": [
          "tax",
          "tax_declaration"
        ],
        "x-token": "tax.tax_declaration.create",
        "x-realizes-features": [
          "TAX-F02"
        ],
        "x-screens": [
          "TAX-S02"
        ],
        "x-touches-entities": [
          "tax.tax_declarations",
          "tax.tax_regime_choices"
        ],
        "x-idempotent": true,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TaxDeclarationCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Declaration opened (status DRAFT).",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxDeclaration"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "get": {
        "operationId": "tax.tax_declaration.list",
        "summary": "My investment declarations",
        "description": "The employee's declarations by fiscal year and window, with the running verification rollup (TAX-S02, db 07 §2.1).",
        "tags": [
          "tax",
          "tax_declaration"
        ],
        "x-token": "tax.tax_declaration.list",
        "x-realizes-features": [
          "TAX-F02"
        ],
        "x-screens": [
          "TAX-S02"
        ],
        "x-touches-entities": [
          "tax.tax_declarations"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "fiscal_year",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "window",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/DeclarationWindow"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/TaxDeclarationStatus"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: fiscal_year, -fiscal_year, status.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of the caller's own declarations.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxDeclarationPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-declarations/{id}": {
      "get": {
        "operationId": "tax.tax_declaration.get",
        "summary": "Get one investment declaration, with its item lines",
        "description": "Declaration detail for the employee's own declaration, with its item lines EMBEDDED as `items` (TAX-S02 · TAX-S08, db 07 §2.1). The embed exists because this is the only self-scoped read of those lines: `tax.declaration_item.list_admin` is TENANT-scoped Finance territory, so without it an employee could write their declaration but never read it back after a reload. Bounded by the statutory `SECTIONS` enum, hence embedded rather than paged; the admin path keeps its dedicated paged items route and its own unchanged response shape.",
        "tags": [
          "tax",
          "tax_declaration"
        ],
        "x-token": "tax.tax_declaration.get",
        "x-realizes-features": [
          "TAX-F02"
        ],
        "x-screens": [
          "TAX-S02"
        ],
        "x-touches-entities": [
          "tax.tax_declarations"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "The declaration, with its item lines embedded.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxDeclarationDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-declarations/{id}/submit": {
      "post": {
        "operationId": "tax.tax_declaration.submit",
        "summary": "Submit the investment declaration",
        "description": "Status DRAFT to SUBMITTED; routes to Finance review (TAX-S02, PAY-F02, db 07 §2.1).",
        "tags": [
          "tax",
          "tax_declaration"
        ],
        "x-token": "tax.tax_declaration.submit",
        "x-realizes-features": [
          "TAX-F02"
        ],
        "x-screens": [
          "TAX-S02"
        ],
        "x-touches-entities": [
          "tax.tax_declarations"
        ],
        "x-idempotent": true,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": "tax.tax_declaration.submitted",
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalDecisionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submitted.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxDeclaration"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-declarations/admin": {
      "get": {
        "operationId": "tax.tax_declaration.list_admin",
        "summary": "Investment declarations (Finance view)",
        "description": "Finance's tenant-wide declaration grid for audit and payroll alignment (TAX-S05, db 07 §2.1). Widened x-rls-scope tenant relative to tax.tax_declaration.list.",
        "tags": [
          "tax",
          "tax_declaration"
        ],
        "x-token": "tax.tax_declaration.list_admin",
        "x-realizes-features": [
          "TAX-F01",
          "TAX-F02"
        ],
        "x-screens": [
          "TAX-S05"
        ],
        "x-touches-entities": [
          "tax.tax_declarations",
          "tax.tax_regime_choices"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "fiscal_year",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/TaxDeclarationStatus"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: fiscal_year, employee_id, status.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tenant-wide page of investment declarations.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxDeclarationPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-declarations/admin/exports": {
      "post": {
        "operationId": "tax.tax_declaration.export",
        "summary": "Export the current Finance declarations view as CSV",
        "description": "Generates a CSV from the supplied fiscal-year, legal-entity, and status filters, stores it as a temporary object, and returns a 15-minute presigned download handle. The operation is idempotency-keyed, capped at 10000 rows, neutralizes spreadsheet formulas, and records both artifact audit evidence and a SALARY-classified privileged-read access event.\n",
        "tags": [
          "tax",
          "tax_declaration"
        ],
        "x-token": "tax.tax_declaration.export",
        "x-realizes-features": [
          "TAX-F01",
          "TAX-F02"
        ],
        "x-screens": [
          "TAX-S05"
        ],
        "x-touches-entities": [
          "tax.tax_declarations",
          "people.employees",
          "org.legal_entities",
          "xc.object_refs",
          "audit.audit_log",
          "audit.access_log"
        ],
        "x-idempotent": true,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TaxDeclarationExportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Temporary presigned CSV download.",
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileDownloadRef"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-declarations/admin/roster": {
      "get": {
        "operationId": "tax.tax_declaration.roster",
        "summary": "Finance-scoped employee and legal-entity roster for declaration reconciliation",
        "description": "Returns only the minimal active employee identity and legal-entity fields TAX-S05 needs to render not-declared rows and its entity filter. This is a dedicated Finance contract; the web does not borrow people.employee.list or acquire HR's broader employee-master permission.\n",
        "tags": [
          "tax",
          "tax_declaration"
        ],
        "x-token": "tax.tax_declaration.roster",
        "x-realizes-features": [
          "TAX-F01",
          "TAX-F02"
        ],
        "x-screens": [
          "TAX-S05"
        ],
        "x-touches-entities": [
          "people.employees",
          "org.legal_entities"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "legal_entity_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cursor page of non-terminal employees visible to the Finance tax workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxDeclarationRosterPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-declarations/admin/{id}": {
      "get": {
        "operationId": "tax.tax_declaration.get_admin",
        "summary": "Get one declaration (Finance verification view)",
        "description": "The declaration rollup panel behind the proof-verification drawer (TAX-S06, db 07 §2.1).",
        "tags": [
          "tax",
          "tax_declaration"
        ],
        "x-token": "tax.tax_declaration.get_admin",
        "x-realizes-features": [
          "TAX-F03"
        ],
        "x-screens": [
          "TAX-S06"
        ],
        "x-touches-entities": [
          "tax.tax_declarations"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "The declaration header, for the verification drawer's rollup panel.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxDeclaration"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-declarations/{id}/items": {
      "post": {
        "operationId": "tax.declaration_item.create",
        "summary": "Declare a deduction line",
        "description": "A section/sub-category claim (80C, 80D, HRA, ...); eligible_amount is declared capped to the statutory cap from the pack (TAX-S02, db 07 §2.1).",
        "tags": [
          "tax",
          "declaration_item"
        ],
        "x-token": "tax.declaration_item.create",
        "x-realizes-features": [
          "TAX-F02"
        ],
        "x-screens": [
          "TAX-S02"
        ],
        "x-touches-entities": [
          "tax.declaration_items",
          "tax.tax_declarations"
        ],
        "x-idempotent": true,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeclarationItemCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Declaration item added (status DECLARED).",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeclarationItem"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-declarations/{id}/items/{item_id}": {
      "patch": {
        "operationId": "tax.declaration_item.update",
        "summary": "Edit a declared deduction line",
        "description": "Edits declared_amount/sub_category before submit (TAX-S02, db 07 §2.1).",
        "tags": [
          "tax",
          "declaration_item"
        ],
        "x-token": "tax.declaration_item.update",
        "x-realizes-features": [
          "TAX-F02"
        ],
        "x-screens": [
          "TAX-S02"
        ],
        "x-touches-entities": [
          "tax.declaration_items"
        ],
        "x-idempotent": true,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "description": "UUIDv7 of the tax.declaration_items row.",
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeclarationItemUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated declaration item.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeclarationItem"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-declarations/admin/{id}/items": {
      "get": {
        "operationId": "tax.declaration_item.list_admin",
        "summary": "Declaration items grid (Finance verification)",
        "description": "Item, section, declared, eligible, proof status, verification status for one declaration (TAX-S06, db 07 §2.1).",
        "tags": [
          "tax",
          "declaration_item"
        ],
        "x-token": "tax.declaration_item.list_admin",
        "x-realizes-features": [
          "TAX-F03"
        ],
        "x-screens": [
          "TAX-S06"
        ],
        "x-touches-entities": [
          "tax.declaration_items"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/DeclarationItemStatus"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: section, status.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of declaration items for the given declaration.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeclarationItemPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/declaration-items/{id}/proofs": {
      "post": {
        "operationId": "tax.tax_proof.create",
        "summary": "Upload a supporting proof",
        "description": "Attaches a proof document against a declared item; converts it toward a Finance-verified deduction (TAX-S03, XC-F07, db 07 §2.2).",
        "tags": [
          "tax",
          "tax_proof"
        ],
        "x-token": "tax.tax_proof.create",
        "x-realizes-features": [
          "TAX-F03"
        ],
        "x-screens": [
          "TAX-S03"
        ],
        "x-touches-entities": [
          "tax.tax_proofs",
          "tax.declaration_items"
        ],
        "x-idempotent": true,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": "tax.tax_proof.submitted",
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TaxProofCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Proof submitted (status SUBMITTED).",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxProof"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "get": {
        "operationId": "tax.tax_proof.list",
        "summary": "My proofs for a declaration item",
        "description": "Status chips per uploaded proof, including RESUBMIT reasons (TAX-S03, db 07 §2.2).",
        "tags": [
          "tax",
          "tax_proof"
        ],
        "x-token": "tax.tax_proof.list",
        "x-realizes-features": [
          "TAX-F03"
        ],
        "x-screens": [
          "TAX-S03"
        ],
        "x-touches-entities": [
          "tax.tax_proofs"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: created_at, -created_at, status.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of proofs on the given declaration item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxProofPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-proofs/admin": {
      "get": {
        "operationId": "tax.tax_proof.list_admin",
        "summary": "Proof verification queue (Finance)",
        "description": "Finance's queue of submitted proofs to review, with the declared/eligible/verified figures (TAX-S06, db 07 §2.2).",
        "tags": [
          "tax",
          "tax_proof"
        ],
        "x-token": "tax.tax_proof.list_admin",
        "x-realizes-features": [
          "TAX-F03"
        ],
        "x-screens": [
          "TAX-S06"
        ],
        "x-touches-entities": [
          "tax.tax_proofs"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/TaxProofStatus"
            }
          },
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "declaration_item_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: created_at, -created_at, status.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of proofs to verify.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxProofPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-proofs/admin/{id}/approve": {
      "post": {
        "operationId": "tax.tax_proof.approve",
        "summary": "Verify a proof",
        "description": "Sets amount_verified, verified_by, verified_at; status to VERIFIED, cascades to the parent declaration_items.verified_amount/status; TDS recomputes for the employee (TAX-S06, PAY-F02, db 07 §2.2).",
        "tags": [
          "tax",
          "tax_proof"
        ],
        "x-token": "tax.tax_proof.approve",
        "x-realizes-features": [
          "TAX-F03"
        ],
        "x-screens": [
          "TAX-S06"
        ],
        "x-touches-entities": [
          "tax.tax_proofs",
          "tax.declaration_items",
          "tax.tax_declarations"
        ],
        "x-idempotent": true,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": "tax.tax_proof.verified",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TaxProofDecision"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verified.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxProof"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-proofs/admin/{id}/reject": {
      "post": {
        "operationId": "tax.tax_proof.reject",
        "summary": "Reject a proof",
        "description": "Sets rejection_reason; status to REJECTED, cascades to declaration_items.status REJECTED (TAX-S06, db 07 §2.2).",
        "tags": [
          "tax",
          "tax_proof"
        ],
        "x-token": "tax.tax_proof.reject",
        "x-realizes-features": [
          "TAX-F03"
        ],
        "x-screens": [
          "TAX-S06"
        ],
        "x-touches-entities": [
          "tax.tax_proofs",
          "tax.declaration_items"
        ],
        "x-idempotent": true,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": "tax.tax_proof.rejected",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TaxProofDecision"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rejected.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxProof"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tax-proofs/admin/{id}/request-resubmit": {
      "post": {
        "operationId": "tax.tax_proof.request_resubmit",
        "summary": "Return a proof for resubmission",
        "description": "Sets rejection_reason (returned reason); status to RESUBMIT, employee re-uploads on TAX-S03 (TAX-S06, db 07 §2.2).",
        "tags": [
          "tax",
          "tax_proof"
        ],
        "x-token": "tax.tax_proof.request_resubmit",
        "x-realizes-features": [
          "TAX-F03"
        ],
        "x-screens": [
          "TAX-S06"
        ],
        "x-touches-entities": [
          "tax.tax_proofs"
        ],
        "x-idempotent": true,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": "tax.tax_proof.resubmit_requested",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TaxProofDecision"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Returned for resubmission.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxProof"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "428": {
            "$ref": "#/components/responses/PreconditionRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/form16": {
      "get": {
        "operationId": "tax.form16.list",
        "summary": "My Form 16 certificates",
        "description": "The employee's issued Form 16 by fiscal year; a reissue is a new row, current resolved by latest issued_at (TAX-S04, db 07 §2.2).",
        "tags": [
          "tax",
          "form16"
        ],
        "x-token": "tax.form16.list",
        "x-realizes-features": [
          "TAX-F04"
        ],
        "x-screens": [
          "TAX-S04"
        ],
        "x-touches-entities": [
          "tax.form16"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "fiscal_year",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: fiscal_year, -fiscal_year, issued_at.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of the caller's own Form 16 certificates.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Form16Page"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/form16/{id}/download": {
      "get": {
        "operationId": "tax.form16.download",
        "summary": "Download the Form 16 PDF",
        "description": "Presigned download of the issued combined Part A + Part B PDF; integrity by content_hash (TAX-S04 Download, XC-F07, db 07 §2.2).",
        "tags": [
          "tax",
          "form16"
        ],
        "x-token": "tax.form16.download",
        "x-realizes-features": [
          "TAX-F04"
        ],
        "x-screens": [
          "TAX-S04"
        ],
        "x-touches-entities": [
          "tax.form16"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          }
        ],
        "responses": {
          "200": {
            "description": "Presigned download handle for the Form 16 PDF.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileDownloadRef"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/form16/admin": {
      "get": {
        "operationId": "tax.form16.list_admin",
        "summary": "Form 16 issuance grid (Finance)",
        "description": "Employee, FY, taxable income, TDS deposited, Form 16 status, for the post-FY issuance run (TAX-S07, db 07 §2.2).",
        "tags": [
          "tax",
          "form16"
        ],
        "x-token": "tax.form16.list_admin",
        "x-realizes-features": [
          "TAX-F04"
        ],
        "x-screens": [
          "TAX-S07"
        ],
        "x-touches-entities": [
          "tax.form16"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "fiscal_year",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: fiscal_year, employee_id, employee_name.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tenant-wide page of Form 16 certificates.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Form16AdminGridPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/form16/admin/issue": {
      "post": {
        "operationId": "tax.form16.issue",
        "summary": "Generate & issue Form 16 for verified employees",
        "description": "TRACES integration (Part A) + payroll Part B built from tds_records across the year's runs, for one employee_id or (when omitted) every verified employee in the fiscal_year (\"Generate Form 16 for All Verified\") — runs on the jobs tier (TAX-S07, PAY-F02, XC-F08, db 07 §2.2). Async. Part A is acquired through the TRACES filing port, never fabricated by payroll (#176). Refused with 409 unless ALL of: the employee's legal entity is an India entity (le.market='IN' — Form 16 is India-only), their declaration for the year is VERIFIED or LOCKED, and the year's tds_records are backed by a payroll run in EXECUTED or PUBLISHED (a run still EXECUTING, or one later CANCELLED, certifies nothing).\n",
        "tags": [
          "tax",
          "form16"
        ],
        "x-token": "tax.form16.issue",
        "x-realizes-features": [
          "TAX-F04"
        ],
        "x-screens": [
          "TAX-S07"
        ],
        "x-touches-entities": [
          "tax.form16",
          "tax.tds_records",
          "pay.payslips",
          "pay.payroll_runs",
          "org.legal_entities",
          "people.employees"
        ],
        "x-idempotent": true,
        "x-market": "India",
        "x-sync-async": "async",
        "x-emits-event": "tax.form16.issued",
        "x-rls-scope": "tenant",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Form16IssueRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Issuance enqueued; subscribe to tax.form16.issued for the resulting certificate(s).",
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Form16IssueAccepted"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/form16/admin/issue-batch": {
      "post": {
        "operationId": "tax.form16.issue_batch",
        "summary": "Generate & issue Form 16 for every verified employee in a fiscal year",
        "description": "The \"Generate Form 16 for All Verified\" run (TAX-S07): enqueues issuance for every employee whose declaration is VERIFIED or LOCKED for the fiscal_year and who has no certificate yet, optionally narrowed to one legal_entity_id. Its own operation and its own token rather than a body variant of tax.form16.issue — one call can enqueue thousands of certificates, so it is granted, audited and rate-limited in its own right. Runs on the jobs tier (XC-F08). Async. Candidates are narrowed by exactly the gates tax.form16.issue applies one employee at a time (#176): India legal entity, VERIFIED/LOCKED declaration, and tds_records backed by an EXECUTED/PUBLISHED payroll run. An employee failing any of them is silently not a candidate rather than failing the batch, so `issued` is the count that actually met the bar.\n",
        "tags": [
          "tax",
          "form16"
        ],
        "x-token": "tax.form16.issue_batch",
        "x-realizes-features": [
          "TAX-F04"
        ],
        "x-screens": [
          "TAX-S07"
        ],
        "x-touches-entities": [
          "tax.form16",
          "tax.tds_records",
          "tax.tax_declarations",
          "org.legal_entities",
          "people.employees"
        ],
        "x-idempotent": true,
        "x-market": "India",
        "x-sync-async": "async",
        "x-emits-event": "tax.form16.issued",
        "x-rls-scope": "tenant",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Form16IssueBatchRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Batch issuance enqueued; subscribe to tax.form16.issued for the resulting certificates.",
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Form16IssueBatchAccepted"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/form16/admin/{id}/reissue": {
      "post": {
        "operationId": "tax.form16.reissue",
        "summary": "Reissue a Form 16 (new compensating certificate)",
        "description": "Creates a NEW row with a new form16_no for the same employee/FY — never an edit of the original (TAX-S07 Reissue, db 07 §2.2). Async (TRACES/jobs tier). A reissue clears the same gates as a first issue (India entity, VERIFIED/LOCKED declaration, EXECUTED/PUBLISHED-run-backed TDS — 409 otherwise) and additionally takes MC-1 four-eyes: the principal who issued the certificate being compensated may not reissue it, answered 403 MAKER_EQUALS_CHECKER (security-docs/04 §MC-1, #176). Certificates issued before #176 carry no recorded issuer and are exempt from that leg.\n",
        "tags": [
          "tax",
          "form16"
        ],
        "x-token": "tax.form16.reissue",
        "x-realizes-features": [
          "TAX-F04"
        ],
        "x-screens": [
          "TAX-S07"
        ],
        "x-touches-entities": [
          "tax.form16"
        ],
        "x-idempotent": true,
        "x-market": "India",
        "x-sync-async": "async",
        "x-emits-event": "tax.form16.reissued",
        "x-rls-scope": "tenant",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "202": {
            "description": "Reissue enqueued; subscribe to tax.form16.reissued for the new certificate.",
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Form16IssueAccepted"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "423": {
            "$ref": "#/components/responses/Locked"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tds-records": {
      "get": {
        "operationId": "tax.tds_record.list",
        "summary": "My TDS withheld by period",
        "description": "Per-month TDS withheld, projected-annual basis, and challan/TRACES references (TAX-S04, db 07 §2.2).",
        "tags": [
          "tax",
          "tds_record"
        ],
        "x-token": "tax.tds_record.list",
        "x-realizes-features": [
          "TAX-F04"
        ],
        "x-screens": [
          "TAX-S04"
        ],
        "x-touches-entities": [
          "tax.tds_records"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "self",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "fiscal_year",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "quarter",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/TaxQuarter"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: wage_month, -wage_month.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of the caller's own TDS records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TdsRecordPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tds-records/admin": {
      "get": {
        "operationId": "tax.tds_record.list_admin",
        "summary": "TDS records (Finance — Form 16 source data)",
        "description": "The year's TDS rows across all employees, the raw material Form 16 Part B is built from (TAX-S07, PAY-F02, db 07 §2.2).",
        "tags": [
          "tax",
          "tds_record"
        ],
        "x-token": "tax.tds_record.list_admin",
        "x-realizes-features": [
          "TAX-F04"
        ],
        "x-screens": [
          "TAX-S07"
        ],
        "x-touches-entities": [
          "tax.tds_records"
        ],
        "x-idempotent": false,
        "x-market": "India",
        "x-sync-async": "sync",
        "x-emits-event": null,
        "x-rls-scope": "tenant",
        "x-append-only": true,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          {
            "name": "fiscal_year",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "quarter",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/TaxQuarter"
            }
          },
          {
            "$ref": "#/components/parameters/PageSize"
          },
          {
            "$ref": "#/components/parameters/PageAfter"
          },
          {
            "$ref": "#/components/parameters/PageBefore"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort whitelist: wage_month, employee_id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tenant-wide page of TDS records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TdsRecordPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerJWT": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Product session token. Two mint paths, one contract (ADR 0010): employees/managers authenticate against Keycloak (mobile + web); workspace staff arrive from the One portal via bridge-token SSO (`POST /api/sso/exchange` verifies the platform's Ed25519 token and mints the product session). The token carries IDENTITY ONLY — `sub`, `tenantUid`, `principal_class`, MFA level, session ref, `exp`. Roles/permissions are re-resolved server-side per request. Enforcement is layered: gateway (TLS/WAF/routing only — NEVER trusted for auth) → NestJS auth guard (validates token, builds the request auth-context) → entitlement middleware (subscription-status → feature-flag → numeric-limit, ADR 0009) → `SET LOCAL app.tenant_id` / `app.user_id` → Postgres FORCED RLS. `tenantUid` is NEVER a path, query, or body parameter.\n"
      }
    },
    "schemas": {
      "UuidRef": {
        "$ref": "#/components/schemas/Uuid"
      },
      "DateOnlyRef": {
        "$ref": "#/components/schemas/DateOnly"
      },
      "TimestampRef": {
        "$ref": "#/components/schemas/Timestamp"
      },
      "DecimalHoursRef": {
        "$ref": "#/components/schemas/DecimalHours"
      },
      "RateRef": {
        "$ref": "#/components/schemas/Rate"
      },
      "MoneyRef": {
        "$ref": "#/components/schemas/Money"
      },
      "BusinessNoRef": {
        "$ref": "#/components/schemas/BusinessNo"
      },
      "CurrencyCodeRef": {
        "$ref": "#/components/schemas/CurrencyCode"
      },
      "AuditMetaRef": {
        "$ref": "#/components/schemas/AuditMeta"
      },
      "AppendOnlyMetaRef": {
        "$ref": "#/components/schemas/AppendOnlyMeta"
      },
      "CursorPageRef": {
        "$ref": "#/components/schemas/CursorPage"
      },
      "FileDownloadRef": {
        "$ref": "#/components/schemas/FileDownload"
      },
      "RunType": {
        "type": "string",
        "enum": [
          "REGULAR",
          "SUPPLEMENTARY",
          "ARREARS",
          "OFF_CYCLE",
          "FNF"
        ],
        "description": "pay.run_type (db 07 §1.1)."
      },
      "RunFrequency": {
        "type": "string",
        "enum": [
          "MONTHLY",
          "BIWEEKLY",
          "WEEKLY"
        ],
        "description": "pay.frequency (db 07 §1.1)."
      },
      "PayrollRunStatus": {
        "type": "string",
        "enum": [
          "DRAFT",
          "PREVIEWING",
          "PREVIEW",
          "APPROVED",
          "EXECUTING",
          "EXECUTED",
          "PUBLISHING",
          "PUBLISHED",
          "CANCELLED"
        ],
        "description": "pay.payroll_run_status (db 07 §1.1)."
      },
      "PayslipStatus": {
        "type": "string",
        "enum": [
          "DRAFT",
          "PUBLISHED",
          "CANCELLED"
        ],
        "description": "pay.payslip_status (db 07 §1.2)."
      },
      "EarningType": {
        "type": "string",
        "enum": [
          "FIXED",
          "VARIABLE",
          "ARREARS",
          "BONUS",
          "INCENTIVE",
          "REIMBURSEMENT",
          "OVERTIME",
          "LEAVE_ENCASHMENT",
          "ADHOC"
        ],
        "description": "pay.earning_type (db 07 §1.2)."
      },
      "DeductionType": {
        "type": "string",
        "enum": [
          "EPF",
          "EPS",
          "ESI",
          "PT",
          "TDS",
          "LWF",
          "VPF",
          "GOSI",
          "LOAN_EMI",
          "SALARY_ADVANCE",
          "SALARY_ADVANCE_REPAYMENT",
          "ESOP_PERQUISITE_TDS",
          "INSURANCE",
          "ADHOC",
          "OTHER"
        ],
        "description": "pay.deduction_type (db 07 §1.2)."
      },
      "ContributionSide": {
        "type": "string",
        "enum": [
          "EMPLOYEE",
          "EMPLOYER"
        ],
        "description": "pay.contribution_side (db 07 §1.2)."
      },
      "EsopGrantStatus": {
        "type": "string",
        "enum": [
          "GRANTED",
          "PARTIALLY_VESTED",
          "FULLY_VESTED",
          "EXERCISING",
          "EXERCISED",
          "FORFEITED",
          "LAPSED",
          "CANCELLED"
        ],
        "description": "pay.esop_grant_status (db 07 §1.3)."
      },
      "VestingStatus": {
        "type": "string",
        "enum": [
          "PENDING",
          "VESTED",
          "FORFEITED",
          "ACCELERATED"
        ],
        "description": "pay.vesting_status (db 07 §1.3)."
      },
      "EsopExerciseStatus": {
        "type": "string",
        "enum": [
          "REQUESTED",
          "APPROVED",
          "WITHHELD",
          "SETTLED",
          "REJECTED",
          "CANCELLED"
        ],
        "description": "pay.esop_exercise_status (db 07 §1.3)."
      },
      "SalaryAdvanceStatus": {
        "type": "string",
        "enum": [
          "REQUESTED",
          "APPROVED",
          "REJECTED",
          "DISBURSED",
          "RECOVERING",
          "RECOVERED",
          "WRITTEN_OFF",
          "CANCELLED"
        ],
        "description": "pay.salary_advance_status (db 07 §1.4)."
      },
      "LoanType": {
        "type": "string",
        "enum": [
          "PERSONAL",
          "HOUSING",
          "VEHICLE",
          "EMERGENCY",
          "FESTIVAL",
          "EDUCATION",
          "OTHER"
        ],
        "description": "pay.loan_type (db 07 §1.4)."
      },
      "EmployeeLoanStatus": {
        "type": "string",
        "enum": [
          "REQUESTED",
          "APPROVED",
          "REJECTED",
          "DISBURSED",
          "ACTIVE",
          "CLOSED",
          "FORECLOSED",
          "WRITTEN_OFF",
          "CANCELLED"
        ],
        "description": "pay.employee_loan_status (db 07 §1.4)."
      },
      "LoanEmiStatus": {
        "type": "string",
        "enum": [
          "SCHEDULED",
          "DUE",
          "RECOVERED",
          "PARTIAL",
          "DEFERRED",
          "WAIVED"
        ],
        "description": "pay.loan_emi_status (db 07 §1.4)."
      },
      "FullFinalSettlementStatus": {
        "type": "string",
        "enum": [
          "INITIATED",
          "CALCULATING",
          "PENDING_CLEARANCE",
          "PENDING_APPROVAL",
          "APPROVED",
          "SETTLED",
          "PUBLISHED",
          "CANCELLED"
        ],
        "description": "pay.full_final_settlement_status (db 07 §1.5)."
      },
      "TaxRegime": {
        "type": "string",
        "enum": [
          "OLD",
          "NEW"
        ],
        "description": "tax.regime (db 07 §2.1)."
      },
      "TaxRegimeSource": {
        "type": "string",
        "enum": [
          "EMPLOYEE_ELECTION",
          "STATUTORY_DEFAULT"
        ],
        "description": "'tax.regime_source (db 07 §2.2, migration 0146).' Where the regime on a TDS record came from. `EMPLOYEE_ELECTION` is a choice recorded on `tax.tax_regime_choices`; `STATUTORY_DEFAULT` means no election existed for the fiscal year and the ITA-2025 default (`NEW`) was applied at withholding time so the payroll run could proceed. A consumer must NOT present a `STATUTORY_DEFAULT` row as the employee's own election — a new joiner who has not yet elected is the common case.\n"
      },
      "DeclarationWindow": {
        "type": "string",
        "enum": [
          "PROVISIONAL",
          "FINAL"
        ],
        "description": "tax.declaration_window (db 07 §2.1)."
      },
      "TaxDeclarationStatus": {
        "type": "string",
        "enum": [
          "DRAFT",
          "SUBMITTED",
          "UNDER_REVIEW",
          "PARTIALLY_VERIFIED",
          "VERIFIED",
          "LOCKED",
          "REOPENED"
        ],
        "description": "tax.tax_declaration_status (db 07 §2.1)."
      },
      "DeclarationItemSection": {
        "type": "string",
        "enum": [
          "SEC_80C",
          "SEC_80D",
          "SEC_80CCD_1B",
          "HRA",
          "LTA",
          "SEC_24B",
          "SEC_80E",
          "SEC_80G",
          "SEC_80TTA",
          "CHAPTER_VIA_OTHER"
        ],
        "description": "tax.declaration_item_section (db 07 §2.1)."
      },
      "DeclarationItemStatus": {
        "type": "string",
        "enum": [
          "DECLARED",
          "PROOF_PENDING",
          "PROOF_SUBMITTED",
          "PARTIALLY_VERIFIED",
          "VERIFIED",
          "REJECTED"
        ],
        "description": "tax.declaration_item_status (db 07 §2.1)."
      },
      "TaxProofType": {
        "type": "string",
        "enum": [
          "RENT_RECEIPT",
          "INVESTMENT_CERTIFICATE",
          "INSURANCE_PREMIUM",
          "LOAN_STATEMENT",
          "TUITION_RECEIPT",
          "DONATION_RECEIPT",
          "OTHER"
        ],
        "description": "tax.proof_type (db 07 §2.2)."
      },
      "TaxProofStatus": {
        "type": "string",
        "enum": [
          "SUBMITTED",
          "UNDER_REVIEW",
          "VERIFIED",
          "REJECTED",
          "RESUBMIT"
        ],
        "description": "tax.tax_proof_status (db 07 §2.2)."
      },
      "TaxQuarter": {
        "type": "string",
        "enum": [
          "Q1",
          "Q2",
          "Q3",
          "Q4"
        ],
        "description": "tax.quarter (db 07 §2.2)."
      },
      "ApprovalDecisionInput": {
        "type": "object",
        "description": "Generic optional-note decision body shared by approve/reject/cancel/submit actions in this file.",
        "additionalProperties": false,
        "properties": {
          "note": {
            "type": "string"
          }
        }
      },
      "PayrollRun": {
        "description": "pay.payroll_runs — the orchestrator; one controlled run per legal entity per pay period (db 07 §1.1).",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "run_no",
              "legal_entity_id",
              "pay_group_id",
              "pay_period_id",
              "run_type",
              "frequency",
              "pay_period_start",
              "pay_period_end",
              "pay_date",
              "fiscal_year",
              "status"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "run_no": {
                "$ref": "#/components/schemas/BusinessNoRef"
              },
              "legal_entity_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "pay_group_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "pay_period_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The generated period anchor; null only for `OFF_CYCLE` runs."
              },
              "run_type": {
                "$ref": "#/components/schemas/RunType"
              },
              "frequency": {
                "$ref": "#/components/schemas/RunFrequency"
              },
              "pay_period_start": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "pay_period_end": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "pay_date": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "fiscal_year": {
                "type": "integer"
              },
              "status": {
                "$ref": "#/components/schemas/PayrollRunStatus"
              },
              "is_provisional": {
                "type": "boolean",
                "description": "**DERIVED, never a column** ([ADR 0069](../../../architecture-docs/adr/0069-pay-cycle-single-surface-disbursement-ledger-release-batches.md) §(b)): `true` while the run's pay period is `OPEN` or `CUTOFF_PASSED`, i.e. while the input set the figures were computed from can still change. Every amount on a provisional run is labelled *Provisional* on `PAY-S33`, and `pay.payroll_run.submit_for_approval` is refused until the period locks. `false` for a run with no period (`OFF_CYCLE`) — no cycle is not the same as an open one.\n"
              },
              "employee_count": {
                "type": "integer",
                "minimum": 0
              },
              "gross_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "total_deductions_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "net_pay_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "employer_cost_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "previous_run_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "compliance_pack_version": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "config_snapshot": {
                "anyOf": [
                  {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/ConfigVersionStamp"
                      },
                      {
                        "type": "object",
                        "properties": {
                          "pay_structure_versions": {
                            "type": "array",
                            "items": {
                              "type": "integer",
                              "minimum": 1
                            }
                          }
                        }
                      }
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Frozen at execution from calculated payslip stamps; publish validates without re-resolution."
              },
              "submitted_by": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "submitted_by_name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The MAKER, by name, on both `pay.payroll_run.list` and `pay.payroll_run.get` (issue #1640). Resolved by projection, not a join: `submitted_by` holds an `xc.identities.id` — a PRINCIPAL, stamped from the request context — and `xc.identities` carries no name column at all, so the server walks `identity → subject employee → full_name` and falls back to the identity's own `email` for a SERVICE or workspace-member principal that has no employee row by construction. An id written directly as an employee id resolves through a second, direct employee lookup. `null` while unsubmitted, and `null` (never an id-derived string) when neither hop can name the principal.\n"
              },
              "approved_by": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "approved_by_name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The CHECKER, by name, resolved exactly as `submitted_by_name` above (issue #1640). `null` while unapproved."
              },
              "approved_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "executed_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "published_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "PayrollRunCreate": {
        "type": "object",
        "required": [
          "legal_entity_id",
          "run_type",
          "frequency",
          "pay_period_start",
          "pay_period_end",
          "pay_date"
        ],
        "additionalProperties": false,
        "properties": {
          "legal_entity_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "pay_group_id": {
            "$ref": "#/components/schemas/UuidRef",
            "description": "When omitted, defaults to the legal entity's effective DEFAULT pay group."
          },
          "run_type": {
            "$ref": "#/components/schemas/RunType"
          },
          "frequency": {
            "$ref": "#/components/schemas/RunFrequency"
          },
          "pay_period_start": {
            "$ref": "#/components/schemas/DateOnlyRef"
          },
          "pay_period_end": {
            "$ref": "#/components/schemas/DateOnlyRef"
          },
          "pay_date": {
            "$ref": "#/components/schemas/DateOnlyRef"
          },
          "previous_run_id": {
            "$ref": "#/components/schemas/UuidRef"
          }
        }
      },
      "PayrollRunPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PayrollRun"
                }
              }
            }
          }
        ]
      },
      "CompensationRevisionReason": {
        "type": "string",
        "enum": [
          "HIRE",
          "PROMOTION",
          "ANNUAL_REVISION",
          "CORRECTION",
          "OTHER"
        ],
        "description": "'pay.compensation_revision_reason (db 07 §1.1).' `HIRE` opens the chain from an accepted offer or a guided onboarding · `PROMOTION` rides an `engage` promotion (ENG-F05) · `ANNUAL_REVISION` the increment cycle · `CORRECTION` fixes a mis-keyed record (the wrong row is closed and a new one opened, never edited retroactively into published slips) · `OTHER` anything else.\n"
      },
      "CompensationAmount": {
        "type": "string",
        "pattern": "^\\d+(\\.\\d{1,2})?$",
        "description": "numeric(18,2) annual amount as a **decimal string** (db-docs/00 §6) — e.g. \"1800000.00\". Never a JSON number: a binary double cannot hold a rupee or a halala exactly, and a payroll figure that has been through one is not the figure anyone agreed to. Deliberately NOT `MoneyRef`: on `pay.employee_compensation` the currency is a property of the **record** (derived from the employee's legal entity, one currency per entity) rather than of each amount, and pairing a currency with every amount would imply a caller could set it — which is exactly what `pay.employee_compensation.create` refuses.\n"
      },
      "EmployeeCompensationRecord": {
        "description": "'pay.employee_compensation — one effective-dated compensation state for one employee (db 07 §1.1).' The payroll engine reads the row effective on the pay period and stamps its values into the slip's `component_snapshot`, so a later revision never drifts a published slip. At most one row per employee is open (`effective_to = null`); the partial-unique `employee_compensation_one_open_per_employee_key` (migration `0064`) enforces it.\n",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "employee_id",
              "legal_entity_id",
              "pay_group_id",
              "pay_model",
              "effective_from",
              "ctc_amount",
              "basic_amount",
              "currency_code",
              "revision_reason"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef",
                "description": "ref→people.employees — whose compensation (soft ref, never a join)."
              },
              "legal_entity_id": {
                "$ref": "#/components/schemas/UuidRef",
                "description": "ref→org.legal_entities — the entity whose currency and market pack this record is read under."
              },
              "pay_structure_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "ref→org.pay_structures — the CTC blueprint this record binds, when one is assigned."
              },
              "pay_structure_version": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 1,
                "description": "Snapshot-stamped `version_no` of the bound structure (db-docs/00 §8) — a later structure version cannot re-interpret this assignment."
              },
              "pay_group_id": {
                "$ref": "#/components/schemas/UuidRef",
                "description": "Soft `ref→org.pay_groups` (ADR 0028 §(d)). Because compensation is already the one-open-row-per-employee anchor, **pay-group membership versions naturally with revisions** — moving someone between pay groups is an ordinary, dated compensation revision, which is what it actually is, and history stays answerable."
              },
              "pay_model": {
                "$ref": "#/components/schemas/PayModel",
                "description": "ADR 0033 §(a). `NOT NULL DEFAULT MONTHLY_SALARY`. A check constraint ties the bindings: `DAILY_WAGE` requires `rate_card_id`, `PIECE_RATE` requires `piece_rate_catalog_id`, `MONTHLY_SALARY` requires neither and keeps `pay_structure_id` as today."
              },
              "rate_card_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Soft `ref→org.rate_cards` — the `DAILY_WAGE` binding. Versioning is free: a rate-card move is a compensation revision, so a period already paid is never retroactively repriced."
              },
              "piece_rate_catalog_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Soft `ref→org.piece_rate_catalogs` — the `PIECE_RATE` binding."
              },
              "effective_from": {
                "$ref": "#/components/schemas/DateOnlyRef",
                "description": "First day this compensation applies."
              },
              "effective_to": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/DateOnlyRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Last day it applied; **null = the current record**. Set by the next revision, never edited by hand."
              },
              "ctc_amount": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/CompensationAmount"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Annual cost-to-company. **Present exactly when `pay_model` is `MONTHLY_SALARY`, and null otherwise** — a daily-wage or piece-rate worker has no annual CTC, and inventing one is the fiction ADR 0033 exists to prevent. Migration `0124` replaced the column `NOT NULL` with `employee_compensation_monthly_amounts_present`, which requires the amount for the salaried model and only for it."
              },
              "basic_amount": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/CompensationAmount"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Annual basic component — the statutory wage anchor the pack-driven math builds on (PF wage in India, GOSI wage in KSA). Nullable on the same `0124` rule as `ctc_amount`: present exactly for `MONTHLY_SALARY`."
              },
              "currency_code": {
                "$ref": "#/components/schemas/CurrencyCodeRef",
                "description": "Follows the legal entity (INR India / SAR KSA); never accepted from the caller."
              },
              "revision_reason": {
                "$ref": "#/components/schemas/CompensationRevisionReason"
              },
              "notes": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "pf_applicable": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "**EPF enrolment for this employment segment** (migration `0251`). Tri-state, and the third state is the point: `true` enrols and the payroll engine computes the contribution; `false` states an **exemption** (an intern, an international worker under a social-security agreement, a director outside the Act) and the engine computes nothing and reports nothing; `null` means **not stated**, and payroll behaves exactly as it did before the column existed — `pay.payroll_run.populate` falls back to inferring enrolment from a UAN on file. Enrolment sits on the compensation record and not on the employee because it CHANGES over an employment and a recomputed historical period must be computed as it stood; a revision inherits the open row's value where the caller states nothing, so a raise can never silently switch PF off.\n"
              },
              "esi_applicable": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "**ESI enrolment for this employment segment** (migration `0251`), with the same tri-state semantics as `pf_applicable`. The compliance pack's own wage threshold and its Apr–Sep / Oct–Mar contribution-period lock-in still apply **on top** of a `true`: this field says \"in the scheme\", not \"deduct regardless\".\n"
              },
              "revision_count": {
                "type": "integer",
                "minimum": 0,
                "description": "How many CORRECTIONS this record has taken through `pay.employee_compensation.update` — `pay.employee_compensation_revisions` rows, not chain revisions (a chain revision is a different record entirely). Present on the history read and on a correction's own response; **absent on create**, where a row that has just been opened has no correction history and publishing `0` would invite a client to render \"corrected 0 times\" on every new record. A non-zero count is what lets the `PPL-S14` Compensation tab say a figure was corrected without reading the corrections, which is a different operation with a different sensitivity and is deliberately not minted."
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "EmployeeCompensationHistory": {
        "type": "object",
        "description": "The employee's whole compensation chain, sorted `effective_from` **descending** — current record first. Not a `CursorPageRef`: the series is small and bounded, and the question it answers (\"what was this employee's compensation for this period\") is a question about the chain rather than about any one row, so it is returned whole rather than windowed. `currency_code` is hoisted onto the envelope because a legal entity operates in a single currency (db-docs/00 §6) — repeating it per row would imply it could vary between revisions.\n",
        "required": [
          "employee_id",
          "currency_code",
          "records"
        ],
        "additionalProperties": false,
        "properties": {
          "employee_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "currency_code": {
            "$ref": "#/components/schemas/CurrencyCodeRef",
            "description": "Derived from the employee's legal entity."
          },
          "records": {
            "type": "array",
            "description": "Empty for an employee who has no compensation record yet — a legitimate state for hires made before this surface existed, not an error.",
            "items": {
              "$ref": "#/components/schemas/EmployeeCompensationRecord"
            }
          }
        }
      },
      "EmployeeCompensationCreateInput": {
        "type": "object",
        "description": "Opens a new compensation record and closes the currently open one in the same transaction. `currency_code` is **not accepted** — it is derived from the employee's legal entity, so an INR/SAR mix-up is impossible by construction; supplying it is a `422`. `effective_to` is not accepted either: a row is closed only by the next revision, never set by a caller. `tenant_id` is never on the wire (00 §5).\n\n**As-built note (2026-08-14, migration `0124`, issue #580).** The three ADR 0033 fields below — `pay_model`, `rate_card_id`, `piece_rate_catalog_id` — are the specified write surface but are **not yet accepted by the running service**: the columns exist and are readable on `EmployeeCompensationRecord`, and a row created through this operation is `MONTHLY_SALARY` with both bindings null. Supplying them today is rejected as an unknown property. Accepting them (with the cross-field validation described below) belongs to the dispatch owner, issue #576. Until then the non-monthly population is written by the demo seed and by migration, not over HTTP.\n",
        "required": [
          "effective_from",
          "ctc_amount",
          "basic_amount",
          "revision_reason"
        ],
        "additionalProperties": false,
        "properties": {
          "effective_from": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DateOnlyRef"
              }
            ],
            "description": "First day the new compensation applies. Must be **strictly after** the open row's `effective_from`; back-dating over the live record is a `422` with rule `cross-field`, never a silent overlap. The open row is closed at `effective_from - 1 day`.\n"
          },
          "ctc_amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CompensationAmount"
              }
            ],
            "description": "Annual cost-to-company, decimal string, `>= 0`."
          },
          "basic_amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CompensationAmount"
              }
            ],
            "description": "Annual basic, decimal string, `>= 0` and `<= ctc_amount` (a violation is a `422`, rule `cross-field`)."
          },
          "revision_reason": {
            "$ref": "#/components/schemas/CompensationRevisionReason"
          },
          "pay_structure_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "'ref→org.pay_structures.' Optional. When supplied the structure must be `PUBLISHED` **and** belong to the same legal entity as the employee; its `version_no` is stamped into `pay_structure_version` on the created row.\n"
          },
          "pay_group_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "'ref→org.pay_groups.' Optional; defaults to the legal entity's `DEFAULT` group (every existing legal entity acquires one at migration time, so no tenant needs operator action to keep working). Changing it here is how an employee moves between populations — dated, historied and replayable, with no separate versioning machinery.\n"
          },
          "pay_model": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PayModel"
              }
            ],
            "description": "ADR 0033 §(a). Defaults to `MONTHLY_SALARY`. `DAILY_WAGE` **requires** `rate_card_id` and `PIECE_RATE` **requires** `piece_rate_catalog_id` — a mismatch is a `422` with rule `cross-field`, matching the database check constraint rather than discovering it at populate time. Confirming a daily-wage worker onto monthly salary is an ordinary revision with an effective date and a reason, which is exactly why the axis lives here and not on `people.employees`.\n"
          },
          "rate_card_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "ref→org.rate_cards — must be effective across `effective_from` and belong to the employee's legal entity."
          },
          "piece_rate_catalog_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "ref→org.piece_rate_catalogs — its `unit_code`s are the same vocabulary `attend.muster_entries.units_done` is captured against, so capture and pricing never need a translation step."
          },
          "notes": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2000
          },
          "pf_applicable": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "**EPF enrolment for the segment this record opens** (migration `0251`). Optional and tri-state: omitting it is **not** `false`. On a first-ever record, omitting it leaves the column `null` — \"not stated\" — and payroll falls back to the UAN inference. On a **revision**, omitting it means *unchanged*: the currently-open row's value is inherited (`COALESCE`), because a raise is not also a statutory-enrolment decision and a field that reset to `null` on every revision would hand PF back to an inference and could stop a deduction that ran last month. Sending `false` states an exemption. To RETRACT a statement, correct the record with `PATCH … { \"pf_applicable\": null }`. A non-boolean (`\"true\"`, `1`) is refused with a `422` rather than interpreted.\n"
          },
          "esi_applicable": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "**ESI enrolment for the segment this record opens** (migration `0251`), with the same optional, tri-state, inherited-on-revision semantics as `pf_applicable`.\n"
          }
        }
      },
      "EmployeeCompensationCreated": {
        "description": "The newly opened record, plus the id of the row this write closed — so the caller can see the chain edit it caused without re-reading the history.\n",
        "allOf": [
          {
            "$ref": "#/components/schemas/EmployeeCompensationRecord"
          },
          {
            "type": "object",
            "properties": {
              "closed_previous_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The previously open record, now closed at `effective_from - 1 day`. `null` when this is the employee's first-ever compensation record and there was nothing to close.\n"
              }
            }
          }
        ]
      },
      "EmployeeCompensationCorrectionInput": {
        "type": "object",
        "description": "Corrects a record that already exists. Every field is optional **except `correction_reason`**, and at least one correctable field must be present — a PATCH that changes nothing is a caller bug, not a no-op success, and is a `422` at `/`. Presence is what is read, not truthiness: an explicit `null` on `pay_structure_id`, `pay_group_id` or `notes` means *clear this*, while omitting the field means *leave it exactly as it is*. That distinction is the only thing a PATCH has, and it is why this is not `EmployeeCompensationCreateInput` with everything made optional.\n\n**Not accepted, and refused by name rather than ignored** — a silently dropped field is the failure that surfaces three payroll runs later: `currency_code` (derived from the legal entity), `employee_id` and `legal_entity_id` (a record cannot be moved between people or entities — end this one and open another), `version` (assert the version you read in `If-Match`; a body cannot set it), and `pay_model` / `rate_card_id` / `piece_rate_catalog_id` (ADR 0033's dispatch axis, still not writable over HTTP — issue #576). `effective_to` is not accepted either, for the reason it is not accepted on create: a record is closed by whoever starts next, never by hand. `tenant_id` is never on the wire (00 §5).\n",
        "required": [
          "correction_reason"
        ],
        "additionalProperties": false,
        "minProperties": 2,
        "properties": {
          "correction_reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500,
            "description": "Why the record is being corrected — required, trimmed, and stored on the `pay.employee_compensation_revisions` row. A corrected payroll figure with no stated reason is unauditable the following year, when the revision row is the only thing that can answer \"why does this differ from the offer letter\". It is deliberately **not** copied into `audit.audit_log`: free text about a pay change is exactly where somebody types the figure, and the audit plane is exempt from erasure.\n"
          },
          "effective_from": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DateOnlyRef"
              }
            ],
            "description": "Corrects the day this record starts applying. Must be **strictly after** the predecessor's `effective_from`, and **on or before** this record's own `effective_to` when it is closed — both `422` with rule `cross-field`. When it moves and a predecessor exists, the predecessor is **re-closed** at `effective_from - 1 day` in the same transaction, so the chain stays gapless and overlap-free. To move a record past a neighbour, correct the neighbour first.\n"
          },
          "ctc_amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CompensationAmount"
              }
            ],
            "description": "Annual cost-to-company, decimal string, `>= 0`."
          },
          "basic_amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CompensationAmount"
              }
            ],
            "description": "Annual basic, decimal string, `>= 0`. Checked `<= ctc_amount` on the **merged** record — the supplied `ctc_amount` if there is one, otherwise the stored one — as exact minor units and never as a float. Raising this past a CTC the caller did not send is the mistake a partial update makes easy; it is a `422` with rule `cross-field`, not the 500 the DB CHECK would otherwise produce.\n"
          },
          "revision_reason": {
            "$ref": "#/components/schemas/CompensationRevisionReason"
          },
          "pay_structure_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "Re-points the structure binding. Re-resolved from scratch — `PUBLISHED`, same legal entity, `version_no` re-stamped into `pay_structure_version` — because \"it was valid when it was first assigned\" is not the question a correction asks. An explicit `null` clears the binding and the stamped version with it.\n"
          },
          "pay_group_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "Re-resolved against the record's **post-merge** effective date whenever either this or `effective_from` moves: a pay group is effective only across a window of its own, so a record sliding to a new start date can slide off the group it was on. Omitting the field keeps the record's OWN group — unlike `.create`, which falls back to the entity default, because on create there is no group to keep and here there is, and silently re-defaulting somebody's payroll population is a correction nobody asked for. An explicit `null` asks for that default.\n"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2000
          },
          "pf_applicable": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Corrects the EPF enrolment stated on this record (migration `0251`). Presence is what is read: an explicit `null` **retracts** the statement and returns the row to \"not stated\" — it does not mean `false`, which states an exemption — and omitting the field leaves the column exactly as it is. The field is recorded in the revision's `changed_fields` with its before/after values like any other correctable field.\n"
          },
          "esi_applicable": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Corrects the ESI enrolment stated on this record (migration `0251`), with the same three-way presence semantics as `pf_applicable`."
          }
        }
      },
      "EmployeeCompensationCorrected": {
        "description": "The corrected record, at its new `version` — the token to send back in the next `If-Match`, also returned as the `ETag`. `revision_count` is the record's correction count including this one.\n",
        "allOf": [
          {
            "$ref": "#/components/schemas/EmployeeCompensationRecord"
          },
          {
            "type": "object",
            "required": [
              "revision_count"
            ],
            "properties": {
              "closed_previous_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The PREDECESSOR this correction re-closed at `effective_from - 1 day`, when the start date moved. `null` when it did not move, or when there was no predecessor. The field name is `EmployeeCompensationCreated`'s, reused because it answers the same question — which other record did this write close — and a second name for one fact would be worse than the slight asymmetry of one name for two occasions.\n"
              }
            }
          }
        ]
      },
      "Earning": {
        "description": "pay.earnings — one earning line on a payslip; immutable once the parent slip publishes (db 07 §1.2).",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "payslip_id",
              "earning_type",
              "amount"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "payslip_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "component_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "component_code": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "label": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "earning_type": {
                "$ref": "#/components/schemas/EarningType"
              },
              "amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "is_taxable": {
                "type": "boolean"
              },
              "is_prorated": {
                "type": "boolean"
              },
              "arrear_period": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/DateOnlyRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "origin": {
                "$ref": "#/components/schemas/PayrollLineOrigin"
              },
              "run_adjustment_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Set when the line was written by a cohort head adjustment (pay.run_adjustments, #1558); NULL otherwise."
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "PayrollLineOrigin": {
        "type": "string",
        "enum": [
          "GENERATED",
          "MANUAL"
        ],
        "description": "'pay.payroll_line_origin (ADR 0029 §(b), migration 0105).' Who wrote the line. `GENERATED` is `pay.payroll_run.populate`'s own output and is what a re-populate deletes and regenerates; `MANUAL` is an operator line entered through `pay.payroll_run_line.*` and **survives regeneration untouched** — which is what makes delete-and-regenerate safe rather than destructive. Lines created before the engine existed read `MANUAL`, because they were typed, not computed.\n"
      },
      "EarningCreate": {
        "type": "object",
        "required": [
          "employee_id",
          "earning_type",
          "amount"
        ],
        "additionalProperties": false,
        "properties": {
          "employee_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "component_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "earning_type": {
            "$ref": "#/components/schemas/EarningType"
          },
          "amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "arrear_period": {
            "$ref": "#/components/schemas/DateOnlyRef"
          },
          "is_taxable": {
            "type": "boolean",
            "default": true
          },
          "is_prorated": {
            "type": "boolean",
            "default": false
          }
        }
      },
      "EarningUpdate": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "is_taxable": {
            "type": "boolean"
          },
          "is_prorated": {
            "type": "boolean"
          }
        }
      },
      "EarningPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Earning"
                }
              }
            }
          }
        ]
      },
      "Deduction": {
        "description": "pay.deductions — one deduction/contribution line on a payslip; immutable once the parent slip publishes (db 07 §1.2).",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "payslip_id",
              "deduction_type",
              "contribution_side",
              "is_statutory",
              "amount"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "payslip_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "component_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "deduction_type": {
                "$ref": "#/components/schemas/DeductionType"
              },
              "contribution_side": {
                "$ref": "#/components/schemas/ContributionSide"
              },
              "is_statutory": {
                "type": "boolean"
              },
              "amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "rate": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/RateRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "wage_base_amount": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/MoneyRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "source_ref_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Soft polymorphic recovery source, resolved by deduction_type (db 07 §1.2)."
              },
              "origin": {
                "$ref": "#/components/schemas/PayrollLineOrigin"
              },
              "run_adjustment_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Set when the line was written by a cohort head adjustment (pay.run_adjustments, #1558); NULL otherwise."
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "DeductionCreate": {
        "type": "object",
        "required": [
          "employee_id",
          "deduction_type",
          "amount"
        ],
        "additionalProperties": false,
        "properties": {
          "employee_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "component_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "deduction_type": {
            "$ref": "#/components/schemas/DeductionType"
          },
          "amount": {
            "$ref": "#/components/schemas/MoneyRef"
          }
        }
      },
      "RunAdjustmentCohort": {
        "type": "object",
        "additionalProperties": false,
        "description": "A cohort as the operator states it. Every axis is a LIST and the axes are **ANDed** — \"the delivery department, on piece rate\" is one cohort, not two calls. `all` is the explicit whole-run cohort, spelled rather than implied by an empty object, because \"everybody\" and \"the selection I forgot to fill in\" must not be the same request; it cannot be combined with another axis.\n",
        "properties": {
          "all": {
            "type": "boolean"
          },
          "department_ids": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          "org_unit_ids": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          "pay_models": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string",
              "enum": [
                "MONTHLY_SALARY",
                "DAILY_WAGE",
                "PIECE_RATE"
              ]
            }
          },
          "employee_ids": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/UuidRef"
            }
          }
        }
      },
      "RunAdjustmentPercentBasis": {
        "type": "string",
        "enum": [
          "GROSS",
          "NET",
          "BASIC"
        ],
        "description": "'pay.run_adjustment_percent_basis (migration 0219).' The base a percentage is stated against, read from each payslip AS IT STANDS when the adjustment is applied. `BASIC` is the slip's `BASIC` earning line — the base the India pack's statutory formulas are already written against.\n"
      },
      "RunAdjustment": {
        "description": "'pay.run_adjustments — one COHORT HEAD ADJUSTMENT: the operator instruction behind a set of MANUAL payslip lines (db 07 §1.2, ADR 0069 §(c)).' Exactly one of `amount` and `percent` is non-null.\n",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "payroll_run_id",
              "line_kind",
              "component_code",
              "cohort",
              "reason",
              "applied_count"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "payroll_run_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "line_kind": {
                "type": "string",
                "enum": [
                  "EARNING",
                  "DEDUCTION"
                ]
              },
              "component_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "component_code": {
                "type": "string"
              },
              "earning_type": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/EarningType"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "deduction_type": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/DeductionType"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "amount": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/MoneyRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "percent": {
                "type": [
                  "string",
                  "null"
                ],
                "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$",
                "description": "PER CENT, not a fraction: `12.5` is twelve and a half per cent. Decimal string, never a float."
              },
              "percent_of": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/RunAdjustmentPercentBasis"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "is_taxable": {
                "type": "boolean"
              },
              "cohort": {
                "$ref": "#/components/schemas/RunAdjustmentCohort"
              },
              "reason": {
                "type": "string",
                "description": "Mandatory; it is the label the employee reads on the payslip."
              },
              "applied_count": {
                "type": "integer",
                "description": "How many payslip lines the fan-out wrote. A fact about the ACT, not about the lines that survive it."
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "RunAdjustmentCreate": {
        "type": "object",
        "required": [
          "line_kind",
          "component_code",
          "cohort",
          "reason"
        ],
        "additionalProperties": false,
        "description": "State exactly one of `amount` (a flat figure per employee) or `percent` + `percent_of`. `earning_type` is required for an `EARNING` (and may not be `ARREARS`); `deduction_type` is required for a `DEDUCTION` and must be `ADHOC` or `OTHER`. `is_taxable` applies to earnings only.\n",
        "properties": {
          "line_kind": {
            "type": "string",
            "enum": [
              "EARNING",
              "DEDUCTION"
            ]
          },
          "component_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "component_code": {
            "type": "string",
            "pattern": "^[A-Z0-9_]{1,64}$"
          },
          "earning_type": {
            "type": "string",
            "enum": [
              "FIXED",
              "VARIABLE",
              "BONUS",
              "INCENTIVE",
              "REIMBURSEMENT",
              "OVERTIME",
              "LEAVE_ENCASHMENT",
              "ADHOC"
            ]
          },
          "deduction_type": {
            "type": "string",
            "enum": [
              "ADHOC",
              "OTHER"
            ]
          },
          "amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "percent": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]{1,6})?$"
          },
          "percent_of": {
            "$ref": "#/components/schemas/RunAdjustmentPercentBasis"
          },
          "is_taxable": {
            "type": "boolean",
            "default": true
          },
          "cohort": {
            "$ref": "#/components/schemas/RunAdjustmentCohort"
          },
          "reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          }
        }
      },
      "RunAdjustmentSkip": {
        "type": "object",
        "required": [
          "employee_id",
          "reason"
        ],
        "properties": {
          "employee_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "reason": {
            "type": "string",
            "enum": [
              "NO_PAYSLIP",
              "PAYSLIP_CANCELLED",
              "PERCENT_BASE_NOT_POSITIVE",
              "PERCENT_ROUNDS_TO_ZERO"
            ],
            "description": "Why this employee received no line. `NO_PAYSLIP` — named explicitly but this run does not pay them. `PAYSLIP_CANCELLED` — held out of the run (`VOID`). `PERCENT_BASE_NOT_POSITIVE` — the slip's gross/net/BASIC base is zero or negative, so no honest percentage exists. `PERCENT_ROUNDS_TO_ZERO` — the exact figure rounds to `0.00`, and a zero line is noise.\n"
          }
        }
      },
      "RunAdjustmentApplied": {
        "type": "object",
        "required": [
          "adjustment",
          "applied_count",
          "skipped"
        ],
        "properties": {
          "adjustment": {
            "$ref": "#/components/schemas/RunAdjustment"
          },
          "applied_count": {
            "type": "integer"
          },
          "skipped": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunAdjustmentSkip"
            }
          },
          "payroll_run_version": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The run's version after its totals were recomputed — the same value as the ETag."
          }
        }
      },
      "RunAdjustmentRemoved": {
        "type": "object",
        "required": [
          "id",
          "removed_line_count"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "removed_line_count": {
            "type": "integer"
          },
          "payroll_run_version": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "RunAdjustmentList": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunAdjustment"
            }
          }
        }
      },
      "Payslip": {
        "description": "pay.payslips — the per-employee pay record for one run; immutable + config-version-stamped once published (db 07 §1.2).",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "payslip_no",
              "payroll_run_id",
              "employee_id",
              "fiscal_year",
              "pay_period_start",
              "pay_period_end",
              "status"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "payslip_no": {
                "$ref": "#/components/schemas/BusinessNoRef"
              },
              "payroll_run_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "fiscal_year": {
                "type": "integer"
              },
              "pay_period_start": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "pay_period_end": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "paid_days": {
                "$ref": "#/components/schemas/DecimalHoursRef"
              },
              "lop_days": {
                "$ref": "#/components/schemas/DecimalHoursRef"
              },
              "gross_earnings_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "total_deductions_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "employer_contrib_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "net_pay_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "ytd_gross_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "ytd_deductions_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "ytd_net_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "ytd_tax_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "status": {
                "$ref": "#/components/schemas/PayslipStatus"
              },
              "pay_structure_version": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "compliance_pack_version": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "component_snapshot": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/ConfigVersionStamp"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Frozen resolved component data plus the canonical v1 config envelope."
              },
              "published_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "disbursement": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/PayslipPaymentSummary"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "**Additive, nullable** (2026-09-02, `PAY-F12`, #1556 — mobile-contract notice in [`api-docs/07` §2](../../07-surface-product-app-api.md)). Payment state read from `pay.payslip_disbursements`, the obligation ledger. Nothing existing on `Payslip` is re-shaped, re-typed or removed, so a client that predates this field keeps today's contract exactly. `null` means **not known** — an older run, or a slip whose ledger row is unreadable to the caller — and a client renders NOTHING rather than inferring \"unpaid\" from an absence.\n"
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "PayslipPaymentStatus": {
        "type": "string",
        "enum": [
          "UNPAID",
          "PARTLY_PAID",
          "PAID",
          "PAID_OUTSIDE_PAYROLL",
          "VOIDED"
        ],
        "description": "What the employee is told about their money (ADR 0069 §(c), backend-spec §10). **Derived on every read, never stored**, from `pay.payslip_disbursements.state` and `released_amount`: `VOID` → `VOIDED`; `OUTSIDE_PAYROLL` → `PAID_OUTSIDE_PAYROLL`; `RELEASED` → `PAID`; anything with money already released → `PARTLY_PAID`; otherwise `UNPAID`.\n\n**`HELD` reads `UNPAID`, deliberately.** A hold is an internal instruction with an internal reason; an employee surface shows the fact (the money has not arrived) and never the reason (fsd 06 §M1 `PAY-S02`). `disbursement.state` still carries the raw ledger value for the admin surfaces entitled to it.\n\n**`PUBLISHED` is not `PAID`.** `pay.payslips.status` says the slip exists; this says whether money moved.\n\nThe list is **append-only**: a client that has not shipped a new member must treat an unrecognised value as `UNPAID` — never as paid.\n"
      },
      "PayslipPaymentSummary": {
        "type": "object",
        "readOnly": true,
        "description": "`pay.payslip_disbursements` — the obligation behind one payslip (db 07 §1.10, migration 0217), projected onto the **payslip** reads. Distinct from `PayslipDisbursement`, which is the Release-stage row of `GET /payroll-runs/{id}/disbursements` (an operator view keyed by employee, carrying bank readiness and the action verb); this one is what an employee — and the register beside them — is told about their own slip. Payment could never have been a payslip column: `pay.protect_published_payroll_evidence` (migration 0033) refuses every UPDATE to a published slip, and `payslips_net_balance` pins `net = gross − deductions`, so a prior balance may never touch `net_pay_amount` either.\n",
        "required": [
          "state",
          "payment_status",
          "due_amount",
          "released_amount",
          "remaining_amount"
        ],
        "properties": {
          "state": {
            "$ref": "#/components/schemas/DisbursementState"
          },
          "payment_status": {
            "$ref": "#/components/schemas/PayslipPaymentStatus"
          },
          "due_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Owed THROUGH PAYROLL for this cycle — the slip net, or 0 for OUTSIDE_PAYROLL/VOID."
          },
          "released_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Sum of settlements against this obligation, by ANY run's batch."
          },
          "remaining_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Generated `due − released`; what is still owed."
          },
          "paid_on": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "The last release date as a CALENDAR DATE in the **pay group's** timezone (`org.pay_groups.timezone`), not the caller's and not the server's. `null` while nothing has been released.\n"
          },
          "settled_in_period_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Set only when a **later** cycle's batch closed this obligation — \"paid with the 2026-08 payroll\". `null` when this slip's own cycle paid it, and `null` while it is unpaid.\n"
          }
        }
      },
      "PayslipPaymentDetail": {
        "description": "`PayslipDetail`'s flavour of the same object: everything on `PayslipPaymentSummary` plus the two blocks that only make sense on one slip at a time.\n",
        "allOf": [
          {
            "$ref": "#/components/schemas/PayslipPaymentSummary"
          },
          {
            "type": "object",
            "properties": {
              "settlements": {
                "type": "array",
                "description": "Every settlement that has moved money against THIS slip, oldest first. `period_code` is the period of the run whose batch **paid** — the obligation's own period is already known (it is this slip), whereas which cycle's money closed it is the fact worth carrying.\n",
                "items": {
                  "type": "object",
                  "required": [
                    "release_batch_id",
                    "payroll_run_id",
                    "period_code",
                    "amount",
                    "released_at"
                  ],
                  "properties": {
                    "release_batch_id": {
                      "$ref": "#/components/schemas/UuidRef"
                    },
                    "payroll_run_id": {
                      "$ref": "#/components/schemas/UuidRef"
                    },
                    "period_code": {
                      "type": "string"
                    },
                    "amount": {
                      "$ref": "#/components/schemas/MoneyRef"
                    },
                    "released_at": {
                      "$ref": "#/components/schemas/TimestampRef"
                    }
                  }
                }
              },
              "prior_balance": {
                "type": "object",
                "description": "**Balance due, read live from the ledger** (ADR 0069 §(g)) — nothing is carried, projected or duplicated. `open_items` are the employee's own earlier slips whose obligation was never closed, oldest period first; `HELD` items ARE included (the money is owed whether or not somebody paused it) and carry their own `state`, but never the hold's reason. Shown **informationally**: a prior balance is a disbursement, never gross, and is never re-taxed.\n",
                "required": [
                  "open_amount",
                  "open_items",
                  "paid_against_by_this_cycle"
                ],
                "properties": {
                  "open_amount": {
                    "$ref": "#/components/schemas/MoneyRef"
                  },
                  "open_items": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "payslip_id",
                        "payslip_no",
                        "period_code",
                        "remaining_amount",
                        "state"
                      ],
                      "properties": {
                        "payslip_id": {
                          "$ref": "#/components/schemas/UuidRef"
                        },
                        "payslip_no": {
                          "$ref": "#/components/schemas/BusinessNoRef"
                        },
                        "period_code": {
                          "type": "string"
                        },
                        "remaining_amount": {
                          "$ref": "#/components/schemas/MoneyRef"
                        },
                        "state": {
                          "$ref": "#/components/schemas/DisbursementState"
                        }
                      }
                    }
                  },
                  "paid_against_by_this_cycle": {
                    "type": "array",
                    "description": "What THIS cycle's release batches have already paid against those earlier obligations.",
                    "items": {
                      "type": "object",
                      "required": [
                        "obligation_payslip_no",
                        "period_code",
                        "amount",
                        "released_at"
                      ],
                      "properties": {
                        "obligation_payslip_no": {
                          "$ref": "#/components/schemas/BusinessNoRef"
                        },
                        "period_code": {
                          "type": "string"
                        },
                        "amount": {
                          "$ref": "#/components/schemas/MoneyRef"
                        },
                        "released_at": {
                          "$ref": "#/components/schemas/TimestampRef"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "PayslipHeaderProjection": {
        "type": "object",
        "readOnly": true,
        "description": "Employer + employee header, resolved by projection (never a join) from org.legal_entities / people.employees / org.designations — not pay columns (fsd 06 §1.6b, PAY-S02).\n",
        "properties": {
          "employer_name": {
            "type": "string"
          },
          "employee_no": {
            "$ref": "#/components/schemas/BusinessNoRef"
          },
          "employee_full_name": {
            "type": "string"
          },
          "designation_label": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "PayslipDetail": {
        "description": "PAY-S02 full detail — the payslip plus embedded earnings/deductions lines and header projections (db 07 §1.2).",
        "allOf": [
          {
            "$ref": "#/components/schemas/Payslip"
          },
          {
            "type": "object",
            "properties": {
              "header": {
                "$ref": "#/components/schemas/PayslipHeaderProjection"
              },
              "earnings": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Earning"
                }
              },
              "deductions": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Deduction"
                }
              },
              "disbursement": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/PayslipPaymentDetail"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "**Additive, nullable** (`PAY-F12`, #1556) — `Payslip.disbursement` plus `settlements[]` and `prior_balance`. Null carries the same meaning here as on the list: payment state is not known, so no block is rendered and none is inferred.\n"
              }
            }
          }
        ]
      },
      "PayslipPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Payslip"
                }
              }
            }
          }
        ]
      },
      "PayslipExportRequest": {
        "type": "object",
        "required": [
          "format"
        ],
        "additionalProperties": false,
        "properties": {
          "payroll_run_id": {
            "$ref": "#/components/schemas/UuidRef",
            "description": "Required for REGISTER, COST_CENTRE and GL_ACCOUNT; optional for PAY-S20 groupings. Mutually exclusive with fiscal_year and the period range."
          },
          "employee_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "status": {
            "$ref": "#/components/schemas/PayslipStatus"
          },
          "fiscal_year": {
            "type": "integer",
            "description": "PAY-S20 fiscal-year selection; mutually exclusive with the period range."
          },
          "period_start": {
            "$ref": "#/components/schemas/DateOnlyRef",
            "description": "PAY-S20 explicit range start; supplied with period_end."
          },
          "period_end": {
            "$ref": "#/components/schemas/DateOnlyRef",
            "description": "PAY-S20 explicit range end; supplied with period_start."
          },
          "legal_entity_id": {
            "$ref": "#/components/schemas/UuidRef",
            "description": "Optional PAY-S20 filter only; it does not alter the TENANT authorization scope."
          },
          "format": {
            "type": "string",
            "enum": [
              "CSV",
              "PDF"
            ],
            "description": "Both formats are supported; CSV cells are formula-neutralized."
          },
          "grouping": {
            "type": "string",
            "enum": [
              "REGISTER",
              "COST_CENTRE",
              "GL_ACCOUNT",
              "ORG_UNIT",
              "LEGAL_ENTITY",
              "DEPARTMENT"
            ],
            "description": "The \"one grouper, not two\" switch (`design-finance/04` §5): `pay.payslip.export` reads through the SAME server-side projection its two preview reads use, so the exported file can never drift from the grid a Finance user just looked at. `REGISTER` (the default) is the pre-existing flat payroll register (PAY-S11) — **omitting this field is fully backward compatible** and every caller that has never heard of it keeps getting exactly that. `COST_CENTRE` produces the cost-centre grid `pay.payslip.cost_centre_summary` previews (PAY-S17); `GL_ACCOUNT` produces the GL-account grid `pay.payslip.gl_summary` previews (PAY-S18); `ORG_UNIT` / `LEGAL_ENTITY` / `DEPARTMENT` produce PAY-S20's exact filtered grid. `format: PDF` is only valid with `REGISTER` — every grouped export with `PDF` is rejected (422).\n"
          }
        }
      },
      "BankAdviceGenerateRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "release_batch_id"
        ],
        "properties": {
          "release_batch_id": {
            "$ref": "#/components/schemas/UuidRef",
            "description": "*(rev. 2026-09-02, #1555 — REQUIRED)* The release batch whose file to re-issue. Omitting it is the deprecated run-wide mode and is refused with a `422` naming `pay.payroll_release_batch.create`: once a cycle can be released in parts there is no such thing as \"the run's payment file\", and inventing a population would misstate what was paid.\n"
          },
          "layout_version": {
            "type": "string",
            "maxLength": 64,
            "description": "The versioned advice layout to cut (config, never code — ADR 0005). Omitted → the neutral v1 CSV layout. One artifact exists per BATCH per layout; a repeat generate returns it.\n"
          }
        }
      },
      "BankAdviceFile": {
        "description": "One generated bank-advice artifact — the append-only `pay.bank_advice_files` evidence row plus a presigned download handle. `content_hash` is the sha256 of the exact uploaded bytes; the generator is deterministic, so for one run and one layout the hash is reproducible.\n",
        "type": "object",
        "required": [
          "id",
          "payroll_run_id",
          "layout_version",
          "currency_code",
          "employee_count",
          "total_amount",
          "content_hash",
          "file_name",
          "mime_type",
          "generated_at",
          "url",
          "expires_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "payroll_run_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "release_batch_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "*(rev. 2026-09-02, #1555)* The batch this file pays. `null` only on the pre-2026-09 rows generated per run; every new file is cut per batch, inside the batch's own transaction."
          },
          "batch_no": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 1
              },
              {
                "type": "null"
              }
            ],
            "description": "The owning batch's 1-based number — *\"batch 3 of the August cycle\"*. `null` on the legacy run-wide rows."
          },
          "layout_version": {
            "type": "string"
          },
          "currency_code": {
            "type": "string",
            "minLength": 3,
            "maxLength": 3
          },
          "employee_count": {
            "type": "integer",
            "minimum": 0
          },
          "total_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "content_hash": {
            "type": "string",
            "description": "sha256 hex of the exact uploaded bytes (tamper evidence)."
          },
          "size_bytes": {
            "type": "integer",
            "minimum": 0
          },
          "file_name": {
            "type": "string"
          },
          "mime_type": {
            "type": "string"
          },
          "generated_by": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "url": {
            "type": "string",
            "description": "Time-limited presigned download URL — never persisted client-side."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "idempotency_replayed": {
            "type": "boolean",
            "description": "Present true when this response was replayed from the idempotency store."
          }
        }
      },
      "BankAdviceFileSummary": {
        "description": "The list projection of an advice artifact — deliberately WITHOUT `url`/`expires_at`: a presigned handle is minted only by `pay.bank_advice.download`, so every handout of the full-account-number file is individually logged.\n",
        "type": "object",
        "required": [
          "id",
          "payroll_run_id",
          "layout_version",
          "currency_code",
          "employee_count",
          "total_amount",
          "content_hash",
          "file_name",
          "mime_type",
          "generated_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "payroll_run_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "release_batch_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "*(rev. 2026-09-02, #1555)* The batch this file pays. `null` only on the pre-2026-09 rows generated per run; every new file is cut per batch, inside the batch's own transaction."
          },
          "batch_no": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 1
              },
              {
                "type": "null"
              }
            ],
            "description": "The owning batch's 1-based number — *\"batch 3 of the August cycle\"*. `null` on the legacy run-wide rows."
          },
          "layout_version": {
            "type": "string"
          },
          "currency_code": {
            "type": "string",
            "minLength": 3,
            "maxLength": 3
          },
          "employee_count": {
            "type": "integer",
            "minimum": 0
          },
          "total_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "content_hash": {
            "type": "string"
          },
          "size_bytes": {
            "type": "integer",
            "minimum": 0
          },
          "file_name": {
            "type": "string"
          },
          "mime_type": {
            "type": "string"
          },
          "generated_by": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BankAdviceFileList": {
        "type": "object",
        "required": [
          "payroll_run_id",
          "data"
        ],
        "properties": {
          "payroll_run_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "data": {
            "type": "array",
            "description": "Newest first.",
            "items": {
              "$ref": "#/components/schemas/BankAdviceFileSummary"
            }
          }
        }
      },
      "CostCentreAllocationLine": {
        "description": "One cost centre's aggregated actual payroll cost for a period — a read-model projection over pay.payslips grouped by org.departments.cost_center (no cross-schema join). No budget/target figure — org.departments has no paired budget entity (design-docs/04 G-14④). Carries three explicitly-named money figures rather than one ambiguous \"employer cost\": gross_cost_amount (gross pay only), employer_contrib_amount (employer contributions only) and total_employer_cost_amount (their sum, the full cost-to-employer) — added because fsd-docs 06 PAY-S16 and design-finance/06 §6 had described a contributions-only sum as \"the\" employer-cost figure while the shipped projection always meant the gross+contributions total, so a reader must never again have to guess which figure a screen means by \"employer cost\".\n",
        "type": "object",
        "required": [
          "cost_center",
          "employee_count",
          "gross_cost_amount",
          "employer_contrib_amount",
          "total_employer_cost_amount",
          "employer_cost_amount",
          "percent_of_total"
        ],
        "properties": {
          "cost_center": {
            "type": [
              "string",
              "null"
            ],
            "description": "org.departments.cost_center; null groups under \"Unassigned\"."
          },
          "department_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "department_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "org.departments.name (locale-keyed, projected to the request locale)."
          },
          "employee_count": {
            "type": "integer",
            "minimum": 0
          },
          "gross_cost_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "employer_contrib_amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/MoneyRef"
              }
            ],
            "description": "Employer contributions only (sum(pay.payslips.employer_contrib_amount)) — excludes gross pay."
          },
          "total_employer_cost_amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/MoneyRef"
              }
            ],
            "description": "The full cost to the employer: gross_cost_amount + employer_contrib_amount. This is the figure percent_of_total is a share of.\n"
          },
          "employer_cost_amount": {
            "deprecated": true,
            "description": "Deprecated alias of total_employer_cost_amount, retained for backward compatibility — it is a published contract field and this value has not changed. New consumers should read total_employer_cost_amount instead.\n",
            "allOf": [
              {
                "$ref": "#/components/schemas/MoneyRef"
              }
            ]
          },
          "percent_of_total": {
            "type": "number",
            "description": "total_employer_cost_amount ÷ Σ(all cost centres' total_employer_cost_amount) for the scoped run/period."
          }
        }
      },
      "CostCentreAllocationResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "payroll_run_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CostCentreAllocationLine"
            }
          }
        }
      },
      "WorkforceCostGroupBy": {
        "type": "string",
        "description": "The grouping axis of pay.payslip.cost_summary. The cost-centre axis stays on pay.payslip.cost_centre_summary.",
        "enum": [
          "org_unit",
          "legal_entity",
          "department"
        ]
      },
      "WorkforceCostLine": {
        "description": "One group's aggregated workforce cost for the selection — a read-model projection over pay.payslips regrouped on the requested axis. Current-assignment org/people labels resolve in the same tenant transaction; this is live reference resolution, not an eventually-consistent projection.\n",
        "type": "object",
        "required": [
          "group_label",
          "employee_count",
          "gross_cost_amount",
          "employer_cost_amount",
          "percent_of_total"
        ],
        "properties": {
          "group_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "The org.org_units / org.legal_entities / org.departments id for the group; null on the \"Unassigned\" row."
          },
          "group_key": {
            "type": [
              "string",
              "null"
            ],
            "description": "Stable code for the group (unit_code / entity_code / department code); null on \"Unassigned\"."
          },
          "group_label": {
            "$ref": "#/components/schemas/LocalizedText",
            "description": "Locale-keyed group name; the literal \"Unassigned\" bucket when the employee has no value on the chosen axis."
          },
          "currency_code": {
            "$ref": "#/components/schemas/CurrencyCodeRef",
            "description": "The group's currency, from its legal entity. Lines in different currencies are never summed together."
          },
          "employee_count": {
            "type": "integer",
            "minimum": 0,
            "description": "COUNT(DISTINCT pay.payslips.employee_id) in the group — payslips in the period, so a mid-period joiner counts once."
          },
          "gross_cost_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "SUM(pay.payslips.gross_earnings_amount) for the group."
          },
          "employer_cost_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "SUM(pay.payslips.employer_contrib_amount) — the cost-of-workforce figure, not net pay."
          },
          "percent_of_total": {
            "type": "number",
            "description": "employer cost ÷ Σ(all groups in the SELECTION, within this currency) — not of the tenant."
          }
        }
      },
      "WorkforceCostCurrencyTotal": {
        "type": "object",
        "description": "One currency's subtotal for the selection. Returned per currency with **no grand total** — a multi-entity selection spanning INR and SAR has no meaningful sum (fsd 06 PAY-S20).\n",
        "required": [
          "currency_code",
          "employee_count",
          "gross_cost_amount",
          "employer_cost_amount"
        ],
        "properties": {
          "currency_code": {
            "$ref": "#/components/schemas/CurrencyCodeRef"
          },
          "employee_count": {
            "type": "integer",
            "minimum": 0
          },
          "gross_cost_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "employer_cost_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          }
        }
      },
      "WorkforceCostSummaryResponse": {
        "type": "object",
        "required": [
          "group_by",
          "data",
          "totals"
        ],
        "properties": {
          "group_by": {
            "$ref": "#/components/schemas/WorkforceCostGroupBy"
          },
          "payroll_run_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "period_start": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "period_end": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "run_statuses_included": {
            "type": "array",
            "description": "Always EXECUTED/PUBLISHED — echoed so a consumer never has to assume which runs a total covers.",
            "items": {
              "type": "string",
              "enum": [
                "EXECUTED",
                "PUBLISHED"
              ]
            }
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkforceCostLine"
            }
          },
          "totals": {
            "type": "array",
            "description": "Per-currency subtotals for the selection. No grand total, by design.",
            "items": {
              "$ref": "#/components/schemas/WorkforceCostCurrencyTotal"
            }
          }
        }
      },
      "RunCostGroupBy": {
        "type": "string",
        "description": "The grouping axis of pay.payroll_run.cost_summary. Two more than pay.payslip.cost_summary offers: `cost_centre` (org.departments.cost_center) and `pay_model` (the employee's pay.employee_compensation.pay_model effective on the run's pay_period_end).\n",
        "enum": [
          "department",
          "cost_centre",
          "pay_model",
          "legal_entity",
          "org_unit"
        ]
      },
      "RunCostDisbursement": {
        "type": "object",
        "description": "The group's payment picture, from pay.payslip_disbursements (db-docs/07 §1.10). A slip with no ledger row counts as PENDING at zero — a run populated before migration 0217 still costs money.\n",
        "required": [
          "due_amount",
          "released_amount",
          "remaining_amount",
          "held_amount",
          "outside_payroll_amount",
          "released_count",
          "pending_count",
          "held_count"
        ],
        "properties": {
          "due_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Σ due_amount — what payroll owes THROUGH payroll for this cycle."
          },
          "released_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Σ released_amount — settled by any run's release batch."
          },
          "remaining_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Σ remaining_amount (generated as due − released)."
          },
          "held_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Σ remaining_amount of rows in state HELD — money an operator has deliberately stopped."
          },
          "outside_payroll_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Σ of the SLIP''s net for rows in state OUTSIDE_PAYROLL. Deliberately not `due_amount`: an OUTSIDE_PAYROLL row has due = 0 by construction (payroll owes nothing because the money went another way), so summing due there would report zero and hide the cost.\n"
          },
          "released_count": {
            "type": "integer",
            "minimum": 0
          },
          "pending_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Rows in PENDING or PARTIAL — still owed through payroll."
          },
          "held_count": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "RunCostLine": {
        "description": "One group's cost for the run — an aggregate over pay.payslips (status <> CANCELLED, the same predicate the run's own rollup uses) regrouped on the requested axis, left-joined to the disbursement ledger. Money is summed in minor units as decimal strings; no float ever touches it.\n",
        "type": "object",
        "required": [
          "key",
          "id",
          "label",
          "currency_code",
          "employee_count",
          "gross_amount",
          "employer_contrib_amount",
          "total_employer_cost_amount",
          "net_pay_amount",
          "disbursement",
          "prior_open_balance_amount",
          "prior_open_balance_count",
          "percent_of_total"
        ],
        "properties": {
          "key": {
            "type": [
              "string",
              "null"
            ],
            "description": "Stable code for the group (dept_code / cost centre / pay model / entity_code / unit_code); null on the \"Unassigned\" row."
          },
          "id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "The org.departments / org.legal_entities / org.org_units id. ALWAYS null for `cost_centre` and `pay_model`: a cost centre is a text attribute of a department (two departments may share one) and a pay model is an enum member — neither is a row with an identity to fetch.\n"
          },
          "label": {
            "$ref": "#/components/schemas/LocalizedText",
            "description": "Locale-keyed group name; `{\"en\": <key>}` for the two code-valued axes, and the literal \"Unassigned\" bucket when the employee has no value on the chosen axis."
          },
          "currency_code": {
            "$ref": "#/components/schemas/CurrencyCodeRef",
            "description": "The group's currency, from its payslips. A department staffed from two legal entities comes back as two lines; currencies are never summed."
          },
          "employee_count": {
            "type": "integer",
            "minimum": 0,
            "description": "COUNT(DISTINCT pay.payslips.employee_id) in the group."
          },
          "gross_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Σ gross_earnings_amount."
          },
          "employer_contrib_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Σ employer_contrib_amount — employer contributions only."
          },
          "total_employer_cost_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Σ (gross_earnings_amount + employer_contrib_amount) — the full cost to employer, and the base percent_of_total is taken against."
          },
          "net_pay_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Σ net_pay_amount — the cycle's net liability for the group, never what a bank file moved."
          },
          "disbursement": {
            "$ref": "#/components/schemas/RunCostDisbursement"
          },
          "prior_open_balance_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Balance due from EARLIER cycles for this group''s employees — Σ remaining_amount of their still-open obligations on other PUBLISHED runs of the same pay group (PENDING/HELD/PARTIAL), read live from the same ledger the release table reads. Never part of any slip''s net, so a prior balance is never re-taxed.\n"
          },
          "prior_open_balance_count": {
            "type": "integer",
            "minimum": 0,
            "description": "How many such obligations are open."
          },
          "percent_of_total": {
            "type": "number",
            "description": "total_employer_cost_amount ÷ Σ(all groups of the run, WITHIN this currency) × 100."
          }
        }
      },
      "RunCostCurrencyTotal": {
        "type": "object",
        "description": "One currency's total for the run. Per currency with no grand total, by design.",
        "required": [
          "currency_code",
          "employee_count",
          "gross_amount",
          "employer_contrib_amount",
          "total_employer_cost_amount",
          "net_pay_amount",
          "disbursement",
          "prior_open_balance_amount",
          "prior_open_balance_count"
        ],
        "properties": {
          "currency_code": {
            "$ref": "#/components/schemas/CurrencyCodeRef"
          },
          "employee_count": {
            "type": "integer",
            "minimum": 0
          },
          "gross_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "employer_contrib_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "total_employer_cost_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "net_pay_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "disbursement": {
            "$ref": "#/components/schemas/RunCostDisbursement"
          },
          "prior_open_balance_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "prior_open_balance_count": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "RunCostSummaryResponse": {
        "type": "object",
        "required": [
          "payroll_run_id",
          "group_by",
          "run_status",
          "is_provisional",
          "basis",
          "excluded",
          "data",
          "totals"
        ],
        "properties": {
          "payroll_run_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "group_by": {
            "$ref": "#/components/schemas/RunCostGroupBy"
          },
          "run_status": {
            "$ref": "#/components/schemas/PayrollRunStatus",
            "description": "Echoed so a consumer never has to assume how committed these numbers are."
          },
          "is_provisional": {
            "type": "boolean",
            "description": "True while the run''s inputs can still change underneath the reader — DERIVED from the pay period''s status (anything before INPUTS_LOCKED / RUN_LINKED / CLOSED), never stored. A period-less run (SUPPLEMENTARY / ARREARS / OFF_CYCLE / FNF) is never provisional: it has no calendar to be ahead of.\n"
          },
          "basis": {
            "type": "string",
            "enum": [
              "CURRENT_EMPLOYEE_ASSIGNMENT"
            ],
            "description": "The axis is resolved from the employee's assignment NOW, not as at the pay period (#1132)."
          },
          "excluded": {
            "type": "object",
            "required": [
              "cancelled_slips",
              "employees_without_slip"
            ],
            "description": "What the figures leave out, counted rather than implied.",
            "properties": {
              "cancelled_slips": {
                "type": "integer",
                "minimum": 0,
                "description": "Slips on the run in status CANCELLED — what VOID/HOLD took off it."
              },
              "employees_without_slip": {
                "type": "integer",
                "minimum": 0,
                "description": "Members of the run''s pay group over its period (the predicate populate rosters from) with no live, non-cancelled slip. On a never-populated draft this is the whole group — the honest answer to \"why is my estimate zero\". Always 0 for a run with no pay group.\n"
              }
            }
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunCostLine"
            }
          },
          "totals": {
            "type": "array",
            "description": "Per-currency totals for the run. No grand total, by design.",
            "items": {
              "$ref": "#/components/schemas/RunCostCurrencyTotal"
            }
          }
        }
      },
      "GlAccountLine": {
        "description": "One GL-account bucket's aggregated amount for a run — pay.earnings/pay.deductions grouped by org.pay_components.gl_account_code (soft ref via component_id).\n",
        "type": "object",
        "required": [
          "component_code",
          "line_type",
          "amount"
        ],
        "properties": {
          "gl_account_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "org.pay_components.gl_account_code; null groups under \"Unmapped\"."
          },
          "component_code": {
            "type": "string"
          },
          "line_type": {
            "type": "string",
            "enum": [
              "EARNING",
              "DEDUCTION"
            ]
          },
          "amount": {
            "$ref": "#/components/schemas/MoneyRef"
          }
        }
      },
      "GlExportSummaryResponse": {
        "type": "object",
        "required": [
          "payroll_run_id",
          "data"
        ],
        "properties": {
          "payroll_run_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GlAccountLine"
            }
          }
        }
      },
      "EsopValuationStatus": {
        "type": "string",
        "description": "MC-1 dual control (migration 0235, #1247). `PENDING_REVIEW` is a maker submission and prices nothing — the FMV lookup in `pay.esop_exercise.create` selects `EFFECTIVE` rows only, so a pending valuation leaves an exercise fail-closed. `EFFECTIVE` is reached only through `pay.esop_valuation.complete`, called by a different Finance user. `REJECTED` is that same reviewer's refusal, and it also FREES the plan's effective date: the unique index is partial on `status <> 'REJECTED'`, so the corrected valuation can be recorded for the same day.\n",
        "enum": [
          "PENDING_REVIEW",
          "EFFECTIVE",
          "REJECTED"
        ]
      },
      "EsopValuation": {
        "description": "pay.esop_valuations — an effective-dated, Finance-recorded FMV source for ESOP exercise.",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "legal_entity_id",
              "plan_name",
              "effective_on",
              "fmv_amount",
              "currency_code",
              "status",
              "submitted_by"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "legal_entity_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "plan_name": {
                "type": "string"
              },
              "effective_on": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "fmv_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "currency_code": {
                "type": "string",
                "pattern": "^[A-Z]{3}$"
              },
              "source_reference": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "status": {
                "$ref": "#/components/schemas/EsopValuationStatus"
              },
              "submitted_by": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "approved_by": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "approved_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date-time"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "rejected_by": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "rejected_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "format": "date-time"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "rejection_reason": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Required and non-empty on a `REJECTED` row (DB CHECK); null otherwise."
              },
              "grandfathered_single_control": {
                "type": "boolean",
                "description": "True on exactly the rows that existed before migration 0235. They took effect under single control and had already priced exercises, so they are grandfathered `EFFECTIVE` rather than re-priced; the flag keeps that from reading as a two-person signature.\n"
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "EsopValuationCreate": {
        "type": "object",
        "required": [
          "legal_entity_id",
          "plan_name",
          "effective_on",
          "fmv_amount",
          "currency_code"
        ],
        "additionalProperties": false,
        "properties": {
          "legal_entity_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "plan_name": {
            "type": "string"
          },
          "effective_on": {
            "$ref": "#/components/schemas/DateOnlyRef"
          },
          "fmv_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "currency_code": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "source_reference": {
            "type": "string",
            "maxLength": 500
          }
        }
      },
      "EsopValuationReject": {
        "type": "object",
        "required": [
          "reason"
        ],
        "additionalProperties": false,
        "properties": {
          "reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1000,
            "description": "Why the FMV is refused. Required — the maker has to be able to read what to correct, and an auditor asking why a date carries no valuation needs the same sentence. Travels in the idempotency request body, so a retry that changes it is `IDEMPOTENCY_KEY_REUSE`.\n"
          }
        }
      },
      "EsopValuationPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/EsopValuation"
                }
              }
            }
          }
        ]
      },
      "EsopGrant": {
        "description": "pay.esop_grants — an equity grant with running vested/exercised/forfeited balances (db 07 §1.3).",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "grant_no",
              "employee_id",
              "plan_name",
              "grant_date",
              "granted_units",
              "exercise_price_amount",
              "vesting_start_date",
              "total_vesting_months",
              "status"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "grant_no": {
                "$ref": "#/components/schemas/BusinessNoRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "plan_name": {
                "type": "string"
              },
              "grant_date": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "granted_units": {
                "type": "integer",
                "minimum": 1
              },
              "exercise_price_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "grant_value_amount": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/MoneyRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "vesting_start_date": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "cliff_months": {
                "type": "integer",
                "minimum": 0
              },
              "total_vesting_months": {
                "type": "integer"
              },
              "vested_units": {
                "type": "integer",
                "minimum": 0
              },
              "exercised_units": {
                "type": "integer",
                "minimum": 0
              },
              "forfeited_units": {
                "type": "integer",
                "minimum": 0
              },
              "status": {
                "$ref": "#/components/schemas/EsopGrantStatus"
              },
              "grant_document": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/FileDownloadRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "VestingTranche": {
        "description": "pay.vesting_schedules — one scheduled vest event within a grant (db 07 §1.3).",
        "type": "object",
        "required": [
          "id",
          "tranche_no",
          "vest_date",
          "vest_units",
          "is_cliff",
          "status"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "tranche_no": {
            "type": "integer",
            "minimum": 1
          },
          "vest_date": {
            "$ref": "#/components/schemas/DateOnlyRef"
          },
          "vest_units": {
            "type": "integer",
            "minimum": 1
          },
          "vest_pct": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/RateRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "is_cliff": {
            "type": "boolean"
          },
          "status": {
            "$ref": "#/components/schemas/VestingStatus"
          },
          "vested_at": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TimestampRef"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "EsopGrantDetail": {
        "description": "PAY-S04/PAY-S13 grant detail — the grant plus its embedded vesting tranches (db 07 §1.3).",
        "allOf": [
          {
            "$ref": "#/components/schemas/EsopGrant"
          },
          {
            "type": "object",
            "properties": {
              "vesting_schedules": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/VestingTranche"
                }
              }
            }
          }
        ]
      },
      "EsopGrantCreate": {
        "type": "object",
        "required": [
          "employee_id",
          "plan_name",
          "grant_date",
          "granted_units",
          "exercise_price_amount",
          "vesting_start_date",
          "total_vesting_months",
          "vesting_schedules"
        ],
        "additionalProperties": false,
        "properties": {
          "employee_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "plan_name": {
            "type": "string"
          },
          "grant_date": {
            "$ref": "#/components/schemas/DateOnlyRef"
          },
          "granted_units": {
            "type": "integer",
            "minimum": 1
          },
          "exercise_price_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "grant_value_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "vesting_start_date": {
            "$ref": "#/components/schemas/DateOnlyRef"
          },
          "cliff_months": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          },
          "total_vesting_months": {
            "type": "integer"
          },
          "vesting_schedules": {
            "type": "array",
            "minItems": 1,
            "description": "The tranche plan to generate; sum of vest_pct across tranches must equal 1.",
            "items": {
              "type": "object",
              "required": [
                "tranche_no",
                "vest_date",
                "vest_units"
              ],
              "additionalProperties": false,
              "properties": {
                "tranche_no": {
                  "type": "integer",
                  "minimum": 1
                },
                "vest_date": {
                  "$ref": "#/components/schemas/DateOnlyRef"
                },
                "vest_units": {
                  "type": "integer",
                  "minimum": 1
                },
                "vest_pct": {
                  "$ref": "#/components/schemas/RateRef"
                },
                "is_cliff": {
                  "type": "boolean",
                  "default": false
                }
              }
            }
          }
        }
      },
      "EsopGrantPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/EsopGrant"
                }
              }
            }
          }
        ]
      },
      "EsopExercise": {
        "description": "pay.esop_exercises — an exercise request; the money- and tax-bearing event (db 07 §1.3).",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "exercise_no",
              "esop_grant_id",
              "employee_id",
              "exercise_date",
              "exercised_units",
              "exercise_price_amount",
              "fmv_amount",
              "total_cost_amount",
              "perquisite_amount",
              "status"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "exercise_no": {
                "$ref": "#/components/schemas/BusinessNoRef"
              },
              "esop_grant_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "exercise_date": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "exercised_units": {
                "type": "integer",
                "minimum": 1
              },
              "exercise_price_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "fmv_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "total_cost_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "perquisite_amount": {
                "$ref": "#/components/schemas/MoneyRef",
                "description": "Taxable perquisite; India-only tax consequence."
              },
              "withholding_amount": {
                "$ref": "#/components/schemas/MoneyRef",
                "description": "0 for KSA (no personal income tax)."
              },
              "withholding_review_reason": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Finance review reason; server-derived KSA no-PIT rationale for KSA."
              },
              "withholding_deduction_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "status": {
                "$ref": "#/components/schemas/EsopExerciseStatus"
              },
              "market": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "IN",
                  "KSA",
                  null
                ],
                "readOnly": true,
                "description": "The MARKET of the legal entity the underlying grant was issued under, joined onto the ADMIN list read only (#1649). Not a column of `pay.esop_exercises` and never writable: it is `org.legal_entities.market`, reached through `pay.esop_grants.legal_entity_id`, and it is the same value `pay.esop_exercise.approve` already reads to decide whether the India withholding-review leg applies.\n\n**Why a read publishes it.** Approving an exercise on an `IN` entity REQUIRES a reviewed `withholding_amount` and a reason (`422 WITHHOLDING_REVIEW_REQUIRED` otherwise); on `KSA` it requires neither, because there is no personal income tax to withhold. The pay console knows which because it is a pay screen, but the unified approvals drawer renders one decide control for every source type and had no way to tell — so it would either demand a figure a KSA approval discards, or let an India approver submit a decision the service was always going to refuse. `null` when the grant's legal entity has been soft-deleted: the exercise still lists (the row is the queue's, not the entity's) and the client treats an unknown market as \"ask\", never as \"not required\".\n"
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "EsopExerciseCreate": {
        "type": "object",
        "required": [
          "esop_grant_id",
          "exercised_units"
        ],
        "additionalProperties": false,
        "properties": {
          "esop_grant_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "exercised_units": {
            "type": "integer",
            "minimum": 1
          }
        }
      },
      "EsopExerciseReviewInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "withholding_amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Required for India; ignored and forced to 0 for KSA."
          },
          "reason": {
            "type": "string",
            "maxLength": 1000,
            "description": "Required for India; recorded Finance-review rationale."
          }
        }
      },
      "EsopExercisePage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/EsopExercise"
                }
              }
            }
          }
        ]
      },
      "SalaryAdvance": {
        "description": "pay.salary_advances — a short-term employer-funded advance recovered through payroll (db 07 §1.4).",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "advance_no",
              "employee_id",
              "request_date",
              "amount",
              "installments_count",
              "recovery_start_period",
              "outstanding_amount",
              "status"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "advance_no": {
                "$ref": "#/components/schemas/BusinessNoRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "request_date": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "reason": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "installments_count": {
                "type": "integer",
                "minimum": 1
              },
              "recovery_start_period": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "recovered_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "outstanding_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "status": {
                "$ref": "#/components/schemas/SalaryAdvanceStatus"
              },
              "submitted_by": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "approved_by": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "approved_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "disbursed_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "SalaryAdvanceCreate": {
        "type": "object",
        "required": [
          "amount",
          "installments_count",
          "recovery_start_period"
        ],
        "additionalProperties": false,
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "reason": {
            "type": "string"
          },
          "installments_count": {
            "type": "integer",
            "minimum": 1
          },
          "recovery_start_period": {
            "$ref": "#/components/schemas/DateOnlyRef"
          }
        }
      },
      "SalaryAdvancePage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/SalaryAdvance"
                }
              }
            }
          }
        ]
      },
      "EmployeeLoan": {
        "description": "pay.employee_loans — a structured employer-funded loan recovered via a generated EMI schedule (db 07 §1.4).",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "loan_no",
              "employee_id",
              "loan_type",
              "principal_amount",
              "interest_rate",
              "tenure_months",
              "emi_amount",
              "outstanding_principal",
              "recovery_start_date",
              "status"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "loan_no": {
                "$ref": "#/components/schemas/BusinessNoRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "loan_type": {
                "$ref": "#/components/schemas/LoanType"
              },
              "principal_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "interest_rate": {
                "$ref": "#/components/schemas/RateRef"
              },
              "tenure_months": {
                "type": "integer",
                "minimum": 1
              },
              "emi_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "outstanding_principal": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "recovery_start_date": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "status": {
                "$ref": "#/components/schemas/EmployeeLoanStatus"
              },
              "submitted_by": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "approved_by": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "approved_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "disbursed_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "closed_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "EmployeeLoanCreate": {
        "type": "object",
        "required": [
          "loan_type",
          "principal_amount",
          "tenure_months",
          "recovery_start_date"
        ],
        "additionalProperties": false,
        "properties": {
          "loan_type": {
            "$ref": "#/components/schemas/LoanType"
          },
          "principal_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "interest_rate": {
            "$ref": "#/components/schemas/RateRef"
          },
          "tenure_months": {
            "type": "integer",
            "minimum": 1
          },
          "recovery_start_date": {
            "$ref": "#/components/schemas/DateOnlyRef"
          }
        }
      },
      "EmployeeLoanPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/EmployeeLoan"
                }
              }
            }
          }
        ]
      },
      "LoanEmi": {
        "description": "pay.loan_emis — one scheduled instalment for an employee loan (db 07 §1.4).",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "employee_loan_id",
              "installment_no",
              "due_period",
              "principal_amount",
              "total_amount",
              "status"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "employee_loan_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "installment_no": {
                "type": "integer",
                "minimum": 1
              },
              "due_period": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "principal_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "interest_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "total_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "status": {
                "$ref": "#/components/schemas/LoanEmiStatus"
              },
              "recovered_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "deduction_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "recovered_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "LoanEmiPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/LoanEmi"
                }
              }
            }
          }
        ]
      },
      "FullFinalSettlement": {
        "description": "pay.full_final_settlements — the leaver's reconciled exit settlement; immutable once published (db 07 §1.5).",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "settlement_no",
              "employee_id",
              "last_working_date",
              "status",
              "net_settlement_amount",
              "no_dues_cleared"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "settlement_no": {
                "$ref": "#/components/schemas/BusinessNoRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "exit_case_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "last_working_date": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "payroll_run_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "settlement_payslip_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "pending_salary_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "leave_encashment_days": {
                "$ref": "#/components/schemas/DecimalHoursRef"
              },
              "leave_encashment_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "gratuity_amount": {
                "$ref": "#/components/schemas/MoneyRef",
                "description": "India only; exactly one of gratuity_amount/eosb_amount is non-zero."
              },
              "eosb_amount": {
                "$ref": "#/components/schemas/MoneyRef",
                "description": "KSA only end-of-service benefit."
              },
              "other_earnings_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "notice_recovery_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "loan_recovery_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "tax_amount": {
                "$ref": "#/components/schemas/MoneyRef",
                "description": "India-only TDS on the settlement."
              },
              "net_settlement_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "no_dues_cleared": {
                "type": "boolean"
              },
              "clearance_ref": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "status": {
                "$ref": "#/components/schemas/FullFinalSettlementStatus"
              },
              "submitted_by": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "approved_by": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "approved_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "published_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "FullFinalSettlementDetail": {
        "description": "What `pay.full_final_settlement.get_admin` answers (issue #194): the settlement row, **plus** the two sub-resources that have no operation of their own because `operationId` is the permission token (ADR 0015) and neither is addressable apart from its settlement. `pay.full_final_settlement.list_admin` answers the base `FullFinalSettlement` and carries neither.\n",
        "allOf": [
          {
            "$ref": "#/components/schemas/FullFinalSettlement"
          },
          {
            "type": "object",
            "properties": {
              "overrides": {
                "type": "array",
                "description": "The settlement's governed manual overrides, oldest first. PAY-S15 needs this to honour design-finance/02 §5's last rule — an overridden line loses its `View derivation →` and carries a permanent `Manual override — <reason>, approved by <checker>` badge, which the screen cannot render without knowing the override's reason and its checker.\n",
                "items": {
                  "$ref": "#/components/schemas/FullFinalSettlementOverride"
                }
              },
              "explanation": {
                "$ref": "#/components/schemas/FnfExplanationBundle"
              }
            }
          }
        ]
      },
      "FullFinalSettlementInitiate": {
        "type": "object",
        "required": [
          "employee_id",
          "last_working_date"
        ],
        "additionalProperties": false,
        "properties": {
          "employee_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "exit_case_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "last_working_date": {
            "$ref": "#/components/schemas/DateOnlyRef"
          }
        }
      },
      "FullFinalSettlementClearanceInput": {
        "type": "object",
        "required": [
          "clearance_ref"
        ],
        "additionalProperties": false,
        "properties": {
          "clearance_ref": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "FullFinalSettlementOverride": {
        "type": "object",
        "required": [
          "id",
          "full_final_settlement_id",
          "failed_prerequisites",
          "override_values",
          "reason",
          "status",
          "submitted_by"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "full_final_settlement_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "failed_prerequisites": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "override_values": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/MoneyRef"
            }
          },
          "reason": {
            "type": "string",
            "maxLength": 1000
          },
          "status": {
            "type": "string",
            "enum": [
              "REQUESTED",
              "APPROVED",
              "REJECTED"
            ]
          },
          "submitted_by": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "approved_by": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "approved_at": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TimestampRef"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "FullFinalSettlementOverrideInput": {
        "type": "object",
        "required": [
          "failed_prerequisites",
          "override_values",
          "reason"
        ],
        "additionalProperties": false,
        "properties": {
          "failed_prerequisites": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "override_values": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "pending_salary_amount",
              "leave_encashment_days",
              "leave_encashment_amount",
              "gratuity_amount",
              "eosb_amount",
              "other_earnings_amount",
              "notice_recovery_amount",
              "loan_recovery_amount",
              "tax_amount"
            ],
            "properties": {
              "pending_salary_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "leave_encashment_days": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "leave_encashment_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "gratuity_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "eosb_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "other_earnings_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "notice_recovery_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "loan_recovery_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "tax_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              }
            }
          },
          "reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1000
          }
        }
      },
      "FullFinalSettlementPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/FullFinalSettlement"
                }
              }
            }
          }
        ]
      },
      "TaxRegimeChoice": {
        "description": "tax.tax_regime_choices — the employee's India regime election for a fiscal year (db 07 §2.1). India-only.",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "employee_id",
              "fiscal_year",
              "regime",
              "is_locked"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "fiscal_year": {
                "type": "integer"
              },
              "regime": {
                "$ref": "#/components/schemas/TaxRegime"
              },
              "is_locked": {
                "type": "boolean"
              },
              "effective_from": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/DateOnlyRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "chosen_at": {
                "$ref": "#/components/schemas/TimestampRef"
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "TaxRegimeChoiceCreate": {
        "type": "object",
        "required": [
          "fiscal_year",
          "regime"
        ],
        "additionalProperties": false,
        "properties": {
          "fiscal_year": {
            "type": "integer"
          },
          "regime": {
            "$ref": "#/components/schemas/TaxRegime"
          },
          "effective_from": {
            "$ref": "#/components/schemas/DateOnlyRef"
          }
        }
      },
      "TaxRegimeChoiceUpdate": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "regime": {
            "$ref": "#/components/schemas/TaxRegime"
          },
          "effective_from": {
            "$ref": "#/components/schemas/DateOnlyRef"
          }
        }
      },
      "TaxRegimeChoicePage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TaxRegimeChoice"
                }
              }
            }
          }
        ]
      },
      "TaxDeclaration": {
        "description": "tax.tax_declarations — the employee's investment-declaration header for an India FY (db 07 §2.1). India-only.",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "declaration_no",
              "employee_id",
              "fiscal_year",
              "regime",
              "window",
              "total_declared_amount",
              "total_verified_amount",
              "status"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "declaration_no": {
                "$ref": "#/components/schemas/BusinessNoRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "fiscal_year": {
                "type": "integer"
              },
              "regime": {
                "$ref": "#/components/schemas/TaxRegime"
              },
              "window": {
                "$ref": "#/components/schemas/DeclarationWindow"
              },
              "total_declared_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "total_verified_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "status": {
                "$ref": "#/components/schemas/TaxDeclarationStatus"
              },
              "submitted_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "TaxDeclarationDetail": {
        "description": "A declaration as the SELF-scoped `GET /tax-declarations/{id}` returns it: the header of `TaxDeclaration` plus the employee's own item lines. The same shape the payslip and ESOP-grant detail reads use (`earnings`/`deductions`, `vesting_schedules`) — a self-scoped detail read carries the children the owner cannot otherwise list.",
        "allOf": [
          {
            "$ref": "#/components/schemas/TaxDeclaration"
          },
          {
            "type": "object",
            "required": [
              "items"
            ],
            "properties": {
              "items": {
                "type": "array",
                "description": "Ordered by statutory section, then by creation. Never paged — bounded by the SECTIONS enum.",
                "items": {
                  "$ref": "#/components/schemas/DeclarationItem"
                }
              }
            }
          }
        ]
      },
      "TaxDeclarationCreate": {
        "type": "object",
        "required": [
          "fiscal_year",
          "window"
        ],
        "additionalProperties": false,
        "properties": {
          "fiscal_year": {
            "type": "integer"
          },
          "window": {
            "$ref": "#/components/schemas/DeclarationWindow"
          }
        }
      },
      "TaxDeclarationPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TaxDeclaration"
                }
              }
            }
          }
        ]
      },
      "TaxDeclarationRosterEntry": {
        "type": "object",
        "required": [
          "employee_id",
          "employee_no",
          "employee_name",
          "legal_entity_id",
          "legal_entity_code",
          "legal_entity_name",
          "market",
          "currency_code"
        ],
        "properties": {
          "employee_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "employee_no": {
            "type": "string"
          },
          "employee_name": {
            "type": "string"
          },
          "legal_entity_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "legal_entity_code": {
            "type": "string"
          },
          "legal_entity_name": {
            "type": "string"
          },
          "market": {
            "type": "string",
            "enum": [
              "IN",
              "KSA"
            ]
          },
          "currency_code": {
            "$ref": "#/components/schemas/CurrencyCodeRef"
          }
        }
      },
      "TaxDeclarationRosterPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "maxItems": 200,
                "items": {
                  "$ref": "#/components/schemas/TaxDeclarationRosterEntry"
                }
              }
            }
          }
        ]
      },
      "TaxDeclarationExportRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "fiscal_year"
        ],
        "properties": {
          "fiscal_year": {
            "type": "integer",
            "minimum": 2000,
            "maximum": 2100
          },
          "legal_entity_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "status": {
            "$ref": "#/components/schemas/TaxDeclarationStatus"
          },
          "format": {
            "type": "string",
            "enum": [
              "CSV"
            ],
            "default": "CSV"
          }
        }
      },
      "DeclarationItem": {
        "description": "tax.declaration_items — one declared deduction line under a declaration (db 07 §2.1). India-only.",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "declaration_id",
              "section",
              "declared_amount",
              "eligible_amount",
              "verified_amount",
              "status"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "declaration_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "section": {
                "$ref": "#/components/schemas/DeclarationItemSection"
              },
              "sub_category": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "declared_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "cap_amount": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/MoneyRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "eligible_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "verified_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "status": {
                "$ref": "#/components/schemas/DeclarationItemStatus"
              },
              "verified_by": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "verified_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "DeclarationItemCreate": {
        "type": "object",
        "required": [
          "section",
          "declared_amount"
        ],
        "additionalProperties": false,
        "properties": {
          "section": {
            "$ref": "#/components/schemas/DeclarationItemSection"
          },
          "sub_category": {
            "type": "string"
          },
          "declared_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          }
        }
      },
      "DeclarationItemUpdate": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "sub_category": {
            "type": "string"
          },
          "declared_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          }
        }
      },
      "DeclarationItemPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DeclarationItem"
                }
              }
            }
          }
        ]
      },
      "TaxProof": {
        "description": "tax.tax_proofs — an uploaded supporting proof for a declared item (db 07 §2.2). India-only.",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "declaration_item_id",
              "proof_type",
              "document",
              "amount_claimed",
              "amount_verified",
              "status"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "declaration_item_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "proof_type": {
                "$ref": "#/components/schemas/TaxProofType"
              },
              "document": {
                "$ref": "#/components/schemas/FileDownloadRef"
              },
              "amount_claimed": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "amount_verified": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "status": {
                "$ref": "#/components/schemas/TaxProofStatus"
              },
              "verified_by": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "verified_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "rejection_reason": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "TaxProofCreate": {
        "type": "object",
        "required": [
          "proof_type",
          "storage_key",
          "content_hash",
          "amount_claimed"
        ],
        "additionalProperties": false,
        "properties": {
          "proof_type": {
            "$ref": "#/components/schemas/TaxProofType"
          },
          "storage_key": {
            "type": "string",
            "description": "Tenant-prefixed key returned by `xc.file.request_upload_url`; verified against object storage before ownership is recorded."
          },
          "content_hash": {
            "type": "string",
            "pattern": "^[A-Fa-f0-9]{64}$",
            "description": "SHA-256 digest of the uploaded evidence, retained with the new xc.object_refs ownership record."
          },
          "amount_claimed": {
            "$ref": "#/components/schemas/MoneyRef"
          }
        }
      },
      "TaxProofDecision": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "amount_verified": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "rejection_reason": {
            "type": "string"
          }
        }
      },
      "TaxProofPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TaxProof"
                }
              }
            }
          }
        ]
      },
      "Form16": {
        "description": "tax.form16 — the year-end Form 16 certificate; append-only, a reissue is a new row (db 07 §2.2). India-only.",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "form16_no",
              "employee_id",
              "legal_entity_id",
              "fiscal_year",
              "regime",
              "gross_salary_amount",
              "taxable_income_amount",
              "total_tax_amount",
              "tds_deposited_amount",
              "issued_at"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "form16_no": {
                "$ref": "#/components/schemas/BusinessNoRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "legal_entity_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "payroll_run_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "fiscal_year": {
                "type": "integer"
              },
              "regime": {
                "$ref": "#/components/schemas/TaxRegime"
              },
              "pan": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "tan": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "traces_ack_no": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "gross_salary_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "chapter_via_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "taxable_income_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "total_tax_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "tds_deposited_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "issued_at": {
                "$ref": "#/components/schemas/TimestampRef"
              }
            }
          },
          {
            "$ref": "#/components/schemas/AppendOnlyMetaRef"
          }
        ]
      },
      "Form16Page": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Form16"
                }
              }
            }
          }
        ]
      },
      "Form16AdminGridRow": {
        "type": "object",
        "additionalProperties": false,
        "description": "One employee/fiscal-year issuance row sourced from TDS records. `id` is the stable source TDS UUID used for cursor pagination; certificate fields remain null while the row is pending.\n",
        "required": [
          "id",
          "employee_id",
          "fiscal_year",
          "taxable_income_amount",
          "tds_deposited_amount",
          "employee_no",
          "employee_name",
          "legal_entity_id",
          "legal_entity_name",
          "form16_status"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "employee_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "fiscal_year": {
            "type": "integer"
          },
          "taxable_income_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "tds_deposited_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          },
          "employee_no": {
            "$ref": "#/components/schemas/BusinessNoRef"
          },
          "employee_name": {
            "type": "string"
          },
          "legal_entity_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "legal_entity_name": {
            "type": "string"
          },
          "form16_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "form16_no": {
            "type": [
              "string",
              "null"
            ]
          },
          "issued_at": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TimestampRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "content_hash": {
            "type": [
              "string",
              "null"
            ]
          },
          "storage_key": {
            "type": [
              "string",
              "null"
            ]
          },
          "form16_status": {
            "type": "string",
            "enum": [
              "ISSUED",
              "PENDING"
            ]
          }
        }
      },
      "Form16AdminGridPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Form16AdminGridRow"
                }
              }
            }
          }
        ]
      },
      "Form16IssueRequest": {
        "type": "object",
        "required": [
          "employee_id",
          "fiscal_year"
        ],
        "additionalProperties": false,
        "description": "Single-employee issuance. legal_entity_id is optional and, when sent, is VALIDATED against the employee's own legal entity rather than trusted — the certificate's entity always comes from people.employees. Use tax.form16.issue_batch for the all-verified run.\n",
        "properties": {
          "fiscal_year": {
            "type": "integer"
          },
          "employee_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "legal_entity_id": {
            "$ref": "#/components/schemas/UuidRef"
          }
        }
      },
      "Form16IssueBatchRequest": {
        "type": "object",
        "required": [
          "fiscal_year"
        ],
        "additionalProperties": false,
        "description": "Fiscal year to run, optionally narrowed to one legal entity.",
        "properties": {
          "fiscal_year": {
            "type": "integer"
          },
          "legal_entity_id": {
            "$ref": "#/components/schemas/UuidRef"
          }
        }
      },
      "Form16IssueAccepted": {
        "type": "object",
        "readOnly": true,
        "description": "Acceptance envelope for the async issuance job.",
        "required": [
          "fiscal_year",
          "status"
        ],
        "properties": {
          "fiscal_year": {
            "type": "integer"
          },
          "legal_entity_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "employee_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "ACCEPTED"
            ]
          },
          "form16_id": {
            "$ref": "#/components/schemas/UuidRef",
            "description": "The id the queued certificate will be written under. Minted here and carried to the jobs tier verbatim, so a poll on this id resolves once the job commits (#176)."
          },
          "form16_no": {
            "$ref": "#/components/schemas/BusinessNoRef"
          },
          "prior_form16_id": {
            "$ref": "#/components/schemas/UuidRef",
            "description": "Reissue only — the certificate this one compensates."
          }
        }
      },
      "Form16IssueBatchAccepted": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Form16IssueAccepted"
          },
          {
            "type": "object",
            "required": [
              "issued"
            ],
            "properties": {
              "issued": {
                "type": "integer",
                "description": "How many certificates were enqueued; 0 with a message when nothing was pending."
              },
              "message": {
                "type": "string"
              }
            }
          }
        ]
      },
      "TdsRecord": {
        "description": "tax.tds_records — the per-month TDS record; append-only, one live row per wage month (db 07 §2.2). India-only.",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "employee_id",
              "fiscal_year",
              "wage_month",
              "quarter",
              "regime",
              "regime_source",
              "projected_annual_income_amount",
              "taxable_income_amount",
              "tax_deducted_amount",
              "deducted_at"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "fiscal_year": {
                "type": "integer"
              },
              "wage_month": {
                "type": "string",
                "description": "YYYY-MM."
              },
              "quarter": {
                "$ref": "#/components/schemas/TaxQuarter"
              },
              "payslip_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "payroll_run_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "regime": {
                "$ref": "#/components/schemas/TaxRegime"
              },
              "regime_source": {
                "$ref": "#/components/schemas/TaxRegimeSource"
              },
              "projected_annual_income_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "taxable_income_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "tax_deducted_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "tds_rate": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/RateRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "challan_ref": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "traces_ack_no": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "deducted_at": {
                "$ref": "#/components/schemas/TimestampRef"
              }
            }
          },
          {
            "$ref": "#/components/schemas/AppendOnlyMetaRef"
          }
        ]
      },
      "TdsRecordPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TdsRecord"
                }
              }
            }
          }
        ]
      },
      "PayPeriodStatus": {
        "type": "string",
        "enum": [
          "OPEN",
          "CUTOFF_PASSED",
          "INPUTS_LOCKED",
          "RUN_LINKED",
          "CLOSED"
        ],
        "description": "'pay.pay_period_status (ADR 0028 §(c)).' Only `OPEN → CUTOFF_PASSED` is advanced by the clock, when `cutoff_at` passes; `INPUTS_LOCKED`, `RUN_LINKED` and `CLOSED` are set by operator action and by the run lifecycle, never by a timer.\n"
      },
      "PayrollInputType": {
        "type": "string",
        "enum": [
          "ATTENDANCE_SUMMARY",
          "OVERTIME",
          "LEAVE_ENCASHMENT",
          "TIMESHEET_HOURS",
          "PIECE_RATE_UNITS",
          "ARREAR",
          "MANUAL_ADJUSTMENT",
          "ADVANCE_RECOVERY",
          "LOAN_EMI"
        ],
        "description": "pay.payroll_input_type (ADR 0030 §(a)) — an APPEND-ONLY enum, never renamed."
      },
      "PayrollInputStatus": {
        "type": "string",
        "enum": [
          "RECEIVED",
          "APPLIED",
          "SUPERSEDED",
          "SPILLED",
          "HELD"
        ],
        "description": "'pay.payroll_input_status (ADR 0030 §(a)).' `APPLIED` is stamped by populate with the realizing `applied_payslip_id`. `SUPERSEDED`''s precise rule (which of two inputs for the same `(employee, period, type)` wins) is settled per input type by its consumer rather than centrally — a known residue to centralize once more than one type actually supersedes.\n"
      },
      "RunValidationSeverity": {
        "type": "string",
        "enum": [
          "HARD",
          "SOFT"
        ],
        "description": "'`HARD` blocks `DRAFT → PREVIEWING`; `SOFT` requires an audited acknowledgement before `APPROVED` (ADR 0029 §(f)).' Both codes migration `0218` appends (`OVERTIME_UNPROJECTED`, `PARTIAL_EXCEEDS_NET`, #1553) are `SOFT`. Seven of the thirteen launch codes are `HARD` — `BANK_MISSING`, `UAN_DUPLICATE`, `NEGATIVE_NET`, `WAGE_FLOOR_BREACH`, `MIN_WAGE_BREACH`, `COMP_ROW_MISSING`, `STRUCTURE_MISSING`, `ATTENDANCE_UNFINALIZED` — and six are `SOFT`. The grading test is: **can the finding be true and the payroll still be correct to pay?** `BANK_DUPLICATE` is `SOFT` because a couple who genuinely share an account have nothing to *fix*, and a `HARD` finding is cleared only by fixing the fact. The per-code grading is tabulated in `db-docs/07 §1.7`.\n"
      },
      "RunValidationStatus": {
        "type": "string",
        "enum": [
          "OPEN",
          "ACKNOWLEDGED",
          "RESOLVED"
        ],
        "description": "`OPEN → ACKNOWLEDGED` (`SOFT` only — the database refuses an acknowledged `HARD` finding) or `OPEN → RESOLVED` (the next `pay.payroll_run.validate` no longer raises it). A finding is never deleted: the queue shrinking is the operator's feedback loop, and a cleared finding is audit evidence.\n"
      },
      "RunValidationRuleCode": {
        "type": "string",
        "enum": [
          "BANK_MISSING",
          "BANK_DUPLICATE",
          "PAN_INVALID",
          "UAN_DUPLICATE",
          "UAN_AADHAAR_UNSEEDED",
          "PT_STATE_MISSING",
          "ESI_PERIOD_THRESHOLD_CROSSING",
          "NEGATIVE_NET",
          "WAGE_FLOOR_BREACH",
          "MIN_WAGE_BREACH",
          "COMP_ROW_MISSING",
          "STRUCTURE_MISSING",
          "ATTENDANCE_UNFINALIZED",
          "OVERTIME_UNPROJECTED",
          "PARTIAL_EXCEEDS_NET"
        ],
        "description": "'pay.run_validation_rule_code (ADR 0029 §(f)) — append-only.' The last two members are migration `0218`'s (#1553): `OVERTIME_UNPROJECTED` compares the target period's `ATTENDANCE_SUMMARY` `ot_hours_approved` against the sum of that period's projected `OVERTIME` inputs, and `PARTIAL_EXCEEDS_NET` records a partial-payment instruction a re-populate outgrew. Both are `SOFT`. `NEGATIVE_NET` exists because a computation landing below zero is **never silently clamped**: a clamp hides a recovery schedule that has outrun the employee''s earnings, which is precisely the situation a payroll manager must see. `ESI_PERIOD_THRESHOLD_CROSSING` encodes the April–September / October–March contribution-period continuation rule — an employee crossing the wage threshold mid-period keeps contributing until the period ends. India-only rule codes are inert under a KSA pack.\n"
      },
      "RunEmployeeActionType": {
        "type": "string",
        "enum": [
          "PAY",
          "HOLD",
          "VOID",
          "PARTIALLY_PAY",
          "PAY_OUTSIDE_PAYROLL"
        ],
        "description": "pay.run_employee_action (ADR 0030 §(f)). Every action carries a mandatory comment, an actor and a timestamp."
      },
      "ArrearReceiptStatus": {
        "type": "string",
        "enum": [
          "PENDING",
          "SCHEDULED",
          "PAID"
        ],
        "description": "pay.arrear_receipt_status (ADR 0030 §(d))."
      },
      "ArrearSourceType": {
        "type": "string",
        "enum": [
          "REGULARIZATION_POST_LOCK",
          "ATTENDANCE_AMENDMENT",
          "COMP_REVISION_RETRO",
          "STRUCTURE_RETRO",
          "PARTIAL_PAYMENT_REMAINDER"
        ],
        "description": "'pay.arrear_source_type (ADR 0030 §(d)) — append-only.' `COMP_REVISION_RETRO` and `STRUCTURE_RETRO` are declared here although their triggers live in the compensation and pay-structure flows — named up front so the receipt table never needs widening later. `PARTIAL_PAYMENT_REMAINDER` (migration 0121, #571) is the member ADR 0030 did not name: §(f) requires a `PARTIALLY_PAY` remainder to raise a `PENDING` receipt, and the other four all describe retro *corrections* rather than a deliberately withheld part of this month's net — reusing one would make the register lie about why the money is owed. Its `source_ref` is the **payslip**, so re-partialling the same person re-prices the existing receipt instead of minting a second claim on the same money.\n"
      },
      "ExplanationTargetType": {
        "type": "string",
        "enum": [
          "EARNING",
          "DEDUCTION",
          "PAYSLIP",
          "VARIANCE",
          "FNF_LINE"
        ],
        "description": "'pay.pay_explanation_target_type (ADR 0031 §(a)).' `PAYSLIP` covers slip-wide steps (net computation, rounding) and is valid but never sufficient alone — the question is almost always about a line.\n"
      },
      "PayModel": {
        "type": "string",
        "enum": [
          "MONTHLY_SALARY",
          "DAILY_WAGE",
          "PIECE_RATE"
        ],
        "description": "'pay.pay_model (ADR 0033 §(a)) — `NOT NULL DEFAULT MONTHLY_SALARY`, so every existing compensation row and writer is unaffected.' The engine dispatches on this to produce **gross**; after gross **nothing forks** — EPF''s ₹15,000 ceiling, ESI''s ₹21,000 threshold, PT slabs, TDS, the payslip shape, the run lifecycle and the audit plane apply identically across all three. That is what makes `pay_model` an axis rather than a parallel payroll.\n"
      },
      "DecimalCount": {
        "type": "string",
        "pattern": "^-?\\d+(\\.\\d{1,2})?$",
        "description": "numeric(9,2) count (days, units) as a DECIMAL STRING, never a JSON number (db-docs/00 §6)."
      },
      "PayPeriod": {
        "description": "'pay.pay_periods — the generated, statused instance of one cycle for one pay group (ADR 0028 §(c)).' Unique `(pay_group_id, period_code)`. A period must exist **before** a run does, because inputs target it, the spill ledger reads it, and finalization references it.\n",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "pay_group_id",
              "period_code",
              "period_start",
              "period_end",
              "attendance_cycle_start",
              "attendance_cycle_end",
              "cutoff_at",
              "pay_date",
              "status",
              "payroll_run_id",
              "version"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "pay_group_id": {
                "$ref": "#/components/schemas/UuidRef",
                "description": "Soft `ref→org.pay_groups` — never a join."
              },
              "period_code": {
                "type": "string",
                "description": "e.g. `\"2026-08\"`. Tenant-unique within the pay group."
              },
              "period_start": {
                "$ref": "#/components/schemas/DateOnlyRef",
                "description": "What is PAID FOR."
              },
              "period_end": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "attendance_cycle_start": {
                "$ref": "#/components/schemas/DateOnlyRef",
                "description": "What was MEASURED. **Deliberately a separate column** from `period_start` — a factory measuring 26th→25th and paying 1st→30th is the normal case, not an edge one."
              },
              "attendance_cycle_end": {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              "cutoff_at": {
                "$ref": "#/components/schemas/TimestampRef",
                "description": "The inclusive `cutoff_day 23:59:59.999` resolved in the pay group's own timezone, so the boundary is an instant and not a fuzzy day."
              },
              "pay_date": {
                "$ref": "#/components/schemas/DateOnlyRef",
                "description": "For monthly periods, `pay_day` in the civil month after `period_end`, after `pay_date_shift_rule` (`PREVIOUS_WORKING_DAY` | `NEXT_WORKING_DAY`) was applied against weekends and the entity-level holiday calendar."
              },
              "status": {
                "$ref": "#/components/schemas/PayPeriodStatus"
              },
              "payroll_run_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The REGULAR run linked to this period. A partial unique index enforces **one REGULAR run per period** — the duplicate-run hole closed as a database fact rather than an operator convention."
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "PayPeriodDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PayPeriod"
          },
          {
            "type": "object",
            "properties": {
              "spill_in_count": {
                "type": "integer",
                "minimum": 0,
                "description": "Inputs whose `origin_period_id` is an earlier period and whose `target_period_id` is this one — a pure read over the pair, no separate store."
              },
              "spill_out_count": {
                "type": "integer",
                "minimum": 0,
                "description": "Facts that belong to this period but will be paid in a later one."
              }
            }
          }
        ]
      },
      "PayPeriodLockInputsResult": {
        "description": "The locked period, plus what the lock did to the cycle's provisional run (ADR 0069 §(b)). Additive over `PayPeriod`: a client that ignores both new members reads exactly what it read before.\n",
        "allOf": [
          {
            "$ref": "#/components/schemas/PayPeriod"
          },
          {
            "type": "object",
            "required": [
              "payroll_run_id",
              "populate_requested"
            ],
            "properties": {
              "payroll_run_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The DRAFT/PREVIEW REGULAR run this lock adopted and advanced to `RUN_LINKED`, or `null` when the cycle has no run yet."
              },
              "populate_requested": {
                "type": "boolean",
                "description": "True when a FULL `pay.payroll_run.populate_requested` was emitted for that run — poll `GET /payroll-runs/{id}` for the result."
              }
            }
          }
        ]
      },
      "PayPeriodEnsureRunResult": {
        "type": "object",
        "required": [
          "payroll_run",
          "created",
          "populate_requested"
        ],
        "properties": {
          "payroll_run": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PayrollRunDetail"
              }
            ],
            "description": "Byte-for-byte the `GET /payroll-runs/{id}` body — the same reader, so it carries every member that read carries (`stage_progress`, `jobs[]`, `disbursement`, `is_provisional`) and cannot drift from it. Read AFTER this call's writes, so `jobs[]` already shows the `QUEUED` populate."
          },
          "created": {
            "type": "boolean",
            "description": "True when this call created the run; false when it found one. Not a status-code distinction on purpose — the contract is \"this cycle has a run\", and both outcomes are `200`."
          },
          "populate_requested": {
            "type": "boolean",
            "description": "True when a `pay.payroll_run.populate_requested` was emitted (the run is `DRAFT` or `PREVIEW`). False for a run already past `APPROVED`, which lets the console say \"estimate already final\" instead of pretending it queued something."
          }
        }
      },
      "PayPeriodPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PayPeriod"
                }
              }
            }
          }
        ]
      },
      "PayPeriodPreview": {
        "type": "object",
        "required": [
          "period_code",
          "period_start",
          "period_end",
          "attendance_cycle_start",
          "attendance_cycle_end",
          "cutoff_at",
          "pay_date",
          "status",
          "is_existing"
        ],
        "properties": {
          "id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "pay_group_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "period_code": {
            "type": "string",
            "pattern": "^\\d{4}-(0[1-9]|1[0-2])$"
          },
          "period_start": {
            "$ref": "#/components/schemas/DateOnlyRef"
          },
          "period_end": {
            "$ref": "#/components/schemas/DateOnlyRef"
          },
          "attendance_cycle_start": {
            "$ref": "#/components/schemas/DateOnlyRef"
          },
          "attendance_cycle_end": {
            "$ref": "#/components/schemas/DateOnlyRef"
          },
          "cutoff_at": {
            "$ref": "#/components/schemas/TimestampRef"
          },
          "nominal_pay_date": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DateOnlyRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "Before weekend/holiday shifting; null on a persisted row whose generation inputs are frozen."
          },
          "pay_date": {
            "$ref": "#/components/schemas/DateOnlyRef"
          },
          "pay_date_shifted": {
            "type": "boolean"
          },
          "shift_reason": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "PREVIOUS_WORKING_DAY",
              "NEXT_WORKING_DAY",
              null
            ]
          },
          "status": {
            "$ref": "#/components/schemas/PayPeriodStatus"
          },
          "is_existing": {
            "type": "boolean",
            "description": "True means the persisted row is returned unchanged and was not recomputed under draft settings."
          }
        }
      },
      "PayPeriodPreviewPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "required": [
              "preview"
            ],
            "properties": {
              "data": {
                "type": "array",
                "minItems": 1,
                "maxItems": 12,
                "items": {
                  "$ref": "#/components/schemas/PayPeriodPreview"
                }
              },
              "preview": {
                "type": "object",
                "required": [
                  "holiday_calendar_readable"
                ],
                "properties": {
                  "holiday_calendar_readable": {
                    "type": "boolean",
                    "description": "False means pay dates are deliberately unshifted and the UI must show the prescribed warning."
                  }
                }
              }
            }
          }
        ]
      },
      "RunStage": {
        "type": "string",
        "enum": [
          "ATTENDANCE_FINALIZED",
          "INPUTS_LOCKED",
          "POPULATED",
          "VALIDATED",
          "VARIANCE_REVIEWED",
          "APPROVED",
          "EXECUTED",
          "PUBLISHED"
        ],
        "description": "pay.run_stage — the readiness pipeline's stages, in order. Append-only."
      },
      "RunStageEvidenceType": {
        "type": "string",
        "enum": [
          "FINALIZATION",
          "INPUT_BATCH",
          "VALIDATION_SNAPSHOT",
          "APPROVAL_INBOX_ROW",
          "RUN_EVENT"
        ],
        "description": "What `evidence_ref` points at — the proof the stage was SATISFIED rather than merely clicked. `FINALIZATION` → `attend.attendance_cycle_finalizations` · `INPUT_BATCH` → `pay.payroll_inputs` · `VALIDATION_SNAPSHOT` → `pay.run_validations` · `APPROVAL_INBOX_ROW` → `xc.approval_inbox` · `RUN_EVENT` → the run itself.\n"
      },
      "RunStageProgress": {
        "description": "'pay.run_stage_progress — one row per `(run, stage)` (ADR 0029 §(c), db 07 §1.7).' **Deliberately not a second lifecycle:** `payroll_runs.status` remains the sole authority and this is the observable record of *how* the run got ready. A row EXISTS once its stage is satisfied; a missing stage renders as outstanding. There is no per-row status and no reversal — a re-populate rewrites the `POPULATED` row and **drops every stage downstream of it**, because a `VALIDATED` row standing over regenerated money would be the pipeline lying about which figures were checked.\n",
        "type": "object",
        "required": [
          "id",
          "stage",
          "completed_at",
          "evidence_type"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "stage": {
            "$ref": "#/components/schemas/RunStage"
          },
          "completed_by": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "The actor; `null` for a job-completed stage (`POPULATED`, `EXECUTED`)."
          },
          "completed_at": {
            "$ref": "#/components/schemas/TimestampRef"
          },
          "evidence_type": {
            "$ref": "#/components/schemas/RunStageEvidenceType"
          },
          "evidence_ref": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "The proving row, resolved by `evidence_type` (soft polymorphic)."
          }
        }
      },
      "PayrollRunJobStatus": {
        "type": "string",
        "enum": [
          "QUEUED",
          "RUNNING",
          "SUCCEEDED",
          "FAILED",
          "RETRYING",
          "CANCELLED"
        ],
        "description": "`xc.job_run_status` — the jobs-tier ledger's own states, reported unmapped."
      },
      "PayrollRunJob": {
        "description": "One `xc.job_runs` row for this run — the observable progress of an act the API answered `202` for (#1547). `populate`, `preview`, `execute` and `publish` each mint a `QUEUED` row in the same transaction as their outbox event; the handler marks it `RUNNING` and then `SUCCEEDED` (with `result` counts) or `FAILED` (with `error`). This is what a client polls instead of offering a manual Refresh button, and it is how a run stuck in `EXECUTING` becomes legible: the run's `status` says what state the money is in, `jobs[]` says whether anything is still working on it.\n",
        "type": "object",
        "required": [
          "job_name",
          "status"
        ],
        "properties": {
          "job_name": {
            "type": "string",
            "enum": [
              "pay.populate_payroll_run",
              "pay.preview_payroll_run",
              "pay.execute_payroll_run",
              "pay.publish_payroll_run"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/PayrollRunJobStatus"
          },
          "started_at": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TimestampRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "finished_at": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TimestampRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Non-null exactly when `status = FAILED` (`job_runs_failed_has_error`)."
          },
          "result": {
            "anyOf": [
              {
                "type": "object",
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "Outcome counts on success — e.g. `payslips_written`, `findings`, `payslips_published`."
          }
        }
      },
      "PayrollRunDetail": {
        "description": "The run plus its readiness pipeline — the `GET /payroll-runs/{id}` shape (PAY-S21, PAY-S10).",
        "allOf": [
          {
            "$ref": "#/components/schemas/PayrollRun"
          },
          {
            "type": "object",
            "properties": {
              "stage_progress": {
                "type": "array",
                "description": "Satisfied stages, oldest first. Absent stages are outstanding, not failed.",
                "items": {
                  "$ref": "#/components/schemas/RunStageProgress"
                }
              },
              "jobs": {
                "type": "array",
                "description": "The LATEST `xc.job_runs` row per job name for this run, oldest first — not the full history, which stays queryable through the `xc` job-run reads. Empty for a run whose async acts all predate #1547. No new token: this is run-shaped progress inside the run read's own tenant scope, exactly as `stage_progress` is.\n",
                "items": {
                  "$ref": "#/components/schemas/PayrollRunJob"
                }
              },
              "is_provisional": {
                "type": "boolean",
                "description": "**Derived, never stored** (ADR 0069 §(b), #1551). `true` while the run's inputs can still change underneath it — that is, while its pay period is anything other than `INPUTS_LOCKED`, `RUN_LINKED` or `CLOSED`. A period-less run (`SUPPLEMENTARY`, `ARREARS`, `OFF_CYCLE`, `FNF`) is never provisional: it has no calendar to be ahead of. The ONE honest signal for \"these numbers can still move\" is the period's own status, not a flag somebody remembered to set.\n"
              },
              "disbursement": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/RunDisbursementSummary"
                  }
                ],
                "description": "The cycle's payment picture, rolled up from `pay.payslip_disbursements` on every read (#1551). No new token — this is run-shaped state inside the run read's own tenant scope, exactly as `stage_progress` and `jobs` are. It is **not** a column on the run and never will be: a run that is partly paid is not in one state, and the immutability trigger would refuse the `UPDATE` that maintaining one would need.\n"
              }
            }
          }
        ]
      },
      "DisbursementState": {
        "type": "string",
        "enum": [
          "PENDING",
          "HELD",
          "PARTIAL",
          "RELEASED",
          "OUTSIDE_PAYROLL",
          "VOID"
        ],
        "description": "`pay.disbursement_state` — where one payslip's money stands. `PENDING` owed, nothing moved · `HELD` deliberately withheld **in this cycle**, facts intact · `PARTIAL` some money moved and a real remainder is still owed · `RELEASED` settled and frozen · `OUTSIDE_PAYROLL` paid by another route (inside statutory computation, `due_amount = 0`) · `VOID` the slip was cancelled and nothing is owed.\n"
      },
      "RunDisbursementSummary": {
        "type": "object",
        "description": "Counts and money for one run's ledger. `complete` is the ADR 0069 §(g) predicate — the cycle is done when no payable row still has money outstanding — expressed that way rather than as \"every row reached RELEASED\" so a legitimate zero-net slip (a full-LOP month) does not hold a cycle open forever.\n",
        "properties": {
          "employee_count": {
            "type": "integer"
          },
          "released_count": {
            "type": "integer"
          },
          "partial_count": {
            "type": "integer"
          },
          "pending_count": {
            "type": "integer"
          },
          "held_count": {
            "type": "integer"
          },
          "outside_payroll_count": {
            "type": "integer"
          },
          "void_count": {
            "type": "integer"
          },
          "settled_elsewhere_count": {
            "type": "integer",
            "description": "Rows a LATER cycle's batch paid — renders as *\"Paid in ‹period›\"* on this one."
          },
          "due_amount": {
            "type": "string",
            "description": "Σ owed through payroll for this cycle. Decimal string, never a float."
          },
          "released_amount": {
            "type": "string"
          },
          "remaining_amount": {
            "type": "string"
          },
          "held_amount": {
            "type": "string"
          },
          "prior_open_balance_amount": {
            "type": "string",
            "description": "What THIS run's people still owe from EARLIER published cycles. Deliberately a separate figure: summing it into this cycle's totals is the conflation ADR 0069 §(g) rejects."
          },
          "prior_open_balance_count": {
            "type": "integer"
          },
          "complete": {
            "type": "boolean"
          }
        }
      },
      "PriorObligation": {
        "type": "object",
        "description": "One still-open obligation from an EARLIER cycle — the old ledger row, which was never closed.",
        "properties": {
          "payslip_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "payslip_no": {
            "type": "string"
          },
          "payroll_run_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "period_code": {
            "type": "string"
          },
          "state": {
            "$ref": "#/components/schemas/DisbursementState"
          },
          "due_amount": {
            "type": "string"
          },
          "released_amount": {
            "type": "string"
          },
          "remaining_amount": {
            "type": "string"
          },
          "held": {
            "type": "boolean",
            "description": "`true` for a `HELD` prior — **listed but not releasable**; releasing it would silently overturn a deliberate hold."
          }
        }
      },
      "PayslipDisbursement": {
        "type": "object",
        "description": "One employee's payment row on this cycle, plus their open balance from earlier ones.",
        "properties": {
          "employee_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "employee_no": {
            "type": "string"
          },
          "full_name": {
            "type": "string"
          },
          "department": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  "name": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Bilingual `{en, ar}` label."
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "pay_model": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "MONTHLY_SALARY",
                  "DAILY_WAGE",
                  "PIECE_RATE"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "payslip_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "payslip_no": {
            "type": "string"
          },
          "payslip_status": {
            "$ref": "#/components/schemas/PayslipStatus"
          },
          "net_pay_amount": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "action": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "action": {
                    "$ref": "#/components/schemas/RunEmployeeActionType"
                  },
                  "comment": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "partial_fraction": {
                    "anyOf": [
                      {
                        "$ref": "#/components/schemas/RateRef"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "partial_amount": {
                    "anyOf": [
                      {
                        "$ref": "#/components/schemas/MoneyRef"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "state": {
            "$ref": "#/components/schemas/DisbursementState"
          },
          "due_amount": {
            "type": "string"
          },
          "released_amount": {
            "type": "string"
          },
          "remaining_amount": {
            "type": "string"
          },
          "partial_release_amount": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The `PARTIALLY_PAY` instruction: the next batch of THIS run releases only this much."
          },
          "last_released_at": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TimestampRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_release_batch_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "settled_by_run_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "disbursement_version": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "currency_code": {
            "type": "string"
          },
          "bank_account_ready": {
            "type": "boolean",
            "description": "A VERIFIED primary bank account exists. A boolean and never an account number — the operator does not need the digits to decide whether to release."
          },
          "prior_obligations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PriorObligation"
            }
          }
        }
      },
      "PayslipDisbursementPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PayslipDisbursement"
                }
              }
            }
          }
        ]
      },
      "PriorBalancePolicy": {
        "type": "string",
        "enum": [
          "ALL",
          "NONE",
          "CUSTOM"
        ],
        "description": "How much of each employee's still-open balance from EARLIER cycles this batch settles. `ALL` pays every open prior obligation · `NONE` pays only this cycle · `CUSTOM` pays the per-employee amounts in `prior_balance_custom`, allocated oldest period first.\n"
      },
      "ReleaseBatchCreateRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "cohort",
          "prior_balance"
        ],
        "properties": {
          "cohort": {
            "$ref": "#/components/schemas/RunCohort",
            "description": "Who to pay, resolved server-side against **this run's own population**. A department id that means something in the org chart and nothing on this run resolves to the empty set.\n"
          },
          "prior_balance": {
            "$ref": "#/components/schemas/PriorBalancePolicy"
          },
          "prior_balance_custom": {
            "type": "array",
            "maxItems": 2000,
            "description": "Required by `CUSTOM`, refused with any other policy. An entry naming somebody outside the cohort is a `422`, not a silent no-op: a custom prior-balance amount is an explicit money instruction.\n",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "employee_id",
                "amount"
              ],
              "properties": {
                "employee_id": {
                  "$ref": "#/components/schemas/UuidRef"
                },
                "amount": {
                  "type": "string",
                  "pattern": "^\\d+(\\.\\d{1,2})?$",
                  "description": "A DECIMAL STRING, never a JSON number — money does not round-trip through an IEEE double. May never exceed the employee's open prior balance (`422`).\n"
                }
              }
            }
          },
          "layout_version": {
            "type": "string",
            "maxLength": 64,
            "description": "The bank-advice layout this batch's file is cut in (config, never code — ADR 0005). Omitted → the neutral v1 CSV layout."
          },
          "note": {
            "type": "string",
            "maxLength": 2000,
            "description": "Recorded on the batch and on the audited release act."
          }
        }
      },
      "ReleaseBatchAdviceRef": {
        "description": "Identity and integrity of the file this batch produced. No URL: a presigned handle comes only from `pay.bank_advice.download`, which logs each handout.",
        "anyOf": [
          {
            "type": "object",
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "layout_version": {
                "type": "string"
              },
              "employee_count": {
                "type": "integer",
                "minimum": 0
              },
              "total_amount": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "content_hash": {
                "type": "string",
                "description": "sha256 hex of the exact uploaded bytes."
              },
              "size_bytes": {
                "type": "integer",
                "minimum": 0
              },
              "file_name": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          },
          {
            "type": "null"
          }
        ]
      },
      "ReleaseBatch": {
        "type": "object",
        "description": "One act of releasing money — append-only, written in ONE transaction with its lines, its settlements, its ledger updates and its bank-advice file. A batch exists **if and only if** money was declared to have left.\n",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "payroll_run_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "batch_no": {
            "type": "integer",
            "minimum": 1,
            "description": "1-based per run — *\"batch 3 of the August cycle\"*."
          },
          "cohort": {
            "$ref": "#/components/schemas/RunCohort",
            "description": "What the operator CHOSE, recorded as intent. The lines are the fact."
          },
          "prior_balance_policy": {
            "$ref": "#/components/schemas/PriorBalancePolicy"
          },
          "employee_count": {
            "type": "integer",
            "minimum": 1
          },
          "this_cycle_amount": {
            "type": "string",
            "description": "Σ line `this_cycle_amount`. Decimal string."
          },
          "prior_balance_amount": {
            "type": "string",
            "description": "Σ line `prior_balance_amount` — money settling EARLIER cycles' obligations. Never part of any slip's net, which is why a prior balance is never re-taxed."
          },
          "total_amount": {
            "type": "string"
          },
          "currency_code": {
            "type": "string",
            "minLength": 3,
            "maxLength": 3,
            "description": "Asserted equal across every obligation the batch settles."
          },
          "bank_advice_file_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ]
          },
          "bank_advice_file": {
            "$ref": "#/components/schemas/ReleaseBatchAdviceRef"
          },
          "released_by": {
            "$ref": "#/components/schemas/UuidRef",
            "description": "The acting principal. MC-2: never the run's `submitted_by`."
          },
          "released_at": {
            "$ref": "#/components/schemas/TimestampRef"
          },
          "note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "ReleaseSettlement": {
        "type": "object",
        "description": "One (line, obligation) pair — how a line's money maps onto ledger rows.",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "batch_line_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "obligation_payslip_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "obligation_run_id": {
            "$ref": "#/components/schemas/UuidRef",
            "description": "The run that CREATED the obligation — never the run that settles it."
          },
          "obligation_period_code": {
            "type": "string",
            "description": "Frozen (`\"2026-07\"`) so the old cycle renders *\"paid in ‹period›\"* without a join."
          },
          "amount": {
            "type": "string"
          },
          "is_prior_cycle": {
            "type": "boolean",
            "description": "`obligation_run_id <> batch.payroll_run_id`."
          }
        }
      },
      "ReleaseBatchLine": {
        "type": "object",
        "description": "One employee per batch — and this row **is** the bank-advice line.",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "release_batch_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "employee_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "employee_no": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "full_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "this_cycle_payslip_id": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/UuidRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "`null` when the line settles ONLY prior obligations — an employee with nothing owed this cycle but a balance outstanding."
          },
          "payslip_no": {
            "type": "string",
            "description": "Frozen onto the line for the advice narration (`SALARY ‹payslip_no›`)."
          },
          "this_cycle_amount": {
            "type": "string"
          },
          "prior_balance_amount": {
            "type": "string"
          },
          "amount": {
            "type": "string",
            "description": "`this_cycle_amount + prior_balance_amount`, always > 0 — a zero line is a skip, never a row."
          },
          "settlements": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReleaseSettlement"
            }
          }
        }
      },
      "ReleaseBatchSkip": {
        "type": "object",
        "description": "An employee in the cohort who received no line, and the state that explains it.",
        "properties": {
          "employee_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "reason": {
            "type": "string",
            "enum": [
              "NO_LEDGER_ROW",
              "HELD",
              "OUTSIDE_PAYROLL",
              "VOID",
              "ALREADY_RELEASED",
              "NOTHING_PAYABLE"
            ]
          }
        }
      },
      "ReleaseBatchResult": {
        "type": "object",
        "required": [
          "batch",
          "lines",
          "skipped",
          "run"
        ],
        "properties": {
          "batch": {
            "$ref": "#/components/schemas/ReleaseBatch"
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReleaseBatchLine"
            }
          },
          "skipped": {
            "type": "array",
            "description": "Reported per employee rather than silently dropped.",
            "items": {
              "$ref": "#/components/schemas/ReleaseBatchSkip"
            }
          },
          "run": {
            "type": "object",
            "properties": {
              "payroll_run_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "disbursement": {
                "$ref": "#/components/schemas/RunDisbursementSummary"
              }
            }
          }
        }
      },
      "ReleaseBatchList": {
        "type": "object",
        "required": [
          "payroll_run_id",
          "data"
        ],
        "properties": {
          "payroll_run_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "data": {
            "type": "array",
            "description": "Newest batch number first.",
            "items": {
              "$ref": "#/components/schemas/ReleaseBatch"
            }
          }
        }
      },
      "ReleaseBatchDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ReleaseBatch"
          },
          {
            "type": "object",
            "properties": {
              "lines": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ReleaseBatchLine"
                }
              },
              "settlements": {
                "type": "array",
                "description": "Every settlement the batch wrote, flat — the same rows also hang off their own line.",
                "items": {
                  "$ref": "#/components/schemas/ReleaseSettlement"
                }
              }
            }
          }
        ]
      },
      "PayrollRunPopulateRequest": {
        "type": "object",
        "description": "Optional scoping for a partial re-populate. Omitted entirely, the call populates the whole pay-group population for the run's period — the normal case.\n",
        "additionalProperties": false,
        "properties": {
          "employee_ids": {
            "type": "array",
            "maxItems": 500,
            "items": {
              "$ref": "#/components/schemas/UuidRef"
            },
            "description": "Restrict regeneration to these employees. The delete-and-regenerate semantics apply only to the named subset."
          },
          "note": {
            "type": "string",
            "maxLength": 2000,
            "description": "Recorded on the audited populate act."
          }
        }
      },
      "PayrollInput": {
        "description": "'pay.payroll_inputs — the ONE staging surface every cross-module fact lands in (ADR 0030 §(a)).' Written only by jobs-tier consumers of outbox events; the populate engine reads pay-local data exclusively and never `attend.*`, `leave.*` or `work.*`. Because the table is keyed on the event id and never mutated by the engine that reads it, **re-populating a run is a pure function of the input set** — the property the whole re-runnability guarantee rests on.\n",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "employee_id",
              "input_type",
              "status",
              "target_period_id",
              "origin_period_id",
              "source_module",
              "source_event_id"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "pay_group_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "origin_period_id": {
                "$ref": "#/components/schemas/UuidRef",
                "description": "The period the fact BELONGS TO."
              },
              "target_period_id": {
                "$ref": "#/components/schemas/UuidRef",
                "description": "The period that will actually PAY it. A fact landing while its origin period is `OPEN` sets both the same; one landing after `cutoff_at`, or after `INPUTS_LOCKED`, keeps its origin and auto-targets the next `OPEN` period."
              },
              "input_type": {
                "$ref": "#/components/schemas/PayrollInputType"
              },
              "payload": {
                "type": "object",
                "additionalProperties": true,
                "description": "Typed per `input_type`, with decimal values carried as **strings, never JSON numbers**. Typed by convention and validated in the consumer, not by a database check constraint — a deliberate trade recorded as residue in ADR 0030."
              },
              "source_module": {
                "type": "string",
                "description": "e.g. `attend`, `leave`, `work`."
              },
              "source_event_id": {
                "$ref": "#/components/schemas/UuidRef",
                "description": "**UNIQUE — this column IS the idempotency guarantee.** It resolves to an `xc.outbox` row, which resolves to an owning-module entity: every rupee on a payslip traces back through it."
              },
              "source_ref": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The owning module's row id (soft ref)."
              },
              "status": {
                "$ref": "#/components/schemas/PayrollInputStatus"
              },
              "applied_payslip_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Stamped when a payslip realizes this input."
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "PayrollInputPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PayrollInput"
                }
              }
            }
          }
        ]
      },
      "RunValidation": {
        "description": "pay.run_validations — one row per `(run, employee, rule_code)`.",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "payroll_run_id",
              "rule_code",
              "severity"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "payroll_run_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "employee_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Null for a run-wide finding."
              },
              "rule_code": {
                "$ref": "#/components/schemas/RunValidationRuleCode"
              },
              "severity": {
                "$ref": "#/components/schemas/RunValidationSeverity"
              },
              "detail": {
                "type": "object",
                "description": "Per-employee specifics — `{ observed, expected, refs: [{ kind, ref }], hint }`. Schemaless and never queried; the queryable axes are `rule_code`, `severity` and `status`. **`refs` is also the evidence slot for the `fintech` penny-drop verification hook** — the rule and its slot exist now, the live integration is a later leg. *(Reconciled 2026-08-13, issue #570: as built this is the `jsonb` column `db-docs/07 §1.7` specifies, not a string, and the separate `evidence_ref` property it replaces was never built — same device as `fsd-docs/06 §1` coverage-gap 10a.)*\n",
                "additionalProperties": true
              },
              "status": {
                "$ref": "#/components/schemas/RunValidationStatus"
              },
              "acknowledged_by": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "acknowledged_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "acknowledgement_reason": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "resolved": {
                "type": "boolean",
                "description": "Convenience projection of `status = RESOLVED`."
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "RunValidationPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "required": [
              "counts"
            ],
            "properties": {
              "counts": {
                "type": "object",
                "description": "Blocking summary for the run — what stands between it and `PREVIEWING`.",
                "properties": {
                  "hard_open": {
                    "type": "integer"
                  },
                  "soft_open": {
                    "type": "integer"
                  },
                  "acknowledged": {
                    "type": "integer"
                  }
                }
              },
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/RunValidation"
                }
              }
            }
          }
        ]
      },
      "RunValidationSummary": {
        "type": "object",
        "description": "The blocking picture after a re-validate — what stands between the run and `PREVIEWING`, and between it and `APPROVED`. `can_preview: false` with `hard_open: 0` is not a state this operation produces.\n",
        "required": [
          "payroll_run_id",
          "hard_open",
          "soft_open",
          "can_preview"
        ],
        "properties": {
          "payroll_run_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "hard_open": {
            "type": "integer",
            "minimum": 0,
            "description": "Unresolved `HARD` findings. Any non-zero value blocks `DRAFT → PREVIEWING`; they must be fixed, never acknowledged away."
          },
          "soft_open": {
            "type": "integer",
            "minimum": 0,
            "description": "Unacknowledged `SOFT` findings. They do not block preview, but they block `APPROVED` until each carries an actor and a reason."
          },
          "acknowledged": {
            "type": "integer",
            "minimum": 0
          },
          "can_preview": {
            "type": "boolean"
          },
          "by_rule_code": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            },
            "description": "Open counts keyed by `rule_code` — the shape the PAY-S10 \"what is blocking me\" panel renders directly."
          },
          "evaluated_at": {
            "$ref": "#/components/schemas/TimestampRef"
          }
        }
      },
      "RunFindingAcknowledgeInput": {
        "type": "object",
        "description": "Shared by `pay.run_validation.acknowledge` and `pay.run_variance.acknowledge`. **The reason is mandatory** — an acknowledgement without one is not a control, and both gates write actor + reason to the append-only audit plane.\n",
        "additionalProperties": false,
        "required": [
          "reason"
        ],
        "properties": {
          "reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000
          }
        }
      },
      "RunVariance": {
        "description": "pay.run_variances — one row per `(run, employee, component)`, computed at the end of populate from pay-local history.",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "payroll_run_id",
              "employee_id",
              "component_code",
              "current_value",
              "flagged"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "payroll_run_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "component_code": {
                "type": "string",
                "description": "Earnings carry their frozen `earnings.component_code`; **employee-side** deductions carry their `deduction_type` (`pay.deductions` has no code column and the type is the code an operator recognises). Employer contributions are excluded — they are the employer's cost, not a movement in the employee's pay. `NET` is the slip-level figure.\n"
              },
              "current_value": {
                "$ref": "#/components/schemas/MoneyRef"
              },
              "prior_period_value": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/MoneyRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "same_period_last_fy_value": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/MoneyRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The seasonal comparison — a bonus month is not an anomaly against the same month last year."
              },
              "delta_prior": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/MoneyRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "delta_last_fy": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/MoneyRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "delta_pct": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/RateRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "A **fraction**, not a percent — `0.100000` is a ten-percent movement (`numeric(9,6)`, `db-docs/00 §6`) — while the pay group's `variance_flag_threshold_pct` is a percent. The prior-period movement where there is one, falling back to the seasonal movement where there is not; `null` when the comparison base is zero, because a movement from nothing is not a percentage.\n"
              },
              "flagged": {
                "type": "boolean",
                "description": "Set against the pay group's `variance_flag_threshold_pct` — tunable per population, because a single tenant-wide threshold is either theatre or noise. **The third comparison suppresses, it does not add:** a row is flagged when the prior-period movement breaches the threshold **and**, where a same-period-last-FY figure exists, that movement breaches it too. An annual bonus that doubles August against July is not an anomaly if last August did the same. A row with no comparison at all — a new joiner, a tenant's first cycle — is never flagged.\n"
              },
              "explanation_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Resolves into the `pay.pay_explanations` chain that explains the move (ADR 0031 §(c)). Triage without attribution is guesswork."
              },
              "acknowledged_by": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "acknowledged_at": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/TimestampRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "acknowledgement_reason": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "RunVariancePage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "required": [
              "counts"
            ],
            "properties": {
              "counts": {
                "type": "object",
                "properties": {
                  "flagged": {
                    "type": "integer"
                  },
                  "unacknowledged": {
                    "type": "integer"
                  }
                }
              },
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/RunVariance"
                }
              }
            }
          }
        ]
      },
      "RunEmployeeAction": {
        "description": "pay.run_employee_actions — one audited row per `(run, employee)`.",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "payroll_run_id",
              "employee_id",
              "action",
              "comment"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "payroll_run_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "action": {
                "$ref": "#/components/schemas/RunEmployeeActionType"
              },
              "comment": {
                "type": "string",
                "description": "**Mandatory.** The whole contribution of this vocabulary over the market's is that it is auditable."
              },
              "partial_fraction": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/RateRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "`PARTIALLY_PAY` only — the fraction of NET to disburse. Applied after the full stack computes, never before proration."
              },
              "partial_amount": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/MoneyRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "`PARTIALLY_PAY` only — an explicit amount instead of a fraction. Supplying both is a `422`."
              },
              "arrear_receipt_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "deprecated": true,
                "description": "**Deprecated as a writer 2026-09-02 (ADR 0069 §(d), #1551) and always `null` on new rows.** `PARTIALLY_PAY` no longer raises a `PARTIAL_PAYMENT_REMAINDER` arrear receipt — the remainder IS `pay.payslip_disbursements.remaining_amount`, read through `pay.payslip_disbursement.list`. The field and the receipts written before that date stay readable; nothing new is written to it, and the open `PENDING` remainder receipts were soft-deleted by migration `0217` so the next run cannot pay the same money twice.\n"
              },
              "acted_by": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "acted_at": {
                "$ref": "#/components/schemas/TimestampRef"
              },
              "payroll_run_version": {
                "type": "integer",
                "description": "The RUN's version after the action moved its rollups — returned on `set` only, and the value of the response `ETag`. The precondition callers need for their next action is the run's, not this row's, so the handshake would otherwise cost a second `GET` per exception.\n"
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "RunEmployeeActionSetInput": {
        "type": "object",
        "description": "`comment` is mandatory for every action, including `PAY`. `partial_fraction`/`partial_amount` are accepted only with `PARTIALLY_PAY` (a `422`, rule `cross-field`, otherwise), and never both together.",
        "additionalProperties": false,
        "required": [
          "employee_id",
          "action",
          "comment"
        ],
        "properties": {
          "employee_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "action": {
            "$ref": "#/components/schemas/RunEmployeeActionType"
          },
          "comment": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000
          },
          "partial_fraction": {
            "$ref": "#/components/schemas/RateRef"
          },
          "partial_amount": {
            "$ref": "#/components/schemas/MoneyRef"
          }
        }
      },
      "RunEmployeeActionPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/RunEmployeeAction"
                }
              }
            }
          }
        ]
      },
      "RunCohort": {
        "type": "object",
        "description": "A cohort as the operator states it (ADR 0069 §(d)). Every axis is a LIST and the axes are **ANDed**: \"the delivery department, on piece rate\" is one cohort, not two calls. `all` is the explicit whole-run cohort — spelled rather than implied by an empty object, because \"release everybody\" and \"release the empty selection I forgot to fill in\" must never be the same request; combining it with another axis is a `422`. Naming no axis at all is also a `422`.\n",
        "additionalProperties": false,
        "properties": {
          "all": {
            "type": "boolean"
          },
          "department_ids": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          "org_unit_ids": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/UuidRef"
            }
          },
          "pay_models": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string",
              "enum": [
                "MONTHLY_SALARY",
                "DAILY_WAGE",
                "PIECE_RATE"
              ]
            }
          },
          "employee_ids": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/UuidRef"
            }
          }
        }
      },
      "RunEmployeeActionBulkInput": {
        "type": "object",
        "description": "`comment` is mandatory, exactly as on the single route. `partial_fraction` is required with — and accepted only with — `PARTIALLY_PAY`; an explicit `partial_amount` is per-employee only.",
        "additionalProperties": false,
        "required": [
          "action",
          "comment",
          "cohort"
        ],
        "properties": {
          "action": {
            "$ref": "#/components/schemas/RunEmployeeActionType"
          },
          "comment": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000
          },
          "cohort": {
            "$ref": "#/components/schemas/RunCohort"
          },
          "partial_fraction": {
            "$ref": "#/components/schemas/RateRef"
          }
        }
      },
      "RunEmployeeActionBulkResult": {
        "type": "object",
        "description": "What the cohort resolved to and what actually happened to each member.",
        "properties": {
          "payroll_run_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "action": {
            "$ref": "#/components/schemas/RunEmployeeActionType"
          },
          "resolved": {
            "type": "integer",
            "description": "Employees the cohort matched on this run's own slips."
          },
          "applied": {
            "type": "integer"
          },
          "skipped": {
            "type": "array",
            "description": "Members the verb could not legally touch — reported, never silently dropped.",
            "items": {
              "type": "object",
              "properties": {
                "employee_id": {
                  "$ref": "#/components/schemas/UuidRef"
                },
                "reason": {
                  "type": "string",
                  "enum": [
                    "ALREADY_RELEASED",
                    "MONEY_ALREADY_RELEASED",
                    "SLIP_CANCELLED",
                    "PARTIAL_NOT_APPLICABLE"
                  ]
                }
              }
            }
          },
          "payroll_run_version": {
            "type": "integer",
            "description": "The run's version after the act — unchanged on a `PUBLISHED` run, where the ledger is the only thing that moved."
          }
        }
      },
      "ArrearReceipt": {
        "description": "'pay.arrear_receipts — retroactivity as an artifact (ADR 0030 §(d)).' Realized as `ARREARS` earning lines against their `arrear_period`, inside the next `REGULAR` run or a dedicated `ARREARS`/`SUPPLEMENTARY` run chained through `payroll_runs.previous_run_id` — **never a re-run of the closed period, never an edit of a published slip.**\n",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "employee_id",
              "source_type",
              "origin_period_id",
              "computed_amount",
              "status",
              "receipt_text"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "source_type": {
                "$ref": "#/components/schemas/ArrearSourceType"
              },
              "source_ref": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The regularization, amendment, revision or structure change that caused it."
              },
              "origin_period_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "computed_amount": {
                "$ref": "#/components/schemas/MoneyRef",
                "description": "The diff engine's result: the origin period recomputed under the new facts, diffed against the **immutable published payslip**. `\"0.00\"` while `computed_at` is null — read the pair, never the amount alone."
              },
              "computed_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "When the diff engine priced this receipt. **`null` means \"not priced yet\", not \"worth nothing\"** — a receipt is raised at approval time, when the cause and the corrected period are known but the money is not. Render `—` for a null `computed_at`, never `₹0`."
              },
              "currency_code": {
                "$ref": "#/components/schemas/CurrencyCodeRef"
              },
              "target_run_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "realized_earning_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The `ARREARS` earning line that actually paid it; set at `PAID`."
              },
              "status": {
                "$ref": "#/components/schemas/ArrearReceiptStatus"
              },
              "receipt_text": {
                "type": "string",
                "description": "The employee-visible line — *\"3 Jun regularization → ₹412 in your August payslip\"*. Reuses the ADR 0031 chain grammar rather than inventing a second explanation format."
              },
              "explanation_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          },
          {
            "$ref": "#/components/schemas/AuditMetaRef"
          }
        ]
      },
      "ArrearReceiptPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CursorPageRef"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ArrearReceipt"
                }
              }
            }
          }
        ]
      },
      "ExplanationInput": {
        "type": "object",
        "description": "One `{ kind, ref, value }` triple — what fed the step, which row it came from, and the frozen decimal-string figure used. `ref` is how to walk to the source; the source is never inlined, and never carries another employee's data.",
        "required": [
          "kind",
          "value"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "COMPONENT",
              "COMPENSATION",
              "STRUCTURE",
              "PAY_GROUP",
              "PAY_PERIOD",
              "SEGMENT",
              "ATTENDANCE_FINALIZATION",
              "PAYROLL_INPUT",
              "COMPLIANCE_PACK",
              "DECLARATION",
              "RATE_CARD",
              "PIECE_CATALOG",
              "SHIFT",
              "CONSTANT",
              "INTERMEDIATE"
            ],
            "description": "The class of upstream fact that fed the step — the `ExplanationInputKind` vocabulary `packages/pay-calc` emits. `COMPLIANCE_PACK` is a pack value (its `ref` names the section), `INTERMEDIATE` is a prior step's own output.\n"
          },
          "ref": {
            "type": [
              "string",
              "null"
            ],
            "description": "Soft reference in `ref→<schema>.<table>/<id>` form, e.g. `ref→attend.attendance_cycle_finalizations/<id>`."
          },
          "value": {
            "type": "string",
            "description": "The frozen decimal-string figure used at computation time. Never re-read."
          }
        }
      },
      "ExplanationStep": {
        "type": "object",
        "description": "One ordered causal step. `seq` mirrors the ADR 0029 §(d) order of operations — the chain IS the stack, in order.",
        "required": [
          "seq",
          "rule_code",
          "output_value"
        ],
        "properties": {
          "seq": {
            "type": "integer",
            "minimum": 1
          },
          "stack_step": {
            "type": "string",
            "enum": [
              "STRUCTURE_RESOLUTION",
              "CALENDAR_SEGMENTATION",
              "COMPONENT_EVALUATION",
              "LOSS_OF_PAY",
              "WAGE_FLOOR",
              "ADDITIVE_INPUTS",
              "STATUTORY",
              "NETTING"
            ],
            "description": "Which of the ADR 0029 §(d) order-of-operations steps this rule belongs to. `seq` orders the chain; `stack_step` says which part of the stack the reader is standing in, so a renderer can group a long chain without knowing the rule-code vocabulary.\n"
          },
          "rule_code": {
            "type": "string",
            "description": "From a **closed, versioned, append-only vocabulary** documented in db-docs/07 beside the table — which is what makes a chain queryable rather than a substring search over prose."
          },
          "rule_label": {
            "type": "object",
            "description": "Locale-keyed `{ en, ar }` (ADR 0012), following the `org.pay_components.name` convention already in the schema. **No Arabic rule-label content is delivered in this wave.**",
            "properties": {
              "en": {
                "type": "string"
              },
              "ar": {
                "type": "string"
              }
            }
          },
          "inputs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExplanationInput"
            }
          },
          "output_value": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "The step's decimal-string result. The LAST step's `output_value` equals the line's `amount` — checkable, and checked in the goldens."
          }
        }
      },
      "PayExplanation": {
        "description": "'pay.pay_explanations — the frozen causal chain for one money-bearing row (ADR 0031 §(a)).' Written by the engine in the **same transaction** as the line it explains (a chain write failure fails the payslip) and frozen with it on publish, under the same immutability trigger that guards published slips. A published explanation is as immutable as the money it explains, and for the same reason.\n",
        "allOf": [
          {
            "type": "object",
            "required": [
              "id",
              "target_type",
              "target_id",
              "chain",
              "engine_version"
            ],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "target_type": {
                "$ref": "#/components/schemas/ExplanationTargetType"
              },
              "target_id": {
                "$ref": "#/components/schemas/UuidRef",
                "description": "The explained row (soft polymorphic, resolved by `target_type`)."
              },
              "payroll_run_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The query axis that makes \"everyone hit by the wage floor this month\" a filter rather than a scan."
              },
              "payslip_id": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The slip whose lifecycle the chain inherits — it freezes with that slip on publish. `null` only for a `VARIANCE` target."
              },
              "chain": {
                "type": "array",
                "description": "The ordered causal steps. Read top to bottom it is a derivation; read bottom-up it is an explanation.",
                "items": {
                  "$ref": "#/components/schemas/ExplanationStep"
                }
              },
              "source_refs": {
                "type": "object",
                "additionalProperties": true,
                "description": "Ids that make the chain auditable beyond the engine — the attendance-cycle finalization id, the leave application id, the compensation revision id, and the **compliance-pack version plus the section** the statutory step read. With `engine_version`, this is what makes a two-year-old payslip reproducible.\n"
              },
              "engine_version": {
                "type": "string",
                "description": "The `pay-calc` version that produced it. Same inputs + same pack version + same engine version ⇒ byte-identical output, forever."
              }
            }
          },
          {
            "$ref": "#/components/schemas/AppendOnlyMetaRef"
          }
        ]
      },
      "PayExplanationBundle": {
        "type": "object",
        "description": "The payslip's chains, returned whole rather than windowed: the set is bounded by the slip's own line count, and the question (\"why is this slip this number\") is about the whole derivation rather than about any one row.\n",
        "required": [
          "payslip_id",
          "explanations"
        ],
        "properties": {
          "payslip_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "engine_version": {
            "type": [
              "string",
              "null"
            ]
          },
          "compliance_pack_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Quoted from `source_refs` onto the envelope so a reader can see, at a glance, which jurisdiction release the numbers were computed under. Packs still carrying `PLACEHOLDER_PENDING_COMPLIANCE_REVIEW` are regression fixtures, not statutory authority."
          },
          "explanations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayExplanation"
            }
          }
        }
      },
      "FnfExplanationBundle": {
        "type": "object",
        "description": "The settlement's chains (issue #194). Shaped like `PayExplanationBundle` so one client mapper serves both doors, with two deliberate differences: the key is `settlement_id`, and `payslip_id` is always `null` — an F&F settlement has no payslip, which is exactly why the payslip-keyed reads could never serve this chain. In practice the array holds **one** `FNF_LINE` row: `pay.pay_explanations` is unique on `(tenant_id, target_type, target_id)` and an F&F line has no row of its own to point at (the nine figures are columns), so the settlement is the target and the single chain carries every line's derivation in stack order.\n",
        "required": [
          "settlement_id",
          "payslip_id",
          "explanations"
        ],
        "properties": {
          "settlement_id": {
            "$ref": "#/components/schemas/UuidRef"
          },
          "payslip_id": {
            "type": "null",
            "description": "Always null. Stated rather than omitted: the absence is the reason this operation exists."
          },
          "engine_version": {
            "type": [
              "string",
              "null"
            ]
          },
          "compliance_pack_version": {
            "type": [
              "string",
              "null"
            ]
          },
          "explanations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayExplanation"
            }
          }
        }
      },
      "TaxWhatIfDeclarationItem": {
        "type": "object",
        "description": "One line of the LIVE, UNSAVED declaration editor. `amount` is what the employee has typed right now — it is fed to the engine as both the eligible and the verified figure and is never persisted.\n",
        "required": [
          "section",
          "amount"
        ],
        "properties": {
          "section": {
            "type": "string",
            "maxLength": 64,
            "pattern": "^[A-Z0-9_]+$",
            "description": "The `tax.declaration_items.section` vocabulary (`SEC_80C` · `SEC_80D` · `SEC_80CCD_1B` · `HRA` · `LTA` · `SEC_24B` · `SEC_80E` · `SEC_80G` · `SEC_80TTA` · `CHAPTER_VIA_OTHER`). Deliberately typed as a string rather than the `DeclarationItemSection` enum: the set a regime HONOURS is pack data (`incomeTax.regimes.<R>.permittedDeclarationSections`), not code, so a section the pack does not permit under a regime contributes nothing to that column rather than failing the request. That is precisely how a typed `SEC_80C` moves `OLD` and leaves `NEW` alone.\n"
          },
          "amount": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Non-negative decimal string, at most two decimal places. Never a float."
          }
        }
      },
      "AdminTaxWhatIfRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TaxWhatIfRequest"
          },
          {
            "type": "object",
            "required": [
              "employee_id"
            ],
            "properties": {
              "employee_id": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/UuidRef"
                  }
                ],
                "description": "The employee under Finance review; never inferred from the Finance caller."
              }
            }
          }
        ]
      },
      "AdminTaxWhatIfResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TaxWhatIfResult"
          },
          {
            "type": "object",
            "required": [
              "employee_id",
              "fiscal_year",
              "projection_basis",
              "remaining_payroll_months"
            ],
            "properties": {
              "employee_id": {
                "$ref": "#/components/schemas/UuidRef"
              },
              "fiscal_year": {
                "type": "integer",
                "minimum": 2000,
                "maximum": 2100
              },
              "projection_basis": {
                "type": "string",
                "enum": [
                  "ANNUALISED_CURRENT_STRUCTURE"
                ]
              },
              "remaining_payroll_months": {
                "type": "integer",
                "minimum": 1,
                "maximum": 12
              }
            }
          }
        ]
      },
      "TaxWhatIfRequest": {
        "type": "object",
        "description": "The computation contract. The employee is resolved from the SESSION and is never a body field — there is no employee parameter on this route and none can be added without changing the RLS scope.\n",
        "required": [
          "fiscal_year",
          "regime",
          "declaration_items",
          "projection_basis"
        ],
        "properties": {
          "fiscal_year": {
            "type": "integer",
            "minimum": 2000,
            "maximum": 2100,
            "description": "The India fiscal-year start year (FY 2026-27 is `2026`). The reference month is the current month clamped into that year's window, so the pack read is the one in force for the year being asked about."
          },
          "regime": {
            "allOf": [
              {
                "$ref": "#/components/schemas/TaxRegime"
              }
            ],
            "description": "The caller's DECLARED regime — the comparison's anchor. It does not filter: the response always carries both columns, and two requests differing only here are byte-identical."
          },
          "declaration_items": {
            "type": "array",
            "maxItems": 100,
            "description": "The live editor state, in full. An empty array is a valid question (\"what if I declare nothing?\").",
            "items": {
              "$ref": "#/components/schemas/TaxWhatIfDeclarationItem"
            }
          },
          "projection_basis": {
            "type": "string",
            "enum": [
              "ANNUALISED_CURRENT_STRUCTURE"
            ],
            "description": "Stated rather than assumed, so a future second basis cannot silently change what old numbers meant. Any other value is a 422."
          }
        }
      },
      "TaxWhatIfColumn": {
        "type": "object",
        "description": "One regime's column. **Every figure is a decimal string, rendered as-is** — the client formats, it never re-computes. `taxable_income` and `total_tax` are ANNUAL (projected); `monthly_tds` and `take_home_monthly` are per month.\n",
        "required": [
          "taxable_income",
          "total_tax",
          "monthly_tds",
          "take_home_monthly",
          "chain",
          "engine_version",
          "pack_version"
        ],
        "properties": {
          "taxable_income": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Projected annual taxable income after the standard deduction and whatever declarations this regime permits."
          },
          "total_tax": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Projected annual liability — slab tax, less rebate, plus surcharge and cess."
          },
          "monthly_tds": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "The annual liability spread over twelve months. `ANNUALISED_CURRENT_STRUCTURE` folds in no year-to-date withholding, so this is a steady-state figure, not a catch-up one."
          },
          "take_home_monthly": {
            "$ref": "#/components/schemas/MoneyRef",
            "description": "Net pay for one full, unprorated month under the current structure — gross less EPF/ESI/PT/LWF and this column's TDS."
          },
          "chain": {
            "type": "array",
            "description": "The ADR 0031 causal chain for **this column''s TDS line**, from the engine''s own explain output — `TDS_PROJECTION → TDS_SLAB_TAX → TDS_REBATE → TDS_SURCHARGE → TDS_CESS → TDS_WITHHELD`. The final step''s `output_value` therefore equals `monthly_tds`, which is what makes the chain checkable (`chainAssertsAmount`). **Empty when the column produces no TDS line at all** (zero liability): an empty chain answers \"there is nothing to explain\", which is different from — and honest about — a chain that failed to build.\n",
            "items": {
              "$ref": "#/components/schemas/ExplanationStep"
            }
          },
          "engine_version": {
            "type": "string",
            "description": "The `pay-calc` version that produced the column."
          },
          "pack_version": {
            "type": "string",
            "description": "The compliance-pack version. **Identical on both columns**, by construction and by server-side assertion."
          }
        }
      },
      "TaxWhatIfResult": {
        "type": "object",
        "description": "The pair, from one call. Never two calls — design-ess/04 §5.4 names two-calls \"the single most likely way this feature would quietly become wrong\".\n",
        "required": [
          "old",
          "new"
        ],
        "properties": {
          "old": {
            "$ref": "#/components/schemas/TaxWhatIfColumn"
          },
          "new": {
            "$ref": "#/components/schemas/TaxWhatIfColumn"
          }
        }
      },
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem detail (application/problem+json). The platform-wide error envelope (03 §1).",
        "required": [
          "type",
          "title",
          "status"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "default": "about:blank",
            "description": "Problem-type URI."
          },
          "title": {
            "type": "string",
            "description": "Short, human-readable summary (stable per type)."
          },
          "status": {
            "type": "integer",
            "description": "HTTP status code, duplicated for convenience."
          },
          "detail": {
            "type": "string",
            "description": "Human-readable explanation specific to this occurrence."
          },
          "instance": {
            "type": "string",
            "description": "URI reference for this specific occurrence."
          },
          "code": {
            "$ref": "#/components/schemas/ErrorCode"
          },
          "correlation_id": {
            "$ref": "#/components/schemas/Uuid"
          }
        }
      },
      "Uuid": {
        "type": "string",
        "format": "uuid",
        "description": "UUIDv7 surrogate primary key (db-docs/00 §3). Never the business identifier."
      },
      "DateOnly": {
        "type": "string",
        "format": "date",
        "description": "Calendar-only value (pay-period date, leave date, due date)."
      },
      "Timestamp": {
        "type": "string",
        "format": "date-time",
        "description": "timestamptz, serialized UTC ISO-8601. Presentation timezone is a client concern."
      },
      "DecimalHours": {
        "type": "string",
        "pattern": "^-?\\d+(\\.\\d{1,2})?$",
        "description": "numeric(9,2) decimal hours/days as a string (OT hours, leave days). Never a float."
      },
      "Rate": {
        "type": "string",
        "pattern": "^-?\\d+(\\.\\d{1,6})?$",
        "description": "numeric(9,6) fraction as a string, e.g. \"0.120000\" for the 12% EPF rate. Never a float; percentages are stored as fractions."
      },
      "Money": {
        "type": "object",
        "description": "Exact decimal money (db-docs/00 §6). `amount` is a STRING so float never enters the wire.",
        "required": [
          "amount",
          "currency_code"
        ],
        "additionalProperties": false,
        "properties": {
          "amount": {
            "type": "string",
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "description": "numeric(18,2) as a string, e.g. \"45000.00\"."
          },
          "currency_code": {
            "$ref": "#/components/schemas/CurrencyCode"
          }
        }
      },
      "BusinessNo": {
        "type": "string",
        "description": "Tenant-unique, prefixed human reference (`employee_no`, `requisition_no`, `offer_no`, `payslip_no`, `claim_no`, `ticket_no`, `asset_no`, `case_no`). Read-model field; never a path key.\n"
      },
      "CurrencyCode": {
        "type": "string",
        "enum": [
          "INR",
          "SAR"
        ],
        "description": "ISO-4217. A legal entity operates in a single currency (db-docs/00 §6)."
      },
      "AuditMeta": {
        "type": "object",
        "description": "Standard mutable-entity columns (db-docs/00 §5). Read-only; present on every mutable read-model.",
        "readOnly": true,
        "properties": {
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "created_by": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ],
            "description": "null = system/jobs"
          },
          "updated_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "updated_by": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "deleted_at": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Timestamp"
              },
              {
                "type": "null"
              }
            ],
            "description": "soft-delete marker; live rows are null. Deleted rows are excluded by default scope."
          },
          "version": {
            "type": "integer",
            "description": "Optimistic-lock counter (where present); surfaces as the ETag."
          }
        }
      },
      "AppendOnlyMeta": {
        "type": "object",
        "description": "Standard append-only/immutable columns (db-docs/00 §5/§8). No update/version/delete; corrections are new compensating rows.",
        "readOnly": true,
        "properties": {
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "created_by": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "CursorPage": {
        "type": "object",
        "description": "Generic cursor-pagination envelope. List operations compose it via allOf to type `data`, e.g. `allOf: [ {$ref CursorPage}, { properties: { data: { items: {$ref Employee} } } } ]`.\n",
        "required": [
          "data",
          "page"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {}
          },
          "page": {
            "type": "object",
            "required": [
              "has_more"
            ],
            "properties": {
              "next_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "prev_cursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "has_more": {
                "type": "boolean"
              },
              "total_est": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Optional, capped, APPROXIMATE row estimate for grid \"X of Z\" display only — never an exact COUNT(*) on large tables (attend.attendance_records, xc.notifications, audit.*).\n"
              }
            }
          }
        }
      },
      "FileDownload": {
        "type": "object",
        "description": "Authorized file handle (db-docs/00 §14, xc.files). Bytes never transit the API — the backend mints a time-limited presigned URL after authorization. Clients never see storage keys or hold storage credentials; the presigned URL is never persisted.\n",
        "required": [
          "file_id",
          "file_name",
          "url",
          "expires_at"
        ],
        "properties": {
          "file_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "file_name": {
            "type": "string"
          },
          "mime_type": {
            "type": "string"
          },
          "size_bytes": {
            "type": "integer"
          },
          "content_hash": {
            "type": [
              "string",
              "null"
            ],
            "description": "SHA-256",
            "present where tamper-evidence matters (payslips": null,
            "letters": null,
            "e-sign artifacts).": null
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Time-limited presigned URL."
          },
          "expires_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "ConfigVersionStamp": {
        "type": "object",
        "readOnly": true,
        "description": "Canonical v1 immutable-artifact envelope (db-docs/00 section 8). Version maps contain only config rows/keys actually read while resolving the artifact; empty means none were consumed.\n",
        "required": [
          "schema_version",
          "pay_structure_version",
          "compliance_pack_version",
          "statutory_config_versions",
          "tenant_config_versions"
        ],
        "properties": {
          "schema_version": {
            "type": "integer",
            "enum": [
              1
            ]
          },
          "pay_structure_version": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1
          },
          "compliance_pack_version": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1
          },
          "statutory_config_versions": {
            "type": "object",
            "additionalProperties": {
              "type": "integer",
              "minimum": 0
            }
          },
          "tenant_config_versions": {
            "type": "object",
            "additionalProperties": {
              "type": "integer",
              "minimum": 0
            }
          }
        }
      },
      "LocalizedText": {
        "type": "object",
        "description": "Locale-keyed content map (db-docs/00 §9) for localized/white-label text (designation titles, announcement bodies, template names). Keys are the legal entity's active locale set.\n",
        "properties": {
          "en": {
            "type": "string"
          },
          "ar": {
            "type": "string"
          }
        },
        "additionalProperties": {
          "type": "string"
        }
      },
      "ValidationProblem": {
        "description": "422 field-level validation failure; extends Problem with a per-field error array. `detail` is ALWAYS present on a 422 (#1251) and is the human summary of `errors[]`: one offending field renders as `\"<field>: <its message>\"` (`withholding_amount: is required for an India entity`), several as `\"N fields were refused: a, b, c.\"`, capped at five names. It is display copy derived from members already in the same body — clients keep branching on `code` and mapping `errors[].pointer` back to a control, never parsing this sentence.\n",
        "allOf": [
          {
            "$ref": "#/components/schemas/Problem"
          },
          {
            "type": "object",
            "required": [
              "detail",
              "errors"
            ],
            "properties": {
              "detail": {
                "type": "string",
                "description": "Human summary of `errors[]`, always populated on a 422 so a client never has to fall back to generic copy for the one status that names a fixable field.\n",
                "example": "withholding_amount: is required for an India entity"
              },
              "errors": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "pointer",
                    "rule"
                  ],
                  "properties": {
                    "pointer": {
                      "type": "string",
                      "description": "JSON Pointer to the offending field, e.g. /claim_amount"
                    },
                    "rule": {
                      "type": "string",
                      "enum": [
                        "required",
                        "format",
                        "length",
                        "range",
                        "cross-field",
                        "async-server",
                        "consent-gated",
                        "uniqueness-business",
                        "not_found"
                      ],
                      "description": "FSD validation taxonomy rule (fsd-docs/00 §8.2). `not_found` is the server-side-lookup arm: a body field that REFERENCES another resource (e.g. `project_id` on a work entry) and did not resolve for this caller. It is reported here, under the field's pointer, and NOT as a 404 — the request addresses its own resource, so the failure belongs on the form field the client can actually fix (#805).\n"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "ErrorCode": {
        "type": "string",
        "description": "Machine-stable error code (paired with the HTTP status; drives client handling, not display copy).",
        "enum": [
          "VALIDATION_FAILED",
          "IDEMPOTENCY_KEY_REUSE",
          "VERSION_CONFLICT",
          "PRECONDITION_REQUIRED",
          "MAKER_EQUALS_CHECKER",
          "STEP_UP_REQUIRED",
          "CONSENT_REQUIRED",
          "TOKEN_DENIED",
          "SCOPE_DENIED",
          "OWNERSHIP_DENIED",
          "STATE_TRANSITION_INVALID",
          "FACE_MISMATCH",
          "FACE_VERIFICATION_REQUIRED",
          "WITHHOLDING_REVIEW_REQUIRED",
          "FEATURE_NOT_IN_PLAN",
          "PLAN_LIMIT_EXCEEDED",
          "TENANT_PAST_DUE",
          "TENANT_SUSPENDED",
          "TENANT_CANCELLED",
          "RATE_LIMITED",
          "NOT_FOUND"
        ]
      }
    },
    "parameters": {
      "PathId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "UUIDv7 surrogate key of the target resource. Business numbers (`employee_no`, `claim_no`, …) are read-model fields, never path keys.",
        "schema": {
          "$ref": "#/components/schemas/Uuid"
        }
      },
      "PageSize": {
        "name": "page[size]",
        "in": "query",
        "required": false,
        "description": "Max items per page. Cursor pagination only (03 §2); offset pagination is rejected (ADR 0015).",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 200,
          "default": 50
        }
      },
      "PageAfter": {
        "name": "page[after]",
        "in": "query",
        "required": false,
        "description": "Opaque forward keyset cursor (from a prior page's `page.next_cursor`).",
        "schema": {
          "type": "string"
        }
      },
      "PageBefore": {
        "name": "page[before]",
        "in": "query",
        "required": false,
        "description": "Opaque backward keyset cursor (from a prior page's `page.prev_cursor`).",
        "schema": {
          "type": "string"
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "Client-generated unique key. REQUIRED on every mutation (this round tightens ADR 0015's \"platform + retryable mutations\" floor to ALL mutations for uniformity — offline punch/leave sync depends on it). Scoped (tenant, principal, route, key); a replay within the ~24h window returns the stored response with `Idempotency-Replayed: true`; the same key with a different body → 409 IDEMPOTENCY_KEY_REUSE (04 §1).\n",
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 255
        }
      },
      "IfMatch": {
        "name": "If-Match",
        "in": "header",
        "required": true,
        "description": "Optimistic-concurrency precondition for mutating a VERSIONED mutable entity (db-docs/00 §5 applies `version` where concurrent edits are likely). Value is the entity's current ETag (the row `version`). Absent → 428; stale → 412 (04 §2). N/A for append-only entities and for unversioned low-contention entities (their update ops simply omit this parameter).\n",
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing, expired, or invalid session token (no authenticated principal).",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Authenticated but denied — permission token not granted, out of scope (self/team/branch), not the owner, tenant suspended, or an MC-2 operation without a fresh step-up challenge. `code` ∈ TOKEN_DENIED | SCOPE_DENIED | OWNERSHIP_DENIED | MAKER_EQUALS_CHECKER | STEP_UP_REQUIRED | CONSENT_REQUIRED | TENANT_SUSPENDED. A plan feature-flag being off is 402 FEATURE_NOT_IN_PLAN, not 403 (see PaymentRequired).\n",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "PaymentRequired": {
        "description": "Plan entitlement refused (ADR 0009 entitlement order). `code` ∈ PLAN_LIMIT_EXCEEDED | FEATURE_NOT_IN_PLAN. For PLAN_LIMIT_EXCEEDED, `detail` names the resource, the current count and the cap; GroundIT publishes four enforced numeric limits — `maxEmployees`, `maxUsers`, `maxLegalEntities`, `maxWorkLocations` (README \"Plan limits and feature flags\"). FEATURE_NOT_IN_PLAN is the plan feature-flag gate (the One portal's `feature_locked` → 402). Both resolve via the One portal plan builder, not in-product.\n",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource does not exist OR is masked by RLS (tenant/self/team/branch scope) — the API does not distinguish, so existence is never confirmed across a scope boundary (02 §4 disclosure posture).\n",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Conflict": {
        "description": "Idempotency-key reuse with a different body, an invalid state transition, or a uniqueness/business-rule violation (fsd 00 §8.2). For database-backed uniqueness rules, detail names the exact violated rule; unmapped constraints are not collapsed into a generic 409.\n",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "UnprocessableEntity": {
        "description": "Field-level validation failed. The body carries both `errors[]` (per-field, pointer-addressed) and a `detail` summarising them — never an empty `detail` (#1251).\n",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ValidationProblem"
            },
            "examples": {
              "singleField": {
                "summary": "One refused field — `detail` names it",
                "value": {
                  "type": "about:blank",
                  "title": "Unprocessable Entity",
                  "status": 422,
                  "code": "VALIDATION_FAILED",
                  "detail": "withholding_amount: is required for an India entity",
                  "errors": [
                    {
                      "pointer": "/withholding_amount",
                      "rule": "required",
                      "message": "is required for an India entity"
                    }
                  ]
                }
              },
              "severalFields": {
                "summary": "Several refused fields — `detail` counts and names them",
                "value": {
                  "type": "about:blank",
                  "title": "Unprocessable Entity",
                  "status": 422,
                  "code": "VALIDATION_FAILED",
                  "detail": "2 fields were refused: effective_from, cap_amount.amount.",
                  "errors": [
                    {
                      "pointer": "/effective_from",
                      "rule": "cross-field",
                      "message": "Overlaps an existing version."
                    },
                    {
                      "pointer": "/cap_amount/amount",
                      "rule": "range",
                      "message": "Must be a non-negative decimal string."
                    }
                  ]
                }
              }
            }
          }
        }
      },
      "Locked": {
        "description": "Tenant subscription `past_due` (ADR 0009): WRITES are blocked (423), reads still succeed. `code` = TENANT_PAST_DUE. Mutations return this; list/get operations do not.\n",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Per-principal/route rate limit exceeded.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "PreconditionRequired": {
        "description": "If-Match header absent on a mutation of a versioned mutable entity (428).",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "PreconditionFailed": {
        "description": "If-Match / ETag mismatch — the row changed since it was read (412, VERSION_CONFLICT).",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      }
    },
    "headers": {
      "ETag": {
        "description": "Strong validator of the row `version` (e.g. `\"v7\"`). Use as `If-Match` on the next mutation.",
        "schema": {
          "type": "string"
        }
      },
      "Location": {
        "description": "URI of the created/affected resource.",
        "schema": {
          "type": "string",
          "format": "uri-reference"
        }
      },
      "IdempotencyReplayed": {
        "description": "`true` when a stored idempotent response was replayed rather than freshly computed.",
        "schema": {
          "type": "boolean"
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying (on 429 / 503).",
        "schema": {
          "type": "integer"
        }
      }
    }
  }
}