{
  "openapi": "3.1.0",
  "info": {
    "title": "Draxis.ai API",
    "version": "2026.04",
    "summary": "REST API for the Draxis cyber risk intelligence platform.",
    "description": "The Draxis API is a multi-tenant REST surface used by the Draxis application, the vCISO portal, the carrier portal, and authorized integrations. All requests are authenticated with a short-lived JWT obtained from `/api/auth/login` and scoped to a single tenant via the `X-Tenant-Slug` header (or the path for platform/org admin routes).\n\nThis reference is grouped by **tag**:\n\n* **System** — health and catalog probes.\n* **Auth** — login, refresh, MFA, and session management.\n* **Platform admin** — superadmin-only operations across organizations, tenants, and carriers.\n* **Org admin** — org-scoped operations over tenants and users inside one organization.\n* **Tenants** — CRUD on the tenant list itself.\n* **KRIs & sources** — the data model that feeds risk scoring.\n* **Integrations** — the connector catalog, test/run endpoints, and run history.\n* **Controls / Risks / Outcomes** — the remaining risk-management primitives.\n* **Vendors & TPRM** — vendor inventory, findings, assessments, playbooks.\n* **CRSE** — cyber risk simulation engine (templates, simulations, chains, MITRE mappings).\n* **Expert panel** — personas and panel sessions.\n* **Workflows** — workflow definitions, interviews, triggers.\n* **Chat** — stakeholder chat, agent chat, onboarding.\n* **Carrier portal** — insurance-carrier scoped API (`/api/carrier/*`).\n\nSome internal-only operations are listed with a short summary but no schema; they are out of scope for external integrations. Production access to non-public endpoints requires a signed agreement with Draxis.ai.",
    "contact": {
      "name": "Draxis.ai Support",
      "email": "support@draxis.ai",
      "url": "https://draxis.ai/support/"
    },
    "license": { "name": "Proprietary" }
  },
  "servers": [
    { "url": "https://app.draxis.ai", "description": "Production" },
    { "url": "https://demo.draxis.ai", "description": "Demo tenant (read-only, shared credentials)" },
    { "url": "http://localhost:8080", "description": "Local development" }
  ],
  "tags": [
    { "name": "System", "description": "Liveness, version, and catalog." },
    { "name": "Auth", "description": "Login, refresh, MFA, and session management. JWTs are signed server-side and expire in 15 minutes; refresh tokens live 30 days." },
    { "name": "Platform admin", "description": "Superadmin-only operations. Requires `role=superadmin` on the JWT. Not available to tenant users." },
    { "name": "Org admin", "description": "Operations scoped to a single organization (MSP / partner). Requires `role=master_admin` or higher." },
    { "name": "Tenants", "description": "Tenant list and lifecycle." },
    { "name": "KRIs & sources", "description": "Key Risk Indicators and the sources that populate them." },
    { "name": "Integrations", "description": "Connector catalog, test, manual run, and run history. Each connector is registered at server boot; see `/api/integrations/catalog`." },
    { "name": "Controls", "description": "Security controls, their owners, and their effectiveness signals." },
    { "name": "Risks", "description": "Risk register, ownership, treatment, and enterprise-risk mappings." },
    { "name": "Outcomes", "description": "Business outcomes that risks roll up to." },
    { "name": "Vendors & TPRM", "description": "Vendor inventory, assessments, findings, decisions, integration points, data elements, and alerts." },
    { "name": "Assessments", "description": "Structured vendor assessments." },
    { "name": "CRSE", "description": "Cyber Risk Simulation Engine — scenario templates, simulations, chains, loss parameters, MITRE mappings, toxic combinations." },
    { "name": "Expert panel", "description": "Personas and panel-session orchestration." },
    { "name": "Workflows", "description": "Workflow definitions, interviews, triggers, and KRI events." },
    { "name": "Chat", "description": "Stakeholder chat, workflow agent chat, and onboarding chat." },
    { "name": "Institutional knowledge", "description": "Institutional memory and documents." },
    { "name": "Organization structure", "description": "Divisions, business units, departments, sites." },
    { "name": "Public", "description": "Unauthenticated endpoints guarded by a single-use token." },
    { "name": "Carrier portal", "description": "Insurance-carrier scoped API under `/api/carrier/*`. Separate auth realm (see `/api/carrier/auth/login`)." }
  ],
  "security": [
    { "bearerAuth": [] }
  ],
  "paths": {
    "/api/health": {
      "get": {
        "tags": ["System"],
        "summary": "Liveness probe",
        "description": "Returns `{ status: 'ok' }` if the server is reachable. Does not check database or integration connectivity.",
        "security": [],
        "responses": {
          "200": {
            "description": "Server is up",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "const": "ok" },
                    "version": { "type": "string", "example": "2026.04.18" }
                  },
                  "required": ["status"]
                }
              }
            }
          }
        }
      }
    },

    "/api/auth/needs-setup": {
      "get": {
        "tags": ["Auth"],
        "summary": "Check if first-run admin setup is required",
        "description": "Returns `{ needsSetup: true }` when no platform admin exists yet. When true, `/api/auth/register-admin` becomes callable without authentication exactly once.",
        "security": [],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "needsSetup": { "type": "boolean" } }, "required": ["needsSetup"] } } } }
        }
      }
    },
    "/api/auth/register-admin": {
      "post": {
        "tags": ["Auth"],
        "summary": "Register the first platform admin (one-time)",
        "description": "Creates the initial superadmin. Fails with 403 if any admin already exists. Use `/api/auth/needs-setup` to check eligibility.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email", "password", "firstName", "lastName"],
                "properties": {
                  "email": { "type": "string", "format": "email" },
                  "password": { "type": "string", "minLength": 12 },
                  "firstName": { "type": "string" },
                  "lastName": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Admin created; returns JWT", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthSuccess" } } } },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/api/auth/login": {
      "post": {
        "tags": ["Auth"],
        "summary": "Exchange email + password for a JWT",
        "description": "Rate-limited to 50 attempts per IP per 15 minutes. If the account has MFA enabled, the response includes `mfaRequired: true` and a short-lived `mfaToken` to complete the flow at `/api/auth/mfa/verify`.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email", "password"],
                "properties": {
                  "email": { "type": "string", "format": "email" },
                  "password": { "type": "string" },
                  "tenantSlug": { "type": "string", "description": "Optional tenant slug; required for users with access to multiple tenants." }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Login successful or MFA required",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    { "$ref": "#/components/schemas/AuthSuccess" },
                    { "$ref": "#/components/schemas/MfaChallenge" }
                  ]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/auth/mfa/verify": {
      "post": {
        "tags": ["Auth"],
        "summary": "Complete MFA verification",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["mfaToken", "code"],
                "properties": {
                  "mfaToken": { "type": "string", "description": "Token returned by /api/auth/login when MFA is required." },
                  "code": { "type": "string", "pattern": "^[0-9]{6}$" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthSuccess" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/auth/refresh": {
      "post": {
        "tags": ["Auth"],
        "summary": "Refresh an expiring JWT",
        "description": "Uses the HTTP-only `draxis_refresh` cookie set at login. Returns a fresh access token.",
        "security": [],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthSuccess" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/auth/me": {
      "get": {
        "tags": ["Auth"],
        "summary": "Current user",
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/auth/me/preferences": {
      "patch": {
        "tags": ["Auth"],
        "summary": "Update current user's UI preferences",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object" } } } },
        "responses": { "200": { "$ref": "#/components/responses/OK" } }
      }
    },
    "/api/auth/change-password": {
      "post": {
        "tags": ["Auth"],
        "summary": "Change password for current user",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["currentPassword", "newPassword"],
                "properties": {
                  "currentPassword": { "type": "string" },
                  "newPassword": { "type": "string", "minLength": 12 }
                }
              }
            }
          }
        },
        "responses": { "200": { "$ref": "#/components/responses/OK" }, "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/api/auth/session": {
      "delete": {
        "tags": ["Auth"],
        "summary": "Log out the current session",
        "responses": { "204": { "description": "Logged out" } }
      }
    },
    "/api/auth/sessions": {
      "delete": {
        "tags": ["Auth"],
        "summary": "Revoke all sessions for current user",
        "responses": { "204": { "description": "All sessions revoked" } }
      }
    },
    "/api/auth/mfa/enroll": {
      "post": {
        "tags": ["Auth"],
        "summary": "Begin MFA enrollment (TOTP)",
        "description": "Returns a provisioning URI and base32 secret for the user's authenticator app. Confirm with `/api/auth/mfa/enroll/confirm`.",
        "responses": {
          "200": {
            "description": "Enrollment secret",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "secret": { "type": "string" },
                    "otpauthUrl": { "type": "string" }
                  },
                  "required": ["secret", "otpauthUrl"]
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/mfa/enroll/confirm": {
      "post": {
        "tags": ["Auth"],
        "summary": "Confirm MFA enrollment with a TOTP code",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["code"],
                "properties": { "code": { "type": "string", "pattern": "^[0-9]{6}$" } }
              }
            }
          }
        },
        "responses": { "200": { "$ref": "#/components/responses/OK" } }
      }
    },
    "/api/auth/mfa": {
      "delete": {
        "tags": ["Auth"],
        "summary": "Disable MFA for current user",
        "responses": { "204": { "description": "MFA disabled" } }
      }
    },
    "/api/auth/mfa/reset": {
      "post": {
        "tags": ["Auth"],
        "summary": "Reset MFA for another tenant user",
        "responses": { "204": { "description": "MFA reset" } }
      }
    },

    "/api/tenants": {
      "get": {
        "tags": ["Tenants"],
        "summary": "List all tenants",
        "description": "Returns every tenant visible to the caller. For superadmins, all tenants. For org admins, only tenants in their organization. For tenant users, only their own tenant.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/Tenant" }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": ["Tenants"],
        "summary": "Create a tenant",
        "description": "Superadmin or master-admin only.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["slug", "name"],
                "properties": {
                  "slug": { "type": "string", "pattern": "^[a-z0-9-]+$" },
                  "name": { "type": "string" },
                  "organizationSlug": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": { "201": { "description": "Created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Tenant" } } } } }
      }
    },
    "/api/tenants/{slug}": {
      "parameters": [{ "$ref": "#/components/parameters/TenantSlug" }],
      "put": { "tags": ["Tenants"], "summary": "Update tenant", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Tenants"], "summary": "Delete tenant", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/tenants/{slug}/mfa-policy": {
      "parameters": [{ "$ref": "#/components/parameters/TenantSlug" }],
      "patch": { "tags": ["Tenants"], "summary": "Update MFA policy for tenant", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },

    "/api/platform/tenants": {
      "get": { "tags": ["Platform admin"], "summary": "List tenants (platform view)", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/platform/audit-logs": {
      "get": { "tags": ["Platform admin"], "summary": "Platform-wide audit log", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/platform/organizations": {
      "get": { "tags": ["Platform admin"], "summary": "List organizations", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": { "tags": ["Platform admin"], "summary": "Create organization", "responses": { "201": { "description": "Created" } } }
    },
    "/api/platform/organizations/{slug}": {
      "parameters": [{ "$ref": "#/components/parameters/OrgSlug" }],
      "get": { "tags": ["Platform admin"], "summary": "Get organization", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "put": { "tags": ["Platform admin"], "summary": "Update organization", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Platform admin"], "summary": "Delete organization", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/platform/organizations/{slug}/suspend": {
      "parameters": [{ "$ref": "#/components/parameters/OrgSlug" }],
      "post": { "tags": ["Platform admin"], "summary": "Suspend organization", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/platform/organizations/{slug}/unsuspend": {
      "parameters": [{ "$ref": "#/components/parameters/OrgSlug" }],
      "post": { "tags": ["Platform admin"], "summary": "Un-suspend organization", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/platform/organizations/{slug}/impersonate": {
      "parameters": [{ "$ref": "#/components/parameters/OrgSlug" }],
      "post": { "tags": ["Platform admin"], "summary": "Impersonate organization (audit-logged)", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/platform/organizations/{slug}/audit-logs": {
      "parameters": [{ "$ref": "#/components/parameters/OrgSlug" }],
      "get": { "tags": ["Platform admin"], "summary": "Audit log for an organization", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/platform/organizations/{slug}/tenants": {
      "parameters": [{ "$ref": "#/components/parameters/OrgSlug" }],
      "get": { "tags": ["Platform admin"], "summary": "Tenants in an organization", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/platform/carriers": {
      "get": { "tags": ["Platform admin"], "summary": "List insurance carriers", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": { "tags": ["Platform admin"], "summary": "Create carrier", "responses": { "201": { "description": "Created" } } }
    },
    "/api/platform/carriers/{carrierId}": {
      "parameters": [{ "name": "carrierId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Platform admin"], "summary": "Get carrier", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "put": { "tags": ["Platform admin"], "summary": "Update carrier", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Platform admin"], "summary": "Delete carrier", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/platform/carriers/{carrierId}/users": {
      "parameters": [{ "name": "carrierId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Platform admin"], "summary": "List users of a carrier", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": { "tags": ["Platform admin"], "summary": "Create carrier user", "responses": { "201": { "description": "Created" } } }
    },
    "/api/platform/carriers/{carrierId}/users/{userId}": {
      "parameters": [
        { "name": "carrierId", "in": "path", "required": true, "schema": { "type": "string" } },
        { "name": "userId", "in": "path", "required": true, "schema": { "type": "string" } }
      ],
      "patch": { "tags": ["Platform admin"], "summary": "Update carrier user", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Platform admin"], "summary": "Delete carrier user", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/platform/carriers/{carrierId}/policies": {
      "parameters": [{ "name": "carrierId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Platform admin"], "summary": "Policies written by a carrier", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },

    "/api/org/users": {
      "get": { "tags": ["Org admin"], "summary": "List users in the caller's organization", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": { "tags": ["Org admin"], "summary": "Create user", "responses": { "201": { "description": "Created" } } }
    },
    "/api/org/users/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Org admin"], "summary": "Update user", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Org admin"], "summary": "Delete user", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/org/info": {
      "get": { "tags": ["Org admin"], "summary": "Organization metadata", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/org/audit-logs": {
      "get": { "tags": ["Org admin"], "summary": "Audit log for the caller's organization", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/org/settings/mfa-policy": {
      "patch": { "tags": ["Org admin"], "summary": "Update org-wide MFA policy", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/org/tenants": {
      "get": { "tags": ["Org admin"], "summary": "Tenants in the caller's organization", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": { "tags": ["Org admin"], "summary": "Create tenant in this organization", "responses": { "201": { "description": "Created" } } }
    },
    "/api/org/tenants/trends": {
      "get": { "tags": ["Org admin"], "summary": "Cross-tenant trend rollup for the org", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/org/tenants/{slug}": {
      "parameters": [{ "$ref": "#/components/parameters/TenantSlug" }],
      "put": { "tags": ["Org admin"], "summary": "Update tenant (org-scoped)", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Org admin"], "summary": "Delete tenant (org-scoped)", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/org/tenants/{slug}/impersonate": {
      "parameters": [{ "$ref": "#/components/parameters/TenantSlug" }],
      "post": { "tags": ["Org admin"], "summary": "Impersonate a tenant (audit-logged)", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/org/tenants/{slug}/users": {
      "parameters": [{ "$ref": "#/components/parameters/TenantSlug" }],
      "get": { "tags": ["Org admin"], "summary": "Users of a tenant", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": { "tags": ["Org admin"], "summary": "Create tenant user", "responses": { "201": { "description": "Created" } } }
    },
    "/api/org/tenants/{slug}/users/{userId}": {
      "parameters": [
        { "$ref": "#/components/parameters/TenantSlug" },
        { "name": "userId", "in": "path", "required": true, "schema": { "type": "string" } }
      ],
      "put": { "tags": ["Org admin"], "summary": "Update tenant user", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Org admin"], "summary": "Delete tenant user", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/org/tenants/{slug}/users/{userId}/set-password": {
      "parameters": [
        { "$ref": "#/components/parameters/TenantSlug" },
        { "name": "userId", "in": "path", "required": true, "schema": { "type": "string" } }
      ],
      "post": { "tags": ["Org admin"], "summary": "Force-set a tenant user's password", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/org/divisions/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Organization structure"], "summary": "Update division", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Organization structure"], "summary": "Delete division", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/org/business-units/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Organization structure"], "summary": "Update business unit", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Organization structure"], "summary": "Delete business unit", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/org/departments/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Organization structure"], "summary": "Update department", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Organization structure"], "summary": "Delete department", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/org/sites/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Organization structure"], "summary": "Update site", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Organization structure"], "summary": "Delete site", "responses": { "204": { "description": "Deleted" } } }
    },

    "/api/kri-sources": {
      "get": {
        "tags": ["KRIs & sources"],
        "summary": "List KRI sources for the current tenant",
        "responses": {
          "200": {
            "description": "OK",
            "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/KriSource" } } } }
          }
        }
      }
    },
    "/api/kri-sources/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": {
        "tags": ["KRIs & sources"],
        "summary": "Create or update a KRI source",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KriSource" } } }
        },
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KriSource" } } } } }
      },
      "delete": {
        "tags": ["KRIs & sources"],
        "summary": "Delete a KRI source",
        "responses": { "204": { "description": "Deleted" } }
      }
    },
    "/api/kri-sources/{id}/test": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": {
        "tags": ["Integrations"],
        "summary": "Probe a KRI source's connectivity without writing data",
        "description": "Invokes the connector's `test` method against the real vendor API. Used by the UI \"Test connection\" button.",
        "responses": {
          "200": {
            "description": "Probe result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean" },
                    "message": { "type": "string" }
                  },
                  "required": ["ok"]
                }
              }
            }
          }
        }
      }
    },
    "/api/kri-sources/{id}/run": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": {
        "tags": ["Integrations"],
        "summary": "Trigger an immediate connector run",
        "description": "Dispatches the connector synchronously. Returns `rowsWritten` / `rowsSkipped` summary once the run finishes (or the error that stopped it).",
        "responses": {
          "200": {
            "description": "Run finished",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/IntegrationRun" }
              }
            }
          },
          "502": { "description": "Vendor upstream error" }
        }
      }
    },
    "/api/kri-sources/{id}/runs": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": {
        "tags": ["Integrations"],
        "summary": "Recent runs for a source",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/IntegrationRun" }
                }
              }
            }
          }
        }
      }
    },
    "/api/integrations/catalog": {
      "get": {
        "tags": ["Integrations"],
        "summary": "Connector catalog",
        "description": "Returns the full registry of connectors available at server boot. Grouped by `sourceType` and keyed globally by `vendorId`.",
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/ConnectorCatalogEntry" }
                }
              }
            }
          }
        }
      }
    },

    "/api/kris": {
      "get": { "tags": ["KRIs & sources"], "summary": "List KRIs", "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Kri" } } } } } } }
    },
    "/api/kris/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["KRIs & sources"], "summary": "Create or update a KRI", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Kri" } } } }, "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/trend-history": {
      "get": { "tags": ["KRIs & sources"], "summary": "KRI trend history (timeseries)", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/risk-owner-trends": {
      "get": { "tags": ["KRIs & sources"], "summary": "KRI rollups by risk owner", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },

    "/api/controls": {
      "get": { "tags": ["Controls"], "summary": "List controls", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/controls/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Controls"], "summary": "Create or update a control", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Controls"], "summary": "Delete control", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/risks": {
      "get": { "tags": ["Risks"], "summary": "List risks", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/risks/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Risks"], "summary": "Create or update a risk", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Risks"], "summary": "Delete risk", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/outcomes": {
      "get": { "tags": ["Outcomes"], "summary": "List business outcomes", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/outcomes/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Outcomes"], "summary": "Create or update an outcome", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/enterprise-risk-mappings": {
      "get": { "tags": ["Risks"], "summary": "List enterprise-risk mappings", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/enterprise-risk-mappings/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Risks"], "summary": "Create or update an enterprise-risk mapping", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Risks"], "summary": "Delete enterprise-risk mapping", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/risk-owners": {
      "get": { "tags": ["Risks"], "summary": "List risk owners", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/risk-owners/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Risks"], "summary": "Create or update a risk owner", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Risks"], "summary": "Delete risk owner", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/stakeholders": {
      "get": { "tags": ["Risks"], "summary": "List stakeholders", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/stakeholders/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Risks"], "summary": "Create or update a stakeholder", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Risks"], "summary": "Delete stakeholder", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/app-users": {
      "get": { "tags": ["Org admin"], "summary": "List application users (tenant-scoped)", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/global-settings": {
      "get": { "tags": ["System"], "summary": "Tenant global settings", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "put": { "tags": ["System"], "summary": "Update tenant global settings", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },

    "/api/vendors": {
      "get": { "tags": ["Vendors & TPRM"], "summary": "List vendors", "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Vendor" } } } } } } }
    },
    "/api/vendors/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Vendors & TPRM"], "summary": "Create or update a vendor", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Vendor" } } } }, "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Vendors & TPRM"], "summary": "Delete vendor", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/vendor-assessments/{vendorId}": {
      "parameters": [{ "name": "vendorId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Assessments"], "summary": "Assessments for a vendor", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/assessments/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Assessments"], "summary": "Get assessment", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/assessments/{id}/step": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "patch": { "tags": ["Assessments"], "summary": "Advance or update assessment step", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/assessments/{id}/approve": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": { "tags": ["Assessments"], "summary": "Approve assessment", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/vendor-findings/{vendorId}": {
      "parameters": [{ "name": "vendorId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Vendors & TPRM"], "summary": "Findings for a vendor", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/vendor-findings/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Vendors & TPRM"], "summary": "Update a finding", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/vendor-decisions/{vendorId}": {
      "parameters": [{ "name": "vendorId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Vendors & TPRM"], "summary": "Decisions for a vendor", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/vendor-alerts": {
      "get": { "tags": ["Vendors & TPRM"], "summary": "All vendor alerts", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/vendor-alerts/{vendorId}": {
      "parameters": [{ "name": "vendorId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Vendors & TPRM"], "summary": "Alerts for a vendor", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/vendor-users": {
      "get": { "tags": ["Vendors & TPRM"], "summary": "List vendor users", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/vendor-users/{vendorId}": {
      "parameters": [{ "name": "vendorId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Vendors & TPRM"], "summary": "Users associated with a vendor", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/data-elements": {
      "get": { "tags": ["Vendors & TPRM"], "summary": "List data elements", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/integration-points": {
      "get": { "tags": ["Vendors & TPRM"], "summary": "List integration points", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/integration-points/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Vendors & TPRM"], "summary": "Update integration point", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Vendors & TPRM"], "summary": "Delete integration point", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/integration-points/vendor/{vendorId}": {
      "parameters": [{ "name": "vendorId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Vendors & TPRM"], "summary": "Integration points for a vendor", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/attested-integrations/{vendorId}": {
      "parameters": [{ "name": "vendorId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Vendors & TPRM"], "summary": "Attested integrations for a vendor", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/asset-inventory": {
      "get": { "tags": ["Vendors & TPRM"], "summary": "Asset inventory", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/playbooks/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Vendors & TPRM"], "summary": "Get playbook", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/playbooks/vendor/{vendorId}": {
      "parameters": [{ "name": "vendorId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Vendors & TPRM"], "summary": "Playbooks for a vendor", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/playbooks/generate/{integrationId}": {
      "parameters": [{ "name": "integrationId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": { "tags": ["Vendors & TPRM"], "summary": "Generate a playbook for an integration", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/blast-radius/vendor/{vendorId}": {
      "parameters": [{ "name": "vendorId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Vendors & TPRM"], "summary": "Blast radius for a vendor", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/blast-radius/data/{dataElementId}": {
      "parameters": [{ "name": "dataElementId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Vendors & TPRM"], "summary": "Blast radius for a data element", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/integration-drift/{vendorId}": {
      "parameters": [{ "name": "vendorId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Vendors & TPRM"], "summary": "Integration drift for a vendor", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },

    "/api/chat-messages/{stakeholderId}": {
      "parameters": [{ "name": "stakeholderId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Chat"], "summary": "Chat history for a stakeholder", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Chat"], "summary": "Clear chat history for a stakeholder", "responses": { "204": { "description": "Cleared" } } }
    },
    "/api/chat-documents/{stakeholderId}": {
      "parameters": [{ "name": "stakeholderId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Chat"], "summary": "Documents attached to a chat", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": {
        "tags": ["Chat"],
        "summary": "Upload a document into a chat",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": { "file": { "type": "string", "format": "binary" } },
                "required": ["file"]
              }
            }
          }
        },
        "responses": { "201": { "description": "Uploaded" } }
      }
    },
    "/api/chat-documents/{stakeholderId}/{docId}": {
      "parameters": [
        { "name": "stakeholderId", "in": "path", "required": true, "schema": { "type": "string" } },
        { "name": "docId", "in": "path", "required": true, "schema": { "type": "string" } }
      ],
      "delete": { "tags": ["Chat"], "summary": "Delete a chat document", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/chat": {
      "post": {
        "tags": ["Chat"],
        "summary": "Send a message to an expert persona",
        "description": "Streams a response from the selected persona (AI vCISO, Privacy, TPRM, Cyber Insurance). Response is JSON by default; set `Accept: text/event-stream` for SSE.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["message"],
                "properties": {
                  "personaId": { "type": "string" },
                  "stakeholderId": { "type": "string" },
                  "message": { "type": "string" },
                  "sessionId": { "type": "string", "format": "uuid" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reply",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "reply": { "type": "string" } } } } }
          }
        }
      }
    },
    "/api/personas": {
      "get": { "tags": ["Expert panel"], "summary": "Available personas", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/personas/{personaId}": {
      "parameters": [{ "name": "personaId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Expert panel"], "summary": "Get persona", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/panel-sessions": {
      "get": { "tags": ["Expert panel"], "summary": "List panel sessions", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": { "tags": ["Expert panel"], "summary": "Create a panel session", "responses": { "201": { "description": "Created" } } }
    },
    "/api/panel-sessions/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Expert panel"], "summary": "Get panel session", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "patch": { "tags": ["Expert panel"], "summary": "Update panel session", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/panel-sessions/{id}/documents": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Expert panel"], "summary": "List panel session documents", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": {
        "tags": ["Expert panel"],
        "summary": "Upload document to a panel session",
        "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "file": { "type": "string", "format": "binary" } }, "required": ["file"] } } } },
        "responses": { "201": { "description": "Uploaded" } }
      }
    },
    "/api/panel-sessions/{id}/documents/{docId}": {
      "parameters": [
        { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } },
        { "name": "docId", "in": "path", "required": true, "schema": { "type": "string" } }
      ],
      "delete": { "tags": ["Expert panel"], "summary": "Delete panel session document", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/panel-sessions/{id}/end": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": { "tags": ["Expert panel"], "summary": "End panel session", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/panel-sessions/{id}/messages": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": { "tags": ["Expert panel"], "summary": "Post a message to the panel", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/panel-sessions/{id}/synthesize": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": { "tags": ["Expert panel"], "summary": "Generate the panel's synthesis", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/panel-sessions/{id}/audit": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Expert panel"], "summary": "Panel session audit trail", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/panel-sessions/{id}/transcript": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Expert panel"], "summary": "Panel session transcript", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },

    "/api/institutional-knowledge": {
      "get": { "tags": ["Institutional knowledge"], "summary": "List institutional knowledge entries", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "put": { "tags": ["Institutional knowledge"], "summary": "Upsert institutional knowledge", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/institutional-documents": {
      "get": { "tags": ["Institutional knowledge"], "summary": "List institutional documents", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": {
        "tags": ["Institutional knowledge"],
        "summary": "Upload an institutional document",
        "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "file": { "type": "string", "format": "binary" } }, "required": ["file"] } } } },
        "responses": { "201": { "description": "Uploaded" } }
      }
    },
    "/api/institutional-documents/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "patch": { "tags": ["Institutional knowledge"], "summary": "Update document metadata", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Institutional knowledge"], "summary": "Delete document", "responses": { "204": { "description": "Deleted" } } }
    },

    "/api/onboarding-status": {
      "get": { "tags": ["Chat"], "summary": "Onboarding progress", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/onboarding-skip": {
      "post": { "tags": ["Chat"], "summary": "Skip onboarding", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/onboarding-chat": {
      "post": { "tags": ["Chat"], "summary": "Chat with the onboarding agent", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },

    "/api/workflows": {
      "get": { "tags": ["Workflows"], "summary": "List workflows", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": { "tags": ["Workflows"], "summary": "Create workflow", "responses": { "201": { "description": "Created" } } }
    },
    "/api/workflows/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Workflows"], "summary": "Get workflow", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "patch": { "tags": ["Workflows"], "summary": "Update workflow", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Workflows"], "summary": "Delete workflow", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/workflows/{id}/activate": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": { "tags": ["Workflows"], "summary": "Activate workflow", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/workflows/{id}/pause": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": { "tags": ["Workflows"], "summary": "Pause workflow", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/workflows/{id}/archive": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": { "tags": ["Workflows"], "summary": "Archive workflow", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/workflows/{id}/trigger-logs": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Workflows"], "summary": "Workflow trigger log history", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/workflows/{id}/change-log": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Workflows"], "summary": "Workflow change log", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/workflow-interviews": {
      "post": { "tags": ["Workflows"], "summary": "Start a workflow interview", "responses": { "201": { "description": "Created" } } }
    },
    "/api/workflow-interviews/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Workflows"], "summary": "Get a workflow interview", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/workflow-interviews/{id}/message": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": { "tags": ["Workflows"], "summary": "Send a message in a workflow interview", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/workflow-interviews/{id}/confirm": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": { "tags": ["Workflows"], "summary": "Confirm interview and create workflow", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/workflow-interviews/{id}/abandon": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": { "tags": ["Workflows"], "summary": "Abandon interview", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/workflow-versions/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Workflows"], "summary": "Update workflow version", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/workflow-kri-definitions/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Workflows"], "summary": "Update workflow KRI definition", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Workflows"], "summary": "Delete workflow KRI definition", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/workflow-kri-events": {
      "get": { "tags": ["Workflows"], "summary": "List workflow KRI events", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": { "tags": ["Workflows"], "summary": "Record a workflow KRI event", "responses": { "201": { "description": "Created" } } }
    },
    "/api/workflow-agent-messages/{workflowId}": {
      "parameters": [{ "name": "workflowId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Workflows"], "summary": "Workflow agent chat history", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/workflow-agent-chat": {
      "post": { "tags": ["Workflows"], "summary": "Chat with the workflow agent", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/relay-config": {
      "get": { "tags": ["Workflows"], "summary": "Get relay configuration", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "put": { "tags": ["Workflows"], "summary": "Update relay configuration", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/infrastructure/readiness": {
      "get": { "tags": ["System"], "summary": "Infrastructure readiness probe", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },

    "/api/crse/templates": {
      "get": { "tags": ["CRSE"], "summary": "Simulation templates", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/crse/target-options": {
      "get": { "tags": ["CRSE"], "summary": "Valid targets for simulations", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/crse/simulations": {
      "get": { "tags": ["CRSE"], "summary": "List simulation runs", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": { "tags": ["CRSE"], "summary": "Start a simulation run", "responses": { "202": { "description": "Accepted" } } }
    },
    "/api/crse/simulations/{runId}": {
      "parameters": [{ "name": "runId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["CRSE"], "summary": "Get simulation run", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["CRSE"], "summary": "Delete simulation run", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/crse/chains": {
      "get": { "tags": ["CRSE"], "summary": "List chains", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": { "tags": ["CRSE"], "summary": "Create chain", "responses": { "201": { "description": "Created" } } }
    },
    "/api/crse/chains/{chainId}": {
      "parameters": [{ "name": "chainId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["CRSE"], "summary": "Get chain", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["CRSE"], "summary": "Delete chain", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/crse/chains/{chainId}/run": {
      "parameters": [{ "name": "chainId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": { "tags": ["CRSE"], "summary": "Run chain", "responses": { "202": { "description": "Accepted" } } }
    },
    "/api/crse/chains/auto-generate": {
      "post": { "tags": ["CRSE"], "summary": "Auto-generate chains", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/crse/blast-radius": {
      "get": { "tags": ["CRSE"], "summary": "CRSE blast-radius summary", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/crse/loss-parameters/templates": {
      "get": { "tags": ["CRSE"], "summary": "Loss parameter templates", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/crse/loss-parameters/overrides": {
      "put": { "tags": ["CRSE"], "summary": "Upsert loss parameter overrides", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/crse/loss-parameters/override": {
      "get": { "tags": ["CRSE"], "summary": "Read a loss parameter override", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/crse/controls/{controlId}/mitre-mappings": {
      "parameters": [{ "name": "controlId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["CRSE"], "summary": "MITRE mappings for a control", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": { "tags": ["CRSE"], "summary": "Add MITRE mappings to a control", "responses": { "201": { "description": "Created" } } }
    },
    "/api/crse/mitre-mappings/{id}": {
      "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
      "patch": { "tags": ["CRSE"], "summary": "Update MITRE mapping", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["CRSE"], "summary": "Delete MITRE mapping", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/crse/mitre/techniques": {
      "get": { "tags": ["CRSE"], "summary": "MITRE ATT&CK techniques (reference data)", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/crse/regulatory-fine-models": {
      "get": { "tags": ["CRSE"], "summary": "Regulatory fine models", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/crse/data-collections": {
      "get": { "tags": ["CRSE"], "summary": "Data collections for CRSE", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/crse/toxic-combinations": {
      "get": { "tags": ["CRSE"], "summary": "Toxic combinations", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },

    "/api/public/workflow/{token}": {
      "parameters": [{ "name": "token", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": {
        "tags": ["Public"],
        "summary": "Unauthenticated workflow preview by share token",
        "security": [],
        "responses": { "200": { "$ref": "#/components/responses/OK" } }
      }
    },

    "/api/tenant/carrier-consent": {
      "get": { "tags": ["Carrier portal"], "summary": "List carrier consent decisions for this tenant", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/tenant/carrier-consent/{policyId}": {
      "parameters": [{ "name": "policyId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "patch": { "tags": ["Carrier portal"], "summary": "Update carrier consent for a policy", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },

    "/api/carrier/auth/login": {
      "post": {
        "tags": ["Carrier portal"],
        "summary": "Login to the carrier portal",
        "security": [],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["email", "password"], "properties": { "email": { "type": "string", "format": "email" }, "password": { "type": "string" } } } } } },
        "responses": { "200": { "$ref": "#/components/responses/OK" } }
      }
    },
    "/api/carrier/auth/me": {
      "get": { "tags": ["Carrier portal"], "summary": "Current carrier user", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/carrier/portfolio": {
      "get": { "tags": ["Carrier portal"], "summary": "Portfolio overview", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/carrier/portfolio/distribution": {
      "get": { "tags": ["Carrier portal"], "summary": "Portfolio risk distribution", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/carrier/policies": {
      "post": { "tags": ["Carrier portal"], "summary": "Create a policy", "responses": { "201": { "description": "Created" } } }
    },
    "/api/carrier/policies/{policyId}": {
      "parameters": [{ "name": "policyId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Carrier portal"], "summary": "Get policy", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/carrier/policies/{policyId}/snapshots": {
      "parameters": [{ "name": "policyId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Carrier portal"], "summary": "Policy risk snapshots", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/carrier/policies/{policyId}/brief": {
      "parameters": [{ "name": "policyId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": { "tags": ["Carrier portal"], "summary": "Generate underwriting brief", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/carrier/policies/{policyId}/briefs": {
      "parameters": [{ "name": "policyId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "get": { "tags": ["Carrier portal"], "summary": "List underwriting briefs", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/carrier/alerts": {
      "get": { "tags": ["Carrier portal"], "summary": "List portfolio alerts", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/carrier/alerts/{alertId}": {
      "parameters": [{ "name": "alertId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "patch": { "tags": ["Carrier portal"], "summary": "Ack or resolve an alert", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/carrier/alert-rules": {
      "get": { "tags": ["Carrier portal"], "summary": "List alert rules", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": { "tags": ["Carrier portal"], "summary": "Create alert rule", "responses": { "201": { "description": "Created" } } }
    },
    "/api/carrier/alert-rules/{ruleId}": {
      "parameters": [{ "name": "ruleId", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": { "tags": ["Carrier portal"], "summary": "Update alert rule", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "delete": { "tags": ["Carrier portal"], "summary": "Delete alert rule", "responses": { "204": { "description": "Deleted" } } }
    },
    "/api/carrier/renewals": {
      "get": { "tags": ["Carrier portal"], "summary": "Upcoming renewals", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/carrier/actuarial/export": {
      "post": { "tags": ["Carrier portal"], "summary": "Start an actuarial export", "responses": { "202": { "description": "Accepted" } } }
    },
    "/api/carrier/actuarial/exports": {
      "get": { "tags": ["Carrier portal"], "summary": "List actuarial exports", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/carrier/ai-analysis": {
      "post": { "tags": ["Carrier portal"], "summary": "Run carrier AI analysis", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/carrier/underwriting-criteria": {
      "get": { "tags": ["Carrier portal"], "summary": "Get underwriting criteria", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "put": { "tags": ["Carrier portal"], "summary": "Update underwriting criteria", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/carrier/settings": {
      "get": { "tags": ["Carrier portal"], "summary": "Carrier settings", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    },
    "/api/carrier/users": {
      "get": { "tags": ["Carrier portal"], "summary": "Carrier users", "responses": { "200": { "$ref": "#/components/responses/OK" } } },
      "post": { "tags": ["Carrier portal"], "summary": "Create carrier user", "responses": { "201": { "description": "Created" } } }
    },
    "/api/carrier/available-tenants": {
      "get": { "tags": ["Carrier portal"], "summary": "Tenants consenting to share data with this carrier", "responses": { "200": { "$ref": "#/components/responses/OK" } } }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Short-lived (15 min) JWT obtained from `/api/auth/login` or `/api/auth/refresh`. Sent as `Authorization: Bearer <token>`."
      }
    },
    "parameters": {
      "TenantSlug": {
        "name": "slug",
        "in": "path",
        "required": true,
        "description": "Tenant slug (lowercase, hyphen-separated).",
        "schema": { "type": "string", "pattern": "^[a-z0-9-]+$" }
      },
      "OrgSlug": {
        "name": "slug",
        "in": "path",
        "required": true,
        "description": "Organization slug.",
        "schema": { "type": "string", "pattern": "^[a-z0-9-]+$" }
      }
    },
    "responses": {
      "OK": {
        "description": "OK",
        "content": { "application/json": { "schema": { "type": "object" } } }
      },
      "Unauthorized": {
        "description": "Unauthorized — missing, expired, or invalid JWT.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Forbidden": {
        "description": "Forbidden — caller lacks the required role or permission.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "NotFound": {
        "description": "Not found",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "RateLimited": {
        "description": "Too many requests — retry after the `Retry-After` header.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string" },
          "code": { "type": "string" },
          "details": { "type": "object", "additionalProperties": true }
        },
        "required": ["error"]
      },
      "AuthSuccess": {
        "type": "object",
        "description": "Successful authentication response.",
        "properties": {
          "token": { "type": "string", "description": "JWT access token." },
          "expiresIn": { "type": "integer", "description": "Seconds until token expiry." },
          "user": { "$ref": "#/components/schemas/User" }
        },
        "required": ["token", "user"]
      },
      "MfaChallenge": {
        "type": "object",
        "description": "Password accepted, MFA code required to finish login.",
        "properties": {
          "mfaRequired": { "type": "boolean", "const": true },
          "mfaToken": { "type": "string" }
        },
        "required": ["mfaRequired", "mfaToken"]
      },
      "User": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "email": { "type": "string", "format": "email" },
          "firstName": { "type": "string" },
          "lastName": { "type": "string" },
          "role": { "type": "string", "enum": ["superadmin", "master_admin", "tenant_admin", "tenant_user", "carrier_admin", "carrier_user"] },
          "organizationSlug": { "type": "string", "nullable": true },
          "tenantSlug": { "type": "string", "nullable": true },
          "mfaEnabled": { "type": "boolean" }
        },
        "required": ["id", "email", "role"]
      },
      "Tenant": {
        "type": "object",
        "properties": {
          "slug": { "type": "string" },
          "name": { "type": "string" },
          "organizationSlug": { "type": "string", "nullable": true },
          "createdAt": { "type": "string", "format": "date-time" }
        },
        "required": ["slug", "name"]
      },
      "Kri": {
        "type": "object",
        "description": "A Key Risk Indicator.",
        "properties": {
          "id": { "type": "string" },
          "slug": { "type": "string", "description": "Stable identifier used by connectors to update values." },
          "name": { "type": "string" },
          "description": { "type": "string" },
          "sourceId": { "type": "string", "description": "ID of the `kri_source` that writes values." },
          "value": { "type": "number" },
          "threshold": {
            "type": "object",
            "properties": {
              "warn": { "type": "number" },
              "critical": { "type": "number" },
              "direction": { "type": "string", "enum": ["higher-is-worse", "lower-is-worse"] }
            }
          },
          "updatedAt": { "type": "string", "format": "date-time" }
        },
        "required": ["slug", "name"]
      },
      "KriSource": {
        "type": "object",
        "description": "A tenant-specific connection to a data source (one row per configured integration).",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "sourceType": { "type": "string", "example": "vulnerability" },
          "vendorId": { "type": "string", "example": "tenable-io" },
          "apiEndpoint": { "type": "string", "format": "uri" },
          "authType": { "type": "string", "enum": ["api-key", "oauth2", "basic", "none"] },
          "scheduleKind": { "type": "string", "enum": ["daily", "hourly", "manual"] },
          "extraConfigJson": { "type": "string", "nullable": true, "description": "Stringified JSON for non-secret per-connector config." },
          "lastRunAt": { "type": "string", "format": "date-time", "nullable": true },
          "lastRunStatus": { "type": "string", "enum": ["ok", "error", "unknown"] }
        },
        "required": ["name", "sourceType", "vendorId"]
      },
      "ConnectorCatalogEntry": {
        "type": "object",
        "description": "A connector registered in the server boot registry.",
        "properties": {
          "sourceType": { "type": "string" },
          "vendorId": { "type": "string" },
          "vendorLabel": { "type": "string" },
          "defaults": {
            "type": "object",
            "properties": {
              "apiEndpoint": { "type": "string", "nullable": true },
              "apiEndpointHint": { "type": "string", "nullable": true },
              "authType": { "type": "string", "enum": ["api-key", "oauth2", "basic", "none"] },
              "scheduleKind": { "type": "string", "enum": ["daily", "hourly", "manual"] },
              "extraConfigJson": { "type": "string", "nullable": true }
            }
          }
        },
        "required": ["sourceType", "vendorId", "vendorLabel"]
      },
      "IntegrationRun": {
        "type": "object",
        "description": "A single dispatcher run of a connector.",
        "properties": {
          "id": { "type": "string" },
          "sourceId": { "type": "string" },
          "status": { "type": "string", "enum": ["ok", "error", "running"] },
          "trigger": { "type": "string", "enum": ["schedule", "manual"] },
          "startedAt": { "type": "string", "format": "date-time" },
          "finishedAt": { "type": "string", "format": "date-time", "nullable": true },
          "rowsWritten": { "type": "integer" },
          "rowsSkipped": { "type": "integer" },
          "error": { "type": "string", "nullable": true },
          "summary": { "type": "object", "additionalProperties": true }
        },
        "required": ["id", "sourceId", "status", "startedAt"]
      },
      "Vendor": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "category": { "type": "string" },
          "criticality": { "type": "string", "enum": ["low", "medium", "high", "critical"] },
          "dataElements": { "type": "array", "items": { "type": "string" } },
          "contacts": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "name": { "type": "string" } } } }
        },
        "required": ["name"]
      }
    }
  }
}
