{
  "openapi": "3.1.0",
  "info": {
    "title": "PeopleOS API",
    "version": "1.0.0",
    "description": "India-first HRMS + Payroll + Compliance platform. Labour Code 2025 compliant, DPDP Act ready.",
    "contact": { "name": "PeopleOS Engineering", "email": "api@peopleos.app" }
  },
  "servers": [
    { "url": "https://app.peopleos.app", "description": "Production" },
    { "url": "http://localhost:3000", "description": "Local development" }
  ],
  "security": [{ "BearerAuth": [] }],
  "components": {
    "securitySchemes": {
      "BearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string" }
        }
      },
      "Employee": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "orgId": { "type": "string", "format": "uuid" },
          "employeeCode": { "type": "string", "example": "EMP001" },
          "name": { "type": "string", "example": "Rajesh Kumar" },
          "email": { "type": "string", "format": "email" },
          "designation": { "type": "string" },
          "status": { "type": "string", "enum": ["ACTIVE", "INACTIVE", "TERMINATED"] },
          "pan": { "type": "string", "example": "ABCDE1234F" },
          "uan": { "type": "string", "example": "100123456789" },
          "createdAt": { "type": "string", "format": "date-time" }
        }
      },
      "PayrollRun": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "orgId": { "type": "string", "format": "uuid" },
          "month": { "type": "integer", "minimum": 1, "maximum": 12 },
          "year": { "type": "integer" },
          "status": { "type": "string", "enum": ["DRAFT", "PROCESSING", "PROCESSED", "APPROVED", "PAID", "CANCELLED"] },
          "totalGross": { "type": "number" },
          "totalNetPay": { "type": "number" },
          "employeeCount": { "type": "integer" }
        }
      },
      "Payslip": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "employeeId": { "type": "string", "format": "uuid" },
          "month": { "type": "integer" },
          "year": { "type": "integer" },
          "grossEarnings": { "type": "number" },
          "totalDeductions": { "type": "number" },
          "netPay": { "type": "number" },
          "taxRegime": { "type": "string", "enum": ["OLD", "NEW"] },
          "earnings": { "type": "object" },
          "deductions": { "type": "object" }
        }
      },
      "SalaryStructure": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "ctc": { "type": "number" },
          "is50PctCompliant": { "type": "boolean" },
          "components": { "type": "array", "items": { "type": "object" } }
        }
      },
      "FnFSettlement": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "employeeId": { "type": "string", "format": "uuid" },
          "exitType": { "type": "string" },
          "exitDate": { "type": "string", "format": "date" },
          "gratuityAmount": { "type": "number" },
          "status": { "type": "string", "enum": ["INITIATED","CLEARANCE_PENDING","CLEARANCE_DONE","CALCULATED","APPROVED","PAID","REVERSED"] }
        }
      },
      "Subscription": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "orgId": { "type": "string", "format": "uuid" },
          "plan": { "type": "string", "enum": ["free", "starter", "professional", "enterprise"] },
          "status": { "type": "string", "enum": ["trialing", "active", "cancelled", "past_due"] },
          "billingCycle": { "type": "string", "enum": ["monthly", "annual"] },
          "priceInr": { "type": "number" },
          "employeeLimit": { "type": "integer" },
          "renewsAt": { "type": "string", "format": "date-time", "nullable": true }
        }
      }
    }
  },
  "paths": {
    "/api/health": {
      "get": {
        "summary": "Health check",
        "description": "Used by Docker, load balancers, and uptime monitors.",
        "security": [],
        "tags": ["System"],
        "responses": {
          "200": {
            "description": "Service healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "ok" },
                    "version": { "type": "string" },
                    "environment": { "type": "string" },
                    "uptime": { "type": "integer" },
                    "timestamp": { "type": "string", "format": "date-time" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/login": {
      "post": {
        "summary": "Login",
        "description": "Authenticate with email + password. Returns JWT. Supports TOTP 2FA.",
        "security": [],
        "tags": ["Auth"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email", "password"],
                "properties": {
                  "email": { "type": "string", "format": "email" },
                  "password": { "type": "string" },
                  "totpCode": { "type": "string", "description": "6-digit TOTP code if 2FA enabled" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Login successful, JWT returned" },
          "401": { "description": "Invalid credentials" },
          "429": { "description": "Rate limited" }
        }
      }
    },
    "/api/v1/employees": {
      "get": {
        "summary": "List employees",
        "tags": ["Employees"],
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["ACTIVE","INACTIVE","TERMINATED"] } },
          { "name": "search", "in": "query", "schema": { "type": "string" } },
          { "name": "page", "in": "query", "schema": { "type": "integer", "default": 1 } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 25, "maximum": 100 } }
        ],
        "responses": {
          "200": {
            "description": "Employee list",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Employee" } }, "total": { "type": "integer" } } } } }
          }
        }
      },
      "post": {
        "summary": "Create employee",
        "tags": ["Employees"],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Employee" } } }
        },
        "responses": {
          "201": { "description": "Employee created" },
          "400": { "description": "Validation error" }
        }
      }
    },
    "/api/v1/payroll/run": {
      "get": {
        "summary": "List payroll runs",
        "tags": ["Payroll"],
        "responses": { "200": { "description": "Payroll run list" } }
      },
      "post": {
        "summary": "Initiate payroll run",
        "tags": ["Payroll"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["month", "year"],
                "properties": {
                  "month": { "type": "integer", "minimum": 1, "maximum": 12 },
                  "year": { "type": "integer" }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Payroll run initiated" },
          "409": { "description": "Payroll already exists for this period" }
        }
      }
    },
    "/api/v1/payroll/payslip/{id}": {
      "get": {
        "summary": "Get payslip",
        "description": "Returns payslip as JSON (default) or PDF (Accept: application/pdf or ?format=pdf).",
        "tags": ["Payroll"],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } },
          { "name": "format", "in": "query", "schema": { "type": "string", "enum": ["json", "pdf"], "default": "json" } }
        ],
        "responses": {
          "200": {
            "description": "Payslip data or PDF file",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Payslip" } },
              "application/pdf": { "schema": { "type": "string", "format": "binary" } }
            }
          },
          "404": { "description": "Payslip not found" }
        }
      }
    },
    "/api/v1/payroll/statutory-returns": {
      "get": {
        "summary": "Generate statutory returns",
        "description": "Generates ECR (PF), ESI challan, PT return, or 24Q TDS return data.",
        "tags": ["Payroll"],
        "parameters": [
          { "name": "type", "in": "query", "required": true, "schema": { "type": "string", "enum": ["ecr","esi","pt","24q"] } },
          { "name": "month", "in": "query", "schema": { "type": "integer" } },
          { "name": "year", "in": "query", "schema": { "type": "integer" } }
        ],
        "responses": { "200": { "description": "Statutory return data" } }
      }
    },
    "/api/v1/salary-structures": {
      "get": { "summary": "List salary structures", "tags": ["Salary"], "responses": { "200": { "description": "List" } } },
      "post": { "summary": "Create salary structure", "tags": ["Salary"], "responses": { "201": { "description": "Created" } } }
    },
    "/api/v1/salary-components": {
      "get": { "summary": "List salary components", "tags": ["Salary"], "responses": { "200": { "description": "List" } } }
    },
    "/api/v1/fnf": {
      "get": { "summary": "List FnF settlements", "tags": ["FnF"], "responses": { "200": { "description": "List" } } },
      "post": { "summary": "Initiate FnF settlement", "tags": ["FnF"], "responses": { "201": { "description": "Initiated" } } }
    },
    "/api/v1/tax-declarations": {
      "get": { "summary": "Get Form 12BB declaration", "tags": ["Tax"], "responses": { "200": { "description": "Declaration" } } },
      "post": { "summary": "Submit Form 12BB", "tags": ["Tax"], "responses": { "200": { "description": "Submitted" } } }
    },
    "/api/v1/fbp": {
      "get": { "summary": "Get FBP plan", "tags": ["FBP"], "responses": { "200": { "description": "Plan" } } },
      "post": { "summary": "Create/update FBP plan", "tags": ["FBP"], "responses": { "200": { "description": "Updated" } } }
    },
    "/api/v1/fbp/selections": {
      "get": { "summary": "Get FBP selections (ESS)", "tags": ["FBP"], "responses": { "200": { "description": "Selections" } } },
      "post": { "summary": "Submit FBP selection", "tags": ["FBP"], "responses": { "200": { "description": "Saved" } } }
    },
    "/api/v1/fbp/claims": {
      "get": { "summary": "List FBP claims", "tags": ["FBP"], "responses": { "200": { "description": "Claims" } } },
      "post": { "summary": "Submit FBP claim", "tags": ["FBP"], "responses": { "201": { "description": "Created" } } }
    },
    "/api/v1/compliance/pt": {
      "get": { "summary": "Get PT config + registrations", "tags": ["Compliance"], "responses": { "200": { "description": "PT data" } } },
      "post": { "summary": "Upsert PT registration", "tags": ["Compliance"], "responses": { "200": { "description": "Updated" } } }
    },
    "/api/v1/compliance/lwf": {
      "get": { "summary": "Get LWF config", "tags": ["Compliance"], "responses": { "200": { "description": "LWF config" } } },
      "post": { "summary": "Upsert LWF config", "tags": ["Compliance"], "responses": { "200": { "description": "Updated" } } }
    },
    "/api/v1/contractors": {
      "get": { "summary": "List contractors", "tags": ["Contractors"], "responses": { "200": { "description": "List" } } },
      "post": { "summary": "Create contractor", "tags": ["Contractors"], "responses": { "201": { "description": "Created" } } }
    },
    "/api/v1/migration": {
      "get": { "summary": "List migration jobs", "tags": ["Migration"], "responses": { "200": { "description": "Jobs" } } },
      "post": { "summary": "Create migration job", "tags": ["Migration"], "responses": { "201": { "description": "Job created" } } }
    },
    "/api/v1/bonus": {
      "get": { "summary": "Get bonus config + eligibility", "tags": ["Bonus"], "responses": { "200": { "description": "Bonus data" } } },
      "post": { "summary": "Compute Bonus Act payouts", "tags": ["Bonus"], "responses": { "200": { "description": "Computed" } } }
    },
    "/api/v1/letters": {
      "get": { "summary": "List letter templates", "tags": ["Letters"], "responses": { "200": { "description": "Templates" } } },
      "post": { "summary": "Create template or generate letter", "tags": ["Letters"], "responses": { "200": { "description": "Done" } } }
    },
    "/api/v1/accounting": {
      "get": { "summary": "Get integrations or Tally XML export", "tags": ["Accounting"], "responses": { "200": { "description": "Integrations" } } },
      "post": { "summary": "Connect accounting integration", "tags": ["Accounting"], "responses": { "200": { "description": "Connected" } } }
    },
    "/api/v1/oris/chat": {
      "post": {
        "summary": "ORIS AI chat",
        "description": "Natural language HR assistant. Requires Professional plan.",
        "tags": ["ORIS AI"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["query"],
                "properties": {
                  "query": { "type": "string", "maxLength": 2000 },
                  "queryType": { "type": "string", "enum": ["CHAT","INSIGHT","DRAFT","PREFILL","COMPLIANCE_CHECK","TAX_OPTIMIZER","FNF_EXPLAINER","PAYROLL_ANOMALY"] },
                  "page": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": { "200": { "description": "AI response" }, "429": { "description": "Quota exceeded" } }
      }
    },
    "/api/v1/oris/insight": {
      "post": {
        "summary": "ORIS proactive insights",
        "description": "Get data-driven insights about payroll, compliance, or HR metrics.",
        "tags": ["ORIS AI"],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "type": "object", "required": ["topic"], "properties": { "topic": { "type": "string" }, "page": { "type": "string" } } } } }
        },
        "responses": { "200": { "description": "Insight response" } }
      }
    },
    "/api/v1/oris/draft": {
      "post": {
        "summary": "ORIS document draft generation",
        "description": "Generate HR document drafts (offer letters, increment letters, etc.).",
        "tags": ["ORIS AI"],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "type": "object", "required": ["documentType","context"], "properties": { "documentType": { "type": "string" }, "context": { "type": "string" } } } } }
        },
        "responses": { "200": { "description": "Draft content in `draftContent` field" } }
      }
    },
    "/api/v1/oris/prefill": {
      "post": {
        "summary": "ORIS smart form pre-fill",
        "description": "Given a form type and partial data, returns suggested field values.",
        "tags": ["ORIS AI"],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "type": "object", "required": ["formType"], "properties": { "formType": { "type": "string" }, "partialData": { "type": "object" } } } } }
        },
        "responses": { "200": { "description": "Pre-fill suggestions in `formPrefill` field" } }
      }
    },
    "/api/v1/subscriptions": {
      "get": {
        "summary": "Get subscription",
        "description": "Returns current subscription and plan catalogue.",
        "tags": ["Billing"],
        "responses": { "200": { "description": "Subscription data", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Subscription" } } } } }
      },
      "post": {
        "summary": "Upgrade/change plan",
        "tags": ["Billing"],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "type": "object", "required": ["plan"], "properties": { "plan": { "type": "string", "enum": ["free","starter","professional","enterprise"] }, "billingCycle": { "type": "string", "enum": ["monthly","annual"] } } } } }
        },
        "responses": { "200": { "description": "Subscription updated" }, "422": { "description": "Employee count exceeds plan limit" } }
      },
      "patch": {
        "summary": "Cancel or modify subscription",
        "tags": ["Billing"],
        "responses": { "200": { "description": "Updated" } }
      }
    },
    "/api/v1/global-payroll/sg": {
      "get": { "summary": "Singapore payroll data", "tags": ["Global Payroll"], "responses": { "200": { "description": "Config + run history" } } },
      "post": {
        "summary": "Configure or run Singapore payroll",
        "tags": ["Global Payroll"],
        "parameters": [{ "name": "action", "in": "query", "schema": { "type": "string", "enum": ["run"] } }],
        "responses": { "200": { "description": "Config saved or payroll run" }, "409": { "description": "Already filed for this period" } }
      }
    },
    "/api/v1/global-payroll/my": {
      "get": { "summary": "Malaysia payroll data", "tags": ["Global Payroll"], "responses": { "200": { "description": "Config + run history" } } },
      "post": {
        "summary": "Configure or run Malaysia payroll",
        "tags": ["Global Payroll"],
        "parameters": [{ "name": "action", "in": "query", "schema": { "type": "string", "enum": ["run"] } }],
        "responses": { "200": { "description": "Config saved or payroll run" }, "409": { "description": "Already filed for this period" } }
      }
    },
    "/api/v1/global-payroll/au": {
      "get": { "summary": "Australia payroll data (PAYG, Super, Medicare, HELP)", "tags": ["Global Payroll — Australia"], "responses": { "200": { "description": "Config + run history" } } },
      "post": {
        "summary": "Configure or run Australia payroll",
        "description": "POST without action: upsert config (ABN, super fund, STP). POST ?action=run: run payroll with PAYG, Super, Medicare Levy, HELP repayment.",
        "tags": ["Global Payroll — Australia"],
        "parameters": [{ "name": "action", "in": "query", "schema": { "type": "string", "enum": ["run"] } }],
        "responses": { "201": { "description": "Config saved or payroll run completed" }, "409": { "description": "Already filed for this period" } }
      }
    },
    "/api/v1/global-payroll/nz": {
      "get": { "summary": "New Zealand payroll data (PAYE, KiwiSaver, ACC)", "tags": ["Global Payroll — New Zealand"], "responses": { "200": { "description": "Config + run history" } } },
      "post": {
        "summary": "Configure or run New Zealand payroll",
        "description": "POST without action: upsert config (IRD number, KiwiSaver scheme). POST ?action=run: run payroll with PAYE, KiwiSaver, ACC levy, Student Loan.",
        "tags": ["Global Payroll — New Zealand"],
        "parameters": [{ "name": "action", "in": "query", "schema": { "type": "string", "enum": ["run"] } }],
        "responses": { "201": { "description": "Config saved or payroll run completed" }, "409": { "description": "Already filed for this period" } }
      }
    },
    "/api/v1/global-payroll/us": {
      "get": { "summary": "US payroll data (Federal Tax, FICA, State Tax)", "tags": ["Global Payroll — United States"], "responses": { "200": { "description": "Config + run history" } } },
      "post": {
        "summary": "Configure or run US payroll",
        "description": "Federal income tax (7 brackets), Social Security (6.2% on $176,100 cap), Medicare (1.45% + 0.9% additional >$200k), state tax (configurable flat rate), FUTA (employer-only).",
        "tags": ["Global Payroll — United States"],
        "parameters": [{ "name": "action", "in": "query", "schema": { "type": "string", "enum": ["run"] } }],
        "responses": { "201": { "description": "Config saved or payroll run completed" }, "409": { "description": "Already filed for this period" } }
      }
    },
    "/api/v1/global-payroll/ca": {
      "get": { "summary": "Canada payroll data (Federal Tax, Provincial Tax, CPP, EI)", "tags": ["Global Payroll — Canada"], "responses": { "200": { "description": "Config + run history" } } },
      "post": {
        "summary": "Configure or run Canada payroll",
        "description": "Federal income tax (5 brackets + BPA), provincial tax (ON/BC/AB/QC), CPP/CPP2 (5.95%/4% with YMPE/YAMPE), EI (1.64% employee / 2.296% employer).",
        "tags": ["Global Payroll — Canada"],
        "parameters": [{ "name": "action", "in": "query", "schema": { "type": "string", "enum": ["run"] } }],
        "responses": { "201": { "description": "Config saved or payroll run completed" }, "409": { "description": "Already filed for this period" } }
      }
    },
    "/api/v1/global-payroll/gcc": {
      "get": {
        "summary": "GCC payroll data (UAE, KSA, Qatar, Bahrain, Kuwait, Oman)",
        "tags": ["Global Payroll — GCC"],
        "parameters": [{ "name": "country", "in": "query", "required": true, "schema": { "type": "string", "enum": ["UAE","KSA","QAT","BHR","KWT","OMN"] } }],
        "responses": { "200": { "description": "Config + run history + country info" } }
      },
      "post": {
        "summary": "Configure or run GCC payroll",
        "description": "Unified endpoint for all 6 GCC countries. Social insurance (nationals-only except Bahrain), EOSG, WPS compliance. BHD/KWD/OMR use 3 decimal places.",
        "tags": ["Global Payroll — GCC"],
        "parameters": [
          { "name": "action", "in": "query", "schema": { "type": "string", "enum": ["run"] } },
          { "name": "country", "in": "query", "schema": { "type": "string", "enum": ["UAE","KSA","QAT","BHR","KWT","OMN"] } }
        ],
        "responses": { "201": { "description": "Config saved or payroll run completed" }, "409": { "description": "Already filed for this period" } }
      }
    },
    "/api/v1/white-label": {
      "get": {
        "summary": "White-label config + client summary",
        "description": "Requires Enterprise plan.",
        "tags": ["White Label"],
        "parameters": [{ "name": "action", "in": "query", "schema": { "type": "string", "enum": ["clients","commission"] } }],
        "responses": { "200": { "description": "Config and summary" }, "403": { "description": "Not Enterprise plan" } }
      },
      "post": {
        "summary": "Configure white-label or manage clients",
        "tags": ["White Label"],
        "parameters": [{ "name": "action", "in": "query", "schema": { "type": "string", "enum": ["add-client","remove-client"] } }],
        "responses": { "200": { "description": "Updated" } }
      }
    },
    "/api/v1/webhooks/whatsapp": {
      "get": { "summary": "WhatsApp webhook verification", "security": [], "tags": ["Webhooks"], "responses": { "200": { "description": "Verification token" } } },
      "post": { "summary": "WhatsApp incoming message handler", "security": [], "tags": ["Webhooks"], "responses": { "200": { "description": "Processed" } } }
    },
    "/api/v1/auth/sso/google": {
      "get": {
        "summary": "Initiate Google SSO",
        "description": "Starts Google OAuth 2.0 PKCE flow. Generates state and code verifier, stores them in httpOnly cookies, and redirects to Google's consent screen.",
        "security": [],
        "tags": ["Auth"],
        "responses": {
          "302": { "description": "Redirect to Google consent screen" },
          "503": { "description": "Google SSO not configured" }
        }
      }
    },
    "/api/v1/auth/sso/microsoft": {
      "get": {
        "summary": "Initiate Microsoft SSO",
        "description": "Starts Microsoft Entra ID OAuth 2.0 PKCE flow. Generates state and code verifier, stores them in httpOnly cookies, and redirects to Microsoft's consent screen.",
        "security": [],
        "tags": ["Auth"],
        "responses": {
          "302": { "description": "Redirect to Microsoft consent screen" },
          "503": { "description": "Microsoft SSO not configured" }
        }
      }
    },
    "/api/v1/auth/oris": {
      "post": {
        "summary": "ORIS Auth — NL login assistant",
        "description": "Extracts email from a natural language message using regex. Returns REDIRECT_LOGIN with email or ASK_EMAIL if no email found. No LLM call — deterministic extraction.",
        "security": [],
        "tags": ["Auth"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["message"],
                "properties": {
                  "message": { "type": "string", "maxLength": 500 }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email extracted or prompt returned",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "action": { "type": "string", "enum": ["REDIRECT_LOGIN", "ASK_EMAIL"] },
                    "email": { "type": "string", "format": "email" },
                    "response": { "type": "string" }
                  }
                }
              }
            }
          },
          "400": { "description": "Invalid request" }
        }
      }
    },
    "/api/v1/auth/forgot-password": {
      "post": {
        "summary": "Request password reset",
        "description": "Sends a password reset email with a secure token. Always returns 200 regardless of whether the email exists (prevents user enumeration). Rate limited to 3 requests per email per hour. Token valid for 1 hour.",
        "security": [],
        "tags": ["Auth"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email"],
                "properties": {
                  "email": { "type": "string", "format": "email" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success (always returned)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": { "type": "string", "example": "If an account exists with that email, a password reset link has been sent." }
                  }
                }
              }
            }
          },
          "400": { "description": "Invalid email format" }
        }
      }
    },
    "/api/v1/auth/reset-password": {
      "post": {
        "summary": "Reset password with token",
        "description": "Validates the reset token and updates the user's password. Hashes with bcrypt cost 12, increments sessionVersion to invalidate all existing JWTs, and deletes all active sessions.",
        "security": [],
        "tags": ["Auth"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email", "token", "newPassword"],
                "properties": {
                  "email": { "type": "string", "format": "email" },
                  "token": { "type": "string" },
                  "newPassword": { "type": "string", "minLength": 8, "maxLength": 128 }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Password reset successful" },
          "400": { "description": "Invalid, expired, or already used token" }
        }
      }
    },
    "/api/v1/digilocker/ekyc": {
      "get": {
        "summary": "Fetch eKYC data from DigiLocker",
        "description": "Retrieves eKYC data (name, DOB, gender, address) from DigiLocker using the employee's stored access token. If ?autofill=true, auto-fills the employee's profile fields. Refreshes the access token if expired.",
        "tags": ["DigiLocker"],
        "parameters": [
          { "name": "autofill", "in": "query", "schema": { "type": "string", "enum": ["true", "false"], "default": "false" }, "description": "Auto-fill employee profile with eKYC data" }
        ],
        "responses": {
          "200": {
            "description": "eKYC data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ekyc": {
                      "type": "object",
                      "properties": {
                        "name": { "type": "string" },
                        "dateOfBirth": { "type": "string", "example": "15-08-1990" },
                        "gender": { "type": "string", "enum": ["M", "F", "T"] },
                        "address": { "type": "object" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "description": "DigiLocker not connected" },
          "404": { "description": "Employee record not found" },
          "502": { "description": "DigiLocker API failure" }
        }
      }
    },
    "/api/v1/digilocker/pull": {
      "post": {
        "summary": "Pull document from DigiLocker",
        "description": "Pulls a verified document from DigiLocker by URI. Stores the document metadata in the DigiLockerDocument table and creates an audit log entry.",
        "tags": ["DigiLocker"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["uri", "docType"],
                "properties": {
                  "uri": { "type": "string", "description": "DigiLocker document URI" },
                  "docType": { "type": "string", "description": "Document type code (e.g., PANCR, DRVLC)", "example": "PANCR" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Document pulled and stored",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "document": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "docType": { "type": "string" },
                        "uri": { "type": "string" },
                        "issuerName": { "type": "string" },
                        "isVerified": { "type": "boolean" },
                        "verifiedAt": { "type": "string", "format": "date-time" },
                        "contentType": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "description": "DigiLocker not connected or validation error" },
          "404": { "description": "Employee record not found" },
          "502": { "description": "DigiLocker API failure" }
        }
      }
    },
    "/api/v1/aadhaar/tokenise": {
      "post": {
        "summary": "Tokenise Aadhaar number",
        "description": "Encrypts a raw Aadhaar number using AES-256-GCM and stores it in the Aadhaar Data Vault. The raw number is NEVER stored in the application database. Returns a token UUID and masked Aadhaar (XXXX-XXXX-1234). Requires AADHAAR_MANAGE permission.",
        "tags": ["Aadhaar Vault"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["aadhaarNumber", "employeeId"],
                "properties": {
                  "aadhaarNumber": { "type": "string", "minLength": 12, "maxLength": 14, "description": "12-digit Aadhaar, optionally with spaces or hyphens" },
                  "employeeId": { "type": "string", "format": "uuid" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Aadhaar tokenised",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tokenId": { "type": "string", "format": "uuid" },
                    "maskedAadhaar": { "type": "string", "example": "XXXX-XXXX-1012" }
                  }
                }
              }
            }
          },
          "400": { "description": "Validation error (invalid Aadhaar format)" },
          "403": { "description": "Missing AADHAAR_MANAGE permission" }
        }
      }
    },
    "/api/v1/aadhaar/verify": {
      "post": {
        "summary": "Verify Aadhaar last 4 digits",
        "description": "Verifies the last 4 digits of an Aadhaar number against the encrypted vault entry. Never reveals the full Aadhaar number.",
        "tags": ["Aadhaar Vault"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["vaultEntryId", "lastFourDigits"],
                "properties": {
                  "vaultEntryId": { "type": "string", "format": "uuid" },
                  "lastFourDigits": { "type": "string", "pattern": "^\\d{4}$", "example": "1012" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": { "type": "boolean" }
                  }
                }
              }
            }
          },
          "400": { "description": "Validation error" }
        }
      }
    },
    "/api/v1/aadhaar/access-log": {
      "get": {
        "summary": "Aadhaar vault access log",
        "description": "Returns the chronological access history for Aadhaar vault entries. Every tokenise, detokenise, verify, and revoke operation is logged. Requires AUDIT_VIEW permission.",
        "tags": ["Aadhaar Vault"],
        "parameters": [
          { "name": "employeeId", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Filter by employee" },
          { "name": "vaultEntryId", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Filter by vault entry" },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "maximum": 200 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
        ],
        "responses": {
          "200": {
            "description": "Access log entries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "logs": { "type": "array", "items": { "type": "object" } },
                    "total": { "type": "integer" }
                  }
                }
              }
            }
          },
          "403": { "description": "Missing AUDIT_VIEW permission" }
        }
      }
    },
    "/api/v1/payroll/payslip/verify": {
      "get": {
        "summary": "Verify payslip authenticity",
        "description": "Public endpoint (no auth). Validates a payslip's HMAC-SHA256 signature from the QR code. Returns employee name, org name, period, and net pay if valid.",
        "security": [],
        "tags": ["Payroll"],
        "parameters": [
          { "name": "id", "in": "query", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Payslip ID" },
          { "name": "sig", "in": "query", "required": true, "schema": { "type": "string" }, "description": "HMAC-SHA256 signature" }
        ],
        "responses": {
          "200": {
            "description": "Payslip verified",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": { "type": "boolean" },
                    "payslip": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "employeeName": { "type": "string", "example": "Rajesh Kumar" },
                        "employeeCode": { "type": "string", "example": "EMP001" },
                        "orgName": { "type": "string", "example": "TechNova Solutions" },
                        "month": { "type": "integer" },
                        "year": { "type": "integer" },
                        "netPay": { "type": "number" },
                        "generatedAt": { "type": "string", "format": "date-time" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "description": "Missing id or sig query parameters" },
          "403": { "description": "Invalid or tampered signature" },
          "404": { "description": "Payslip not found" }
        }
      }
    }
  },
  "tags": [
    { "name": "System" },
    { "name": "Auth" },
    { "name": "Employees" },
    { "name": "Payroll" },
    { "name": "Salary" },
    { "name": "FnF" },
    { "name": "Tax" },
    { "name": "FBP" },
    { "name": "Compliance" },
    { "name": "Contractors" },
    { "name": "Migration" },
    { "name": "Bonus" },
    { "name": "Letters" },
    { "name": "Accounting" },
    { "name": "ORIS AI" },
    { "name": "Billing" },
    { "name": "Global Payroll" },
    { "name": "Global Payroll — United States" },
    { "name": "Global Payroll — Canada" },
    { "name": "Global Payroll — Australia" },
    { "name": "Global Payroll — New Zealand" },
    { "name": "Global Payroll — GCC" },
    { "name": "White Label" },
    { "name": "Webhooks" },
    { "name": "DigiLocker" },
    { "name": "Aadhaar Vault" }
  ]
}
