{
  "openapi": "3.1.0",
  "info": {
    "title": "GroundIT — Payroll",
    "version": "0.2.0",
    "license": {
      "name": "Proprietary — GroundIT/Sysmedac internal"
    },
    "description": "Simple monthly payroll (`payroll`) — tenant settings, named pay heads, effective-dated employee pay, a four-state calendar month, payslips, bank advice, payments and advances. Pay basis is MONTHLY (salary prorated by paid days) or DAILY (day rate × days worked off the muster/day ledger, no LOP — an unmarked day is unpaid); no piece rate. Statutory heads are seed rows, not code constants. India starter set is created on first GET /payroll/settings (#1780).\n"
  },
  "servers": [
    {
      "url": "/api/v1"
    }
  ],
  "security": [
    {
      "bearerJWT": []
    }
  ],
  "tags": [
    {
      "name": "payroll",
      "description": "Simple monthly payroll — epic #1774."
    },
    {
      "name": "settings"
    },
    {
      "name": "pay-head"
    },
    {
      "name": "employee-pay"
    },
    {
      "name": "month"
    },
    {
      "name": "payslip"
    },
    {
      "name": "payment"
    },
    {
      "name": "advance"
    },
    {
      "name": "pay-team",
      "description": "Pay teams — wage payroll by contractor team (#1877)."
    }
  ],
  "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"
      },
      "not_found": {
        "$ref": "#/components/responses/NotFound"
      },
      "conflict": {
        "$ref": "#/components/responses/Conflict"
      },
      "unprocessable": {
        "$ref": "#/components/responses/UnprocessableEntity"
      },
      "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"
      },
      "idempotency_replayed": {
        "$ref": "#/components/headers/IdempotencyReplayed"
      }
    }
  },
  "paths": {
    "/payroll/settings": {
      "get": {
        "operationId": "payroll.settings.get",
        "summary": "Get tenant payroll settings (seeds India starter heads on first call)",
        "tags": [
          "payroll",
          "settings"
        ],
        "x-token": "payroll.settings.get",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.settings",
          "payroll.pay_heads"
        ],
        "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,
        "description": "Returns the tenant's one settings row. On a tenant with no `payroll` rows this call creates the defaults (`days_basis=CALENDAR`, `approval_policy.mode=SINGLE`, all four payment methods) and inserts the nine India starter heads. A second call creates nothing more.\n",
        "responses": {
          "200": {
            "description": "Settings plus the current pay-head set (including the starter seed).",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollSettings"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "put": {
        "operationId": "payroll.settings.update",
        "summary": "Update tenant payroll settings",
        "tags": [
          "payroll",
          "settings"
        ],
        "x-token": "payroll.settings.update",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.settings"
        ],
        "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/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayrollSettingsWrite"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated settings.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollSettings"
                }
              }
            }
          },
          "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"
          }
        }
      }
    },
    "/payroll/pay-heads": {
      "get": {
        "operationId": "payroll.pay_head.list",
        "summary": "List pay heads (including inactive)",
        "tags": [
          "payroll",
          "pay-head"
        ],
        "x-token": "payroll.pay_head.list",
        "x-realizes-features": [
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.pay_heads"
        ],
        "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"
          }
        ],
        "responses": {
          "200": {
            "description": "Page of pay heads, inactive included, ordered by display_order then code.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/CursorPage"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/PayHead"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "operationId": "payroll.pay_head.create",
        "summary": "Create a pay head",
        "tags": [
          "payroll",
          "pay-head"
        ],
        "x-token": "payroll.pay_head.create",
        "x-realizes-features": [
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.pay_heads"
        ],
        "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/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayHeadWrite"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created pay head.",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayHead"
                }
              }
            }
          },
          "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"
          }
        }
      }
    },
    "/payroll/pay-heads/{id}": {
      "patch": {
        "operationId": "payroll.pay_head.update",
        "summary": "Update a pay head",
        "tags": [
          "payroll",
          "pay-head"
        ],
        "x-token": "payroll.pay_head.update",
        "x-realizes-features": [
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.pay_heads",
          "payroll.payslip_lines",
          "payroll.months"
        ],
        "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,
        "description": "A head referenced by a payslip of an APPROVED month may be deactivated (`active=false`) and is never deleted and never re-rated in place (`percent_rate`, `calc`, `wage_cap_amount`).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayHeadPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated pay head.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayHead"
                }
              }
            }
          },
          "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"
          }
        }
      }
    },
    "/employees/{id}/payroll-pay": {
      "get": {
        "operationId": "payroll.employee_pay.get",
        "summary": "Get an employee's open payroll-pay row and history",
        "tags": [
          "payroll",
          "employee-pay"
        ],
        "x-token": "payroll.employee_pay.get",
        "x-realizes-features": [
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.employee_pay"
        ],
        "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": "Open row plus the effective-dated chain, newest first, each with `pay_basis` and `daily_rate_amount`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeePayHistory"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "put": {
        "operationId": "payroll.employee_pay.upsert",
        "summary": "Upsert an employee's monthly payroll-pay (closes the previous open row)",
        "tags": [
          "payroll",
          "employee-pay"
        ],
        "x-token": "payroll.employee_pay.upsert",
        "x-realizes-features": [
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.employee_pay"
        ],
        "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,
        "description": "Closes the previous open row at `effective_from − 1 day` and inserts the new one in the same transaction. Body carries pay_basis (MONTHLY default | DAILY), monthly_basic_amount, daily_rate_amount (required and > 0 for DAILY, refused for MONTHLY), ot_hour_rate_amount, head_amounts, tds_monthly_amount, payment_method. A DAILY row may omit monthly_basic_amount (stored 0.00). The legacy `basis` / `daily_rate` keys are refused.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmployeePayWrite"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The new open row.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeePay"
                }
              }
            }
          },
          "201": {
            "description": "First open row for this employee.",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmployeePay"
                }
              }
            }
          },
          "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"
          }
        }
      }
    },
    "/payroll/months": {
      "get": {
        "operationId": "payroll.month.list",
        "summary": "List payroll months",
        "tags": [
          "payroll",
          "month"
        ],
        "x-token": "payroll.month.list",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.months"
        ],
        "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": "year",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1900,
              "maximum": 9999
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Months for the requested year, newest first. SALARY access is logged.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "year",
                    "data"
                  ],
                  "properties": {
                    "year": {
                      "type": "integer"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PayrollMonth"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll/months/{month}": {
      "get": {
        "operationId": "payroll.month.get",
        "summary": "Get one payroll month",
        "tags": [
          "payroll",
          "month"
        ],
        "x-token": "payroll.month.get",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.months",
          "payroll.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": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/YearMonth"
            }
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "description": "Month with payslips, lines, current gates, advisory chips and carried balances. SALARY access is logged once per read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollMonth"
                }
              }
            }
          },
          "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/months/{month}/prepare": {
      "post": {
        "operationId": "payroll.month.prepare",
        "summary": "Prepare (compute) a payroll month",
        "tags": [
          "payroll",
          "month"
        ],
        "x-token": "payroll.month.prepare",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.months",
          "payroll.payslips",
          "payroll.payslip_lines"
        ],
        "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": "month",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/YearMonth"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "description": "Synchronously computed DRAFT month. Existing overrides and one-off lines are preserved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollMonth"
                }
              }
            }
          },
          "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"
          }
        }
      }
    },
    "/payroll/months/{month}/submit": {
      "post": {
        "operationId": "payroll.month.submit",
        "summary": "Submit a payroll month for approval",
        "description": "Submits a DUAL or CHAIN month: snapshots `approval_policy` onto the month, raises one PENDING `PAYROLL_MONTH` envelope (`source_type` `payroll.months`) with a named `current_approver_id` and a 48-hour SLA, and moves the month to SUBMITTED. SINGLE months cannot be submitted — approve them directly from DRAFT.\n",
        "tags": [
          "payroll",
          "month"
        ],
        "x-token": "payroll.month.submit",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.months"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "xc.approval_inbox.project",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/YearMonth"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "description": "SUBMITTED month with one PENDING PAYROLL_MONTH envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollMonth"
                }
              }
            }
          },
          "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"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll/months/{month}/approve": {
      "post": {
        "operationId": "payroll.month.approve",
        "summary": "Approve a payroll month",
        "description": "Approves a month. SINGLE is one click from DRAFT. DUAL/CHAIN append a decision on the snapshotted policy: the last step flips the month to APPROVED and closes the envelope; an earlier CHAIN step raises the next envelope. The same four refusal lines and MC-1 apply on the inbox path. Override swaps token/scope only and never bypasses four-eyes.\n",
        "tags": [
          "payroll",
          "month"
        ],
        "x-token": "payroll.month.approve",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.months"
        ],
        "x-idempotent": true,
        "x-market": "both",
        "x-sync-async": "sync",
        "x-emits-event": "payroll.month.approved",
        "x-rls-scope": "tenant",
        "x-append-only": false,
        "x-entitlement": null,
        "x-provisional": null,
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/YearMonth"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "description": "Approved SINGLE-policy month. MC-1; own salary requires another approver unless explicitly allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollMonth"
                }
              }
            }
          },
          "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"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "501": {
            "description": "DUAL/CHAIN approval routing is not installed yet (#1782)."
          }
        }
      }
    },
    "/payroll/months/{month}/reject": {
      "post": {
        "operationId": "payroll.month.reject",
        "summary": "Reject a submitted payroll month back to DRAFT",
        "description": "Rejects a SUBMITTED DUAL/CHAIN month back to DRAFT, clears in-flight decisions, and closes the open PAYROLL_MONTH envelope. The four refusal lines and MC-1 apply. Required body field `note`.\n",
        "tags": [
          "payroll",
          "month"
        ],
        "x-token": "payroll.month.reject",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.months"
        ],
        "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": "month",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/YearMonth"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "note"
                ],
                "properties": {
                  "note": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 1000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "description": "Rejected month (DRAFT) when a routing adapter is installed (#1782).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollMonth"
                }
              }
            }
          },
          "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"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "501": {
            "description": "DUAL/CHAIN approval routing is not installed yet (#1782)."
          }
        }
      }
    },
    "/payroll/months/{month}/reopen": {
      "post": {
        "operationId": "payroll.month.reopen",
        "summary": "Reopen an APPROVED month to DRAFT (no payments yet)",
        "tags": [
          "payroll",
          "month"
        ],
        "x-token": "payroll.month.reopen",
        "x-realizes-features": [
          "PAY-F01"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.months",
          "payroll.payments"
        ],
        "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": "month",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/YearMonth"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "description": "Reopened DRAFT month; refused if any payment exists. PDF references are cleared.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollMonth"
                }
              }
            }
          },
          "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"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll/months/{month}/bank-advice": {
      "post": {
        "operationId": "payroll.month.bank_advice",
        "summary": "Download bank-advice CSV for selected or ALL payable slips",
        "tags": [
          "payroll",
          "month"
        ],
        "x-token": "payroll.month.bank_advice",
        "x-realizes-features": [
          "PAY-F11"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.months",
          "payroll.payslips",
          "people.bank_accounts"
        ],
        "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": "month",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/YearMonth"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayrollPayslipSelection"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Inline text/csv from renderBankAdviceCsv. Held slips and non-BANK_TRANSFER rows are omitted. SHA-256 of the bytes is returned as X-Content-SHA256 for use as payment batch_ref. One BANK DATA_ACCESS row is written per call. Missing or non-VERIFIED primary accounts are refused with the same predicate as the BANK_MISSING gate.\n",
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Content-SHA256": {
                "schema": {
                  "type": "string",
                  "pattern": "^[a-f0-9]{64}$"
                },
                "description": "Hex SHA-256 of the CSV body."
              }
            },
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "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"
          }
        }
      }
    },
    "/payroll/months/{month}/payslips/{id}": {
      "patch": {
        "operationId": "payroll.payslip.update",
        "summary": "Override a DRAFT payslip or change an APPROVED hold",
        "tags": [
          "payroll",
          "payslip"
        ],
        "x-token": "payroll.payslip.update",
        "x-realizes-features": [
          "PAY-F03"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.payslips",
          "payroll.payslip_lines"
        ],
        "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": "month",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/YearMonth"
            }
          },
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayrollPayslipPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "description": "Updated payslip with lines and gates. Calculation edits require DRAFT; APPROVED allows hold changes only.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollPayslip"
                }
              }
            }
          },
          "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"
          }
        }
      }
    },
    "/payroll/months/{month}/payments": {
      "post": {
        "operationId": "payroll.payment.create",
        "summary": "Record append-only payments against this month's Pay step",
        "tags": [
          "payroll",
          "payment"
        ],
        "x-token": "payroll.payment.create",
        "x-realizes-features": [
          "PAY-F12"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.payments",
          "payroll.payslips",
          "payroll.months"
        ],
        "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": "month",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/YearMonth"
            }
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayrollPaymentWrite"
              }
            }
          }
        },
        "responses": {
          "201": {
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "description": "Insert-only payment rows. Omit amount for full remaining; amount less than remaining is a partial; a negative amount is a correction and requires reason. ALL skips held this-month slips and includes earlier unpaid (carried) slips oldest-first. months.paid_at is set when every non-held this-month slip has remaining 0 and no held this-month slip remains unpaid.\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PayrollPayment"
                      }
                    }
                  }
                }
              }
            }
          },
          "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"
          }
        }
      }
    },
    "/payroll/pay-teams": {
      "get": {
        "operationId": "payroll.pay_team.list",
        "summary": "List teams with their pay-team configuration",
        "tags": [
          "payroll",
          "pay-team"
        ],
        "x-token": "payroll.pay_team.list",
        "x-realizes-features": [
          "PAY-F03"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.pay_teams",
          "work.teams",
          "people.bank_accounts"
        ],
        "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,
        "description": "Pay teams (#1877). Every ACTIVE work team (and any configured pay team) with its contractor (the team lead), whether the contractor has a primary VERIFIED bank account, the live member count (the contractor excluded) and the pay-team row, if any. Configured teams first.\n",
        "responses": {
          "200": {
            "description": "Teams and the tenant pay_teams switch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayTeamList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll/pay-teams/{teamId}": {
      "put": {
        "operationId": "payroll.pay_team.upsert",
        "summary": "Make a team a pay team, or change it",
        "tags": [
          "payroll",
          "pay-team"
        ],
        "x-token": "payroll.pay_team.upsert",
        "x-realizes-features": [
          "PAY-F03"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.pay_teams"
        ],
        "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,
        "description": "CONTRACTOR teams are daily-wage workers paid default_daily_rate_amount (or their own day rate) per day worked and settled to the team lead by settlement_method (BANK_TRANSFER | CASH). STAFF teams are grouped only and have no day rate. A worker can be in at most one pay team: a membership overlap is refused 409 (constraint pay_team_single_membership), from this call or from any team-roster write.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "teamId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayTeamWrite"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated.",
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayTeam"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayTeam"
                }
              }
            }
          },
          "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"
          }
        }
      },
      "delete": {
        "operationId": "payroll.pay_team.delete",
        "summary": "Stop treating a team as a pay team (soft delete)",
        "tags": [
          "payroll",
          "pay-team"
        ],
        "x-token": "payroll.pay_team.upsert",
        "x-realizes-features": [
          "PAY-F03"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.pay_teams"
        ],
        "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": "teamId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Removed. Existing payslips keep their pay team."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll/pay-teams/{teamId}/member-rates": {
      "get": {
        "operationId": "payroll.pay_team.list_member_rates",
        "summary": "Workers of a pay team with their effective day rate",
        "tags": [
          "payroll",
          "pay-team"
        ],
        "x-token": "payroll.pay_team.list",
        "x-realizes-features": [
          "PAY-F03"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.pay_teams",
          "payroll.employee_pay",
          "work.team_members"
        ],
        "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,
        "description": "One row per live member (the contractor excluded): the worker's own day rate (their open DAILY employee_pay row), the effective rate and its source INDIVIDUAL | TEAM_DEFAULT | NONE.\n",
        "parameters": [
          {
            "name": "teamId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Member rates.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayTeamMemberRates"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "put": {
        "operationId": "payroll.pay_team.set_member_rates",
        "summary": "Set or clear workers’ individual day rates (batch)",
        "tags": [
          "payroll",
          "pay-team"
        ],
        "x-token": "payroll.pay_team.upsert",
        "x-realizes-features": [
          "PAY-F03"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.employee_pay",
          "payroll.pay_teams"
        ],
        "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,
        "description": "CONTRACTOR pay teams only. Each row names a member by employee_id or employee_no; a rate writes the worker's open DAILY employee_pay.daily_rate_amount (creating the row from their joining date if none), null clears it (soft-deletes the open DAILY row) so the team default applies. All-or-nothing: any bad row (not a member, duplicated, a MONTHLY pay setup) is a 422 with a pointer per row.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "teamId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayTeamMemberRatesWrite"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rates after the change.",
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayTeamMemberRates"
                }
              }
            }
          },
          "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"
          }
        }
      }
    },
    "/payroll/months/{month}/not-in-payroll": {
      "get": {
        "operationId": "payroll.month.not_in_payroll",
        "summary": "Who pay-by-teams left out of this month",
        "tags": [
          "payroll",
          "month"
        ],
        "x-token": "payroll.month.get",
        "x-realizes-features": [
          "PAY-F03"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.payslips",
          "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,
        "description": "Pay by teams (#1877) only pays pay-team members and people with a pay setup. This lists the other active-in-month employees (no slip this month). The month view carries the count as not_in_payroll_count.\n",
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/YearMonth"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Employees without a slip this month.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollNotInPayroll"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll/months/{month}/team-settlements": {
      "post": {
        "operationId": "payroll.payment.team_settle",
        "summary": "Settle a contractor team to its contractor",
        "tags": [
          "payroll",
          "payment"
        ],
        "x-token": "payroll.payment.team_settle",
        "x-realizes-features": [
          "PAY-F03"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.team_settlements",
          "payroll.payments",
          "payroll.payslips"
        ],
        "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,
        "description": "APPROVED/PAID month. Pays every unpaid, un-held TEAM slip of one pay team to the team lead in one append-only payroll.team_settlements row plus one payroll.payments row per slip (team_settlement_id, payee_employee_id = the contractor). BANK_TRANSFER requires the contractor's primary VERIFIED bank account and freezes a masked bank_snapshot. 409 when nothing is left to settle or the contractor changed since preparing. TEAM slips are refused by POST payments when named explicitly and skipped by its ALL selection.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "month",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/YearMonth"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TeamSettlementWrite"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The settlement.",
            "headers": {
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamSettlement"
                }
              }
            }
          },
          "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"
          }
        }
      }
    },
    "/payroll/months/{month}/team-statement": {
      "get": {
        "operationId": "payroll.month.team_statement",
        "summary": "Contractor statement CSV for one pay team",
        "tags": [
          "payroll",
          "month"
        ],
        "x-token": "payroll.month.team_statement",
        "x-realizes-features": [
          "PAY-F03"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.payslips",
          "payroll.pay_teams"
        ],
        "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,
        "description": "Header rows (team, contractor, month), then worker, employee_no, days_worked, dates (half days marked), daily_rate, amount per slip, and a total row. One SALARY DATA_ACCESS row.\n",
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/YearMonth"
            }
          },
          {
            "name": "pay_team_id",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "text/csv attachment.",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "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/advances": {
      "get": {
        "operationId": "payroll.advance.list",
        "summary": "List salary advances",
        "tags": [
          "payroll",
          "advance"
        ],
        "x-token": "payroll.advance.list",
        "x-realizes-features": [
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.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,
        "responses": {
          "200": {
            "description": "Salary advances for the tenant.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PayrollAdvance"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "operationId": "payroll.advance.create",
        "summary": "Create a salary advance",
        "tags": [
          "payroll",
          "advance"
        ],
        "x-token": "payroll.advance.create",
        "x-realizes-features": [
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.advances"
        ],
        "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/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayrollAdvanceWrite"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created OPEN salary advance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollAdvance"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/payroll/advances/{id}/events": {
      "post": {
        "operationId": "payroll.advance.event",
        "summary": "Record an advance event (recovery, skip, repayment, write-off)",
        "tags": [
          "payroll",
          "advance"
        ],
        "x-token": "payroll.advance.event",
        "x-realizes-features": [
          "PAY-F04"
        ],
        "x-screens": [
          "PAY-S33"
        ],
        "x-touches-entities": [
          "payroll.advances",
          "payroll.advance_events"
        ],
        "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": [
          {
            "$ref": "#/components/parameters/PathId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayrollAdvanceEventWrite"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Recorded SKIP, MANUAL_REPAYMENT or WRITE_OFF event. RECOVERY is written on month approve.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayrollAdvanceEvent"
                }
              }
            }
          },
          "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"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "YearMonth": {
        "type": "string",
        "pattern": "^(19|[2-9][0-9])[0-9]{2}-(0[1-9]|1[0-2])$",
        "example": "2026-09"
      },
      "Money": {
        "type": "string",
        "pattern": "^\\d{1,16}(\\.\\d{1,2})?$",
        "description": "Decimal string `numeric(18,2)`. Never a JSON number."
      },
      "DaysBasis": {
        "type": "string",
        "enum": [
          "CALENDAR",
          "THIRTY"
        ]
      },
      "PaymentMethod": {
        "type": "string",
        "enum": [
          "BANK_TRANSFER",
          "CASH",
          "UPI",
          "CHEQUE"
        ]
      },
      "PayHeadKind": {
        "type": "string",
        "enum": [
          "EARNING",
          "DEDUCTION"
        ]
      },
      "PayHeadCalc": {
        "type": "string",
        "enum": [
          "FIXED",
          "PERCENT",
          "PER_HOUR"
        ]
      },
      "CapMode": {
        "type": "string",
        "enum": [
          "MIN",
          "ELIGIBILITY"
        ],
        "description": "MIN caps the calculation base; ELIGIBILITY makes the line zero when its base exceeds wage_cap_amount."
      },
      "PercentOf": {
        "type": "string",
        "enum": [
          "BASIC",
          "GROSS",
          "HEAD"
        ]
      },
      "RemitTo": {
        "type": "string",
        "enum": [
          "PF",
          "ESI",
          "PT",
          "TDS",
          "LWF",
          "OTHER"
        ]
      },
      "MonthStatus": {
        "type": "string",
        "enum": [
          "DRAFT",
          "SUBMITTED",
          "APPROVED",
          "PAID"
        ]
      },
      "ApprovalPolicy": {
        "type": "object",
        "required": [
          "mode",
          "allow_self",
          "approvers",
          "stages"
        ],
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "SINGLE",
              "DUAL",
              "CHAIN"
            ]
          },
          "allow_self": {
            "type": "boolean"
          },
          "approvers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Uuid"
            }
          },
          "stages": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "PayrollSettings": {
        "type": "object",
        "required": [
          "id",
          "days_basis",
          "approval_policy",
          "allowed_methods",
          "currency_code",
          "version",
          "pay_heads"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "days_basis": {
            "$ref": "#/components/schemas/DaysBasis"
          },
          "approval_policy": {
            "$ref": "#/components/schemas/ApprovalPolicy"
          },
          "allowed_methods": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentMethod"
            }
          },
          "currency_code": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "pay_teams": {
            "type": "boolean",
            "description": "Pay by teams (#1877). Default false — every tenant keeps individual payroll."
          },
          "version": {
            "type": "integer",
            "minimum": 0
          },
          "created_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "updated_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "pay_heads": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayHead"
            },
            "description": "Current heads after lazy India starter seed."
          }
        }
      },
      "PayrollSettingsWrite": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "days_basis": {
            "$ref": "#/components/schemas/DaysBasis"
          },
          "approval_policy": {
            "$ref": "#/components/schemas/ApprovalPolicy"
          },
          "allowed_methods": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentMethod"
            }
          },
          "currency_code": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "pay_teams": {
            "type": "boolean"
          }
        }
      },
      "PayHead": {
        "type": "object",
        "required": [
          "id",
          "code",
          "name",
          "kind",
          "calc",
          "cap_mode",
          "employer_side",
          "prorate",
          "display_order",
          "is_basic",
          "active",
          "version"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/PayHeadKind"
          },
          "calc": {
            "$ref": "#/components/schemas/PayHeadCalc"
          },
          "percent_of": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PercentOf"
              },
              {
                "type": "null"
              }
            ]
          },
          "percent_of_head_id": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "percent_rate": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "wage_cap_amount": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "cap_mode": {
            "$ref": "#/components/schemas/CapMode"
          },
          "employer_side": {
            "type": "boolean"
          },
          "remit_to": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/RemitTo"
              },
              {
                "type": "null"
              }
            ]
          },
          "prorate": {
            "type": "boolean"
          },
          "display_order": {
            "type": "integer"
          },
          "is_basic": {
            "type": "boolean"
          },
          "active": {
            "type": "boolean"
          },
          "version": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "PayHeadWrite": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "code",
          "name",
          "kind",
          "calc"
        ],
        "properties": {
          "code": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1
          },
          "kind": {
            "$ref": "#/components/schemas/PayHeadKind"
          },
          "calc": {
            "$ref": "#/components/schemas/PayHeadCalc"
          },
          "percent_of": {
            "$ref": "#/components/schemas/PercentOf"
          },
          "percent_of_head_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "percent_rate": {
            "type": "string"
          },
          "wage_cap_amount": {
            "$ref": "#/components/schemas/Money"
          },
          "cap_mode": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CapMode"
              }
            ],
            "default": "MIN"
          },
          "employer_side": {
            "type": "boolean"
          },
          "remit_to": {
            "$ref": "#/components/schemas/RemitTo"
          },
          "prorate": {
            "type": "boolean"
          },
          "display_order": {
            "type": "integer"
          },
          "is_basic": {
            "type": "boolean"
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "PayHeadPatch": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "kind": {
            "$ref": "#/components/schemas/PayHeadKind"
          },
          "calc": {
            "$ref": "#/components/schemas/PayHeadCalc"
          },
          "percent_of": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PercentOf"
              },
              {
                "type": "null"
              }
            ]
          },
          "percent_of_head_id": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "percent_rate": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "wage_cap_amount": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "cap_mode": {
            "$ref": "#/components/schemas/CapMode"
          },
          "employer_side": {
            "type": "boolean"
          },
          "remit_to": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/RemitTo"
              },
              {
                "type": "null"
              }
            ]
          },
          "prorate": {
            "type": "boolean"
          },
          "display_order": {
            "type": "integer"
          },
          "is_basic": {
            "type": "boolean"
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "HeadAmount": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "pay_head_id",
          "amount"
        ],
        "properties": {
          "pay_head_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          }
        }
      },
      "EmployeePay": {
        "type": "object",
        "required": [
          "id",
          "employee_id",
          "effective_from",
          "monthly_basic_amount",
          "head_amounts",
          "tds_monthly_amount",
          "payment_method",
          "currency_code",
          "version"
        ],
        "description": "Effective-dated pay. MONTHLY prorates monthly_basic_amount by paid days; DAILY pays daily_rate_amount × days worked.",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "employee_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "effective_from": {
            "$ref": "#/components/schemas/DateOnly"
          },
          "effective_to": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DateOnly"
              },
              {
                "type": "null"
              }
            ]
          },
          "pay_basis": {
            "type": "string",
            "enum": [
              "MONTHLY",
              "DAILY"
            ]
          },
          "monthly_basic_amount": {
            "$ref": "#/components/schemas/Money"
          },
          "daily_rate_amount": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "ot_hour_rate_amount": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "head_amounts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HeadAmount"
            }
          },
          "tds_monthly_amount": {
            "$ref": "#/components/schemas/Money"
          },
          "payment_method": {
            "$ref": "#/components/schemas/PaymentMethod"
          },
          "currency_code": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "version": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "EmployeePayWrite": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "effective_from"
        ],
        "description": "monthly_basic_amount is required for MONTHLY; daily_rate_amount (> 0) is required for DAILY and refused for MONTHLY. The legacy `basis` / `daily_rate` keys are refused.\n",
        "properties": {
          "effective_from": {
            "$ref": "#/components/schemas/DateOnly"
          },
          "pay_basis": {
            "type": "string",
            "enum": [
              "MONTHLY",
              "DAILY"
            ],
            "default": "MONTHLY"
          },
          "monthly_basic_amount": {
            "$ref": "#/components/schemas/Money"
          },
          "daily_rate_amount": {
            "$ref": "#/components/schemas/Money"
          },
          "ot_hour_rate_amount": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "head_amounts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HeadAmount"
            }
          },
          "tds_monthly_amount": {
            "$ref": "#/components/schemas/Money"
          },
          "payment_method": {
            "$ref": "#/components/schemas/PaymentMethod"
          }
        }
      },
      "EmployeePayHistory": {
        "type": "object",
        "required": [
          "employee_id",
          "records"
        ],
        "properties": {
          "employee_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "currency_code": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "open": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EmployeePay"
              },
              {
                "type": "null"
              }
            ]
          },
          "records": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmployeePay"
            }
          }
        }
      },
      "SignedMoney": {
        "type": "string",
        "pattern": "^-\\d{1,16}(\\.\\d{1,2})?$|^\\d{1,16}(\\.\\d{1,2})?$",
        "description": "Signed decimal amount; negative net is returned with a blocking gate."
      },
      "PayrollMonth": {
        "type": "object",
        "required": [
          "id",
          "month",
          "period_start",
          "period_end",
          "status",
          "version"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "month": {
            "$ref": "#/components/schemas/YearMonth"
          },
          "period_start": {
            "$ref": "#/components/schemas/DateOnly"
          },
          "period_end": {
            "$ref": "#/components/schemas/DateOnly"
          },
          "status": {
            "$ref": "#/components/schemas/MonthStatus"
          },
          "version": {
            "type": "integer",
            "minimum": 0
          },
          "policy_snapshot": {
            "$ref": "#/components/schemas/ApprovalPolicy"
          },
          "decisions": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "prepared_by": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "approved_by": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "submitted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "approved_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "paid_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "gross_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "deductions_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "employer_cost_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "net_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "payslip_count": {
            "type": "integer",
            "minimum": 0
          },
          "held_count": {
            "type": "integer",
            "minimum": 0
          },
          "payslips": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayrollPayslip"
            }
          },
          "teams": {
            "type": "array",
            "description": "Pay by teams only — per pay team subtotals of this month's slips.",
            "items": {
              "$ref": "#/components/schemas/PayTeamSubtotal"
            }
          },
          "not_in_payroll_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Pay by teams only — active-in-month employees with no slip."
          }
        }
      },
      "PayrollGate": {
        "type": "object",
        "required": [
          "code",
          "blocking",
          "message"
        ],
        "properties": {
          "code": {
            "type": "string",
            "enum": [
              "NO_PAY_SETUP",
              "BANK_MISSING",
              "NET_NEGATIVE"
            ]
          },
          "blocking": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string"
          }
        }
      },
      "PayrollChip": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "PayrollPayslipPatch": {
        "type": "object",
        "additionalProperties": false,
        "description": "At least one change is required. Calculation overrides require a nonempty reason and a DRAFT month. APPROVED months accept only held/hold_reason; holding requires a nonempty hold reason. Quantities and money must be decimal strings, never JSON numbers.\n",
        "properties": {
          "lop_days": {
            "type": "string",
            "pattern": "^\\d{1,5}(\\.\\d{1,2})?$"
          },
          "paid_days": {
            "type": "string",
            "pattern": "^\\d{1,5}(\\.\\d{1,2})?$"
          },
          "ot_hours": {
            "type": "string",
            "pattern": "^\\d{1,5}(\\.\\d{1,2})?$"
          },
          "tds_amount": {
            "$ref": "#/components/schemas/Money"
          },
          "net_amount": {
            "$ref": "#/components/schemas/Money"
          },
          "reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1000
          },
          "held": {
            "type": "boolean"
          },
          "hold_reason": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 1000
          },
          "one_offs": {
            "type": "array",
            "description": "Append-only signed manual adjustments. Existing one-offs remain on later edits.",
            "items": {
              "type": "object",
              "required": [
                "label",
                "amount"
              ],
              "additionalProperties": false,
              "properties": {
                "label": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "amount": {
                  "$ref": "#/components/schemas/SignedMoney"
                }
              }
            }
          }
        }
      },
      "PayrollPayslipLine": {
        "type": "object",
        "required": [
          "id",
          "line_kind",
          "code",
          "label",
          "amount"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "payslip_id": {
            "type": "string",
            "format": "uuid"
          },
          "pay_head_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "line_kind": {
            "type": "string",
            "enum": [
              "EARNING",
              "DEDUCTION",
              "EMPLOYER",
              "ADJUSTMENT",
              "ADVANCE_RECOVERY"
            ]
          },
          "code": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "remit_to": {
            "type": [
              "string",
              "null"
            ]
          },
          "calc_basis": {
            "type": [
              "string",
              "null"
            ]
          },
          "quantity": {
            "type": [
              "string",
              "null"
            ]
          },
          "rate": {
            "type": [
              "string",
              "null"
            ]
          },
          "amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "display_order": {
            "type": "integer"
          },
          "version": {
            "type": "integer"
          }
        }
      },
      "PayrollPayslip": {
        "type": "object",
        "required": [
          "id",
          "month_id",
          "employee_id",
          "kind",
          "version",
          "gates",
          "lines"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "month_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "employee_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "employee_no": {
            "type": "string"
          },
          "employee_name": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "REGULAR",
              "ARREAR"
            ]
          },
          "payslip_no": {
            "type": "string"
          },
          "currency_code": {
            "type": "string",
            "pattern": "^[A-Z]{3}$"
          },
          "total_days": {
            "type": "string"
          },
          "paid_days": {
            "type": "string"
          },
          "lop_days": {
            "type": "string"
          },
          "ot_hours": {
            "type": "string"
          },
          "attendance_source": {
            "type": "string",
            "enum": [
              "FINALIZED",
              "LIVE",
              "NONE"
            ]
          },
          "pay_basis": {
            "type": "string",
            "enum": [
              "MONTHLY",
              "DAILY"
            ],
            "description": "DAILY slips pay the day rate × paid_days (= days worked); lop_days is always 0."
          },
          "attendance_coverage": {
            "type": "object",
            "properties": {
              "expected_days": {
                "type": "integer"
              },
              "recorded_days": {
                "type": "integer"
              },
              "payable_days": {
                "type": "number"
              },
              "worked_days": {
                "type": "string",
                "description": "DAILY only — PRESENT/ON_FIELD days count 1, HALF_DAY 0.5."
              },
              "worked_dates": {
                "type": "array",
                "description": "DAILY only — ISO dates worked, ascending; a half day is suffixed `~half`.",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "overrides": {
            "type": "object"
          },
          "gross_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "deductions_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "employer_cost_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "advance_recovery_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "net_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "gates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayrollGate"
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayrollChip"
            }
          },
          "chips": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayrollChip"
            }
          },
          "held": {
            "type": "boolean"
          },
          "hold_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "payment_method": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PaymentMethod"
              },
              {
                "type": "null"
              }
            ]
          },
          "paid_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "remaining_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "payment_status": {
            "type": "string",
            "enum": [
              "UNPAID",
              "PARTIALLY_PAID",
              "PAID",
              "WITHHELD"
            ]
          },
          "calculation_input": {
            "type": [
              "object",
              "null"
            ]
          },
          "carried_balance_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "carried": {
            "type": "boolean"
          },
          "source_month": {
            "$ref": "#/components/schemas/YearMonth"
          },
          "pay_team_id": {
            "$ref": "#/components/schemas/Uuid",
            "description": "Present only on a pay-team slip (#1877)."
          },
          "settlement": {
            "type": "string",
            "enum": [
              "INDIVIDUAL",
              "TEAM"
            ],
            "description": "TEAM = wage-only slip settled to the pay team's contractor; its gates are DAILY_RATE_MISSING, CONTRACTOR_MISSING, CONTRACTOR_CHANGED, CONTRACTOR_BANK_MISSING and NET_NEGATIVE (never the worker's NO_PAY_SETUP / BANK_MISSING).\n"
          },
          "pay_team": {
            "type": [
              "object",
              "null"
            ]
          },
          "contractor": {
            "type": [
              "object",
              "null"
            ]
          },
          "rate_source": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "INDIVIDUAL",
              "TEAM_DEFAULT",
              "NONE",
              null
            ]
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayrollPayslipLine"
            }
          },
          "version": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "PayrollPayslipSelection": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "payslip_ids": {
            "description": "ALL (default) or an explicit list of payslip ids.",
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "ALL"
                ]
              },
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Uuid"
                }
              }
            ]
          }
        }
      },
      "PayrollPaymentWrite": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "method",
          "paid_on"
        ],
        "properties": {
          "payslip_ids": {
            "description": "ALL (default) or an explicit list of payslip ids.",
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "ALL"
                ]
              },
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Uuid"
                }
              }
            ]
          },
          "method": {
            "$ref": "#/components/schemas/PaymentMethod"
          },
          "paid_on": {
            "$ref": "#/components/schemas/DateOnly"
          },
          "amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "reference": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "note": {
            "type": "string"
          },
          "batch_ref": {
            "type": "string",
            "description": "SHA-256 of the bank-advice CSV that this payment follows."
          }
        }
      },
      "PayrollPayment": {
        "type": "object",
        "required": [
          "id",
          "payslip_id",
          "employee_id",
          "month_id",
          "method",
          "amount",
          "paid_on"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "payslip_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "employee_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "month_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "batch_ref": {
            "type": [
              "string",
              "null"
            ]
          },
          "method": {
            "$ref": "#/components/schemas/PaymentMethod"
          },
          "amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "paid_on": {
            "$ref": "#/components/schemas/DateOnly"
          },
          "reference": {
            "type": [
              "string",
              "null"
            ]
          },
          "note": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PayTeam": {
        "type": "object",
        "required": [
          "id",
          "team_id",
          "kind",
          "settlement_method",
          "version"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "team_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "CONTRACTOR",
              "STAFF"
            ]
          },
          "default_daily_rate_amount": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "settlement_method": {
            "type": "string",
            "enum": [
              "BANK_TRANSFER",
              "CASH"
            ]
          },
          "version": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "PayTeamWrite": {
        "type": "object",
        "required": [
          "kind"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "CONTRACTOR",
              "STAFF"
            ]
          },
          "default_daily_rate_amount": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ],
            "description": "CONTRACTOR only; must be null for STAFF."
          },
          "settlement_method": {
            "type": "string",
            "enum": [
              "BANK_TRANSFER",
              "CASH"
            ],
            "default": "BANK_TRANSFER"
          },
          "version": {
            "type": "integer",
            "description": "Optional optimistic-concurrency check on update."
          }
        }
      },
      "PayTeamList": {
        "type": "object",
        "required": [
          "pay_teams_enabled",
          "data"
        ],
        "properties": {
          "pay_teams_enabled": {
            "type": "boolean"
          },
          "currency_code": {
            "type": "string"
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "team_id": {
                  "$ref": "#/components/schemas/Uuid"
                },
                "team_key": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "status": {
                  "type": "string"
                },
                "member_count": {
                  "type": "integer"
                },
                "contractor": {
                  "type": [
                    "object",
                    "null"
                  ],
                  "properties": {
                    "employee_id": {
                      "$ref": "#/components/schemas/Uuid"
                    },
                    "employee_no": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "full_name": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "bank_verified": {
                      "type": "boolean"
                    }
                  }
                },
                "pay_team": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PayTeam"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              }
            }
          }
        }
      },
      "PayTeamMemberRate": {
        "type": "object",
        "properties": {
          "employee_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "employee_no": {
            "type": "string"
          },
          "full_name": {
            "type": "string"
          },
          "individual_daily_rate_amount": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "effective_daily_rate_amount": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "rate_source": {
            "type": "string",
            "enum": [
              "INDIVIDUAL",
              "TEAM_DEFAULT",
              "NONE"
            ]
          },
          "monthly_pay_setup": {
            "type": "boolean",
            "description": "True when the worker has a MONTHLY pay setup (a day rate cannot be set here)."
          }
        }
      },
      "PayTeamMemberRates": {
        "type": "object",
        "properties": {
          "team_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "name": {
            "type": "string"
          },
          "changed": {
            "type": "integer"
          },
          "pay_team": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PayTeam"
              },
              {
                "type": "null"
              }
            ]
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayTeamMemberRate"
            }
          }
        }
      },
      "PayTeamMemberRatesWrite": {
        "type": "object",
        "required": [
          "rates"
        ],
        "properties": {
          "rates": {
            "type": "array",
            "minItems": 1,
            "maxItems": 1000,
            "items": {
              "type": "object",
              "required": [
                "daily_rate_amount"
              ],
              "properties": {
                "employee_id": {
                  "$ref": "#/components/schemas/Uuid"
                },
                "employee_no": {
                  "type": "string"
                },
                "daily_rate_amount": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Money"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "null clears the worker's own rate (the team default applies)."
                }
              }
            }
          }
        }
      },
      "PayTeamSubtotal": {
        "type": "object",
        "properties": {
          "pay_team_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "team_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "CONTRACTOR",
              "STAFF"
            ]
          },
          "settlement": {
            "type": "string",
            "enum": [
              "INDIVIDUAL",
              "TEAM"
            ]
          },
          "settlement_method": {
            "type": "string"
          },
          "contractor": {
            "type": [
              "object",
              "null"
            ]
          },
          "payslip_count": {
            "type": "integer"
          },
          "paid_days": {
            "type": "string"
          },
          "gross_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "net_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "paid_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "remaining_amount": {
            "$ref": "#/components/schemas/SignedMoney"
          }
        }
      },
      "PayrollNotInPayroll": {
        "type": "object",
        "properties": {
          "month": {
            "$ref": "#/components/schemas/YearMonth"
          },
          "count": {
            "type": "integer"
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "employee_id": {
                  "$ref": "#/components/schemas/Uuid"
                },
                "employee_no": {
                  "type": "string"
                },
                "full_name": {
                  "type": "string"
                },
                "reason": {
                  "type": "string",
                  "enum": [
                    "NOT_IN_PAY_TEAM"
                  ]
                }
              }
            }
          }
        }
      },
      "TeamSettlementWrite": {
        "type": "object",
        "required": [
          "pay_team_id",
          "paid_on"
        ],
        "properties": {
          "pay_team_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "method": {
            "type": "string",
            "enum": [
              "BANK_TRANSFER",
              "CASH"
            ],
            "description": "Defaults to the pay team's settlement_method."
          },
          "paid_on": {
            "$ref": "#/components/schemas/DateOnly"
          },
          "reference": {
            "type": "string"
          },
          "batch_ref": {
            "type": "string"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "TeamSettlement": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "month_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "pay_team_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "payee_employee_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "method": {
            "type": "string",
            "enum": [
              "BANK_TRANSFER",
              "CASH"
            ]
          },
          "amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "paid_on": {
            "$ref": "#/components/schemas/DateOnly"
          },
          "reference": {
            "type": [
              "string",
              "null"
            ]
          },
          "batch_ref": {
            "type": [
              "string",
              "null"
            ]
          },
          "bank_snapshot": {
            "type": [
              "object",
              "null"
            ],
            "description": "account_holder_name, account_last4, ifsc_code, bank_name at settlement time."
          },
          "note": {
            "type": [
              "string",
              "null"
            ]
          },
          "payslip_count": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PayrollAdvanceWrite": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "employee_id",
          "amount",
          "start_month",
          "paid_on"
        ],
        "properties": {
          "employee_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "monthly_recovery_amount": {
            "$ref": "#/components/schemas/Money"
          },
          "start_month": {
            "$ref": "#/components/schemas/YearMonth"
          },
          "paid_on": {
            "$ref": "#/components/schemas/DateOnly"
          },
          "method": {
            "$ref": "#/components/schemas/PaymentMethod"
          },
          "reference": {
            "type": "string"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "PayrollAdvance": {
        "type": "object",
        "required": [
          "id",
          "employee_id",
          "amount",
          "monthly_recovery_amount",
          "start_month",
          "paid_on",
          "method",
          "status",
          "version"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "employee_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "monthly_recovery_amount": {
            "$ref": "#/components/schemas/Money"
          },
          "start_month": {
            "$ref": "#/components/schemas/YearMonth"
          },
          "paid_on": {
            "$ref": "#/components/schemas/DateOnly"
          },
          "method": {
            "$ref": "#/components/schemas/PaymentMethod"
          },
          "reference": {
            "type": [
              "string",
              "null"
            ]
          },
          "note": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "OPEN",
              "SETTLED",
              "WRITTEN_OFF"
            ]
          },
          "version": {
            "type": "integer",
            "minimum": 0
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PayrollAdvanceEventWrite": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "kind"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "RECOVERY",
              "SKIP",
              "MANUAL_REPAYMENT",
              "WRITE_OFF"
            ]
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "month": {
            "$ref": "#/components/schemas/YearMonth"
          },
          "reason": {
            "type": "string"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "PayrollAdvanceEvent": {
        "type": "object",
        "required": [
          "id",
          "advance_id",
          "employee_id",
          "month",
          "kind",
          "amount"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "advance_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "employee_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "month": {
            "$ref": "#/components/schemas/YearMonth"
          },
          "kind": {
            "type": "string",
            "enum": [
              "RECOVERY",
              "SKIP",
              "MANUAL_REPAYMENT",
              "WRITE_OFF"
            ]
          },
          "amount": {
            "$ref": "#/components/schemas/SignedMoney"
          },
          "payslip_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "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"
              }
            }
          }
        }
      },
      "Uuid": {
        "type": "string",
        "format": "uuid",
        "description": "UUIDv7 surrogate primary key (db-docs/00 §3). Never the business identifier."
      },
      "Timestamp": {
        "type": "string",
        "format": "date-time",
        "description": "timestamptz, serialized UTC ISO-8601. Presentation timezone is a client concern."
      },
      "DateOnly": {
        "type": "string",
        "format": "date",
        "description": "Calendar-only value (pay-period date, leave date, due date)."
      },
      "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"
          }
        }
      },
      "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"
            }
          }
        }
      },
      "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."
                    }
                  ]
                }
              }
            }
          }
        }
      },
      "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"
        }
      }
    }
  }
}