{
  "openapi": "3.1.0",
  "info": {
    "title": "Strac Comply API",
    "version": "v1",
    "description": "REST API for Strac Comply. Authenticate every request with a Personal Access Token in the `Authorization: Bearer strac_pat_…` header (mint one via `POST /api/companies/{companyId}/pats`, which is Cognito-authenticated). The MCP server at mcp.comply.strac.io exposes the same data as JSON-RPC tools and is documented separately at /docs/mcp."
  },
  "servers": [
    {
      "url": "https://comply.strac.io",
      "description": "comply.strac.io"
    }
  ],
  "tags": [
    {
      "name": "Tokens"
    },
    {
      "name": "Frameworks"
    },
    {
      "name": "Controls"
    },
    {
      "name": "Policies"
    },
    {
      "name": "Documents"
    },
    {
      "name": "Audits"
    },
    {
      "name": "Tests"
    },
    {
      "name": "Personnel"
    },
    {
      "name": "Audit Log"
    }
  ],
  "components": {
    "securitySchemes": {
      "patBearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Personal Access Token (`strac_pat_*`). Mint via POST /api/companies/{companyId}/pats. The token is scoped; each operation lists its required scope."
      },
      "cognitoIdToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "Cognito ID token. Used only to mint and manage PATs — you cannot mint a PAT with a PAT."
      }
    }
  },
  "paths": {
    "/api/companies/{companyId}/pats": {
      "post": {
        "operationId": "patMint",
        "summary": "Mint a Personal Access Token",
        "description": "Create a PAT for the REST API. Cognito-authenticated (you cannot mint a PAT with a PAT). The plaintext token is returned exactly once. Owners/admins can mint any scope; members and viewers can mint read-only scopes only.\n\nRole gate: owner / admin (to mint write scopes).\n\nScope: `any`.",
        "tags": [
          "Tokens"
        ],
        "security": [
          {
            "cognitoIdToken": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string",
                    "description": "Shows in the admin UI and the audit log."
                  },
                  "scopes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Least-privilege scope set; each must be a canonical scope."
                  },
                  "expiresInDays": {
                    "type": "integer",
                    "enum": [
                      0,
                      30,
                      90,
                      365
                    ],
                    "description": "Token lifetime in days. 0 = never expires (service accounts)."
                  }
                },
                "required": [
                  "label",
                  "scopes",
                  "expiresInDays"
                ]
              },
              "example": {
                "label": "CI deploy bot",
                "scopes": [
                  "compliance:read",
                  "documents:write"
                ],
                "expiresInDays": 90
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Mint a Personal Access Token",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "token": "strac_pat_xxxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxx",
                    "pat": {
                      "patId": "<sha256-hash>",
                      "prefix": "strac_pat_a1b2",
                      "label": "CI deploy bot",
                      "scope": "compliance:read documents:write",
                      "expiresAt": 1787616000,
                      "email": "ci@example.com",
                      "createdAt": "2026-05-27T08:18:14.536Z",
                      "createdBy": "ci@example.com",
                      "lastUsedAt": null,
                      "revokedAt": null,
                      "status": "active"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "patList",
        "summary": "List Personal Access Tokens",
        "description": "Returns token metadata only — never the secret. Owners/admins see every PAT in the org; members and viewers see only their own.\n\nScope: `any`.",
        "tags": [
          "Tokens"
        ],
        "security": [
          {
            "cognitoIdToken": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List Personal Access Tokens",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "pats": [
                      {
                        "patId": "<sha256-hash>",
                        "prefix": "strac_pat_a1b2",
                        "label": "CI deploy bot",
                        "scope": "compliance:read documents:write",
                        "expiresAt": 1787616000,
                        "email": "ci@example.com",
                        "createdAt": "2026-05-27T08:18:14.536Z",
                        "createdBy": "ci@example.com",
                        "lastUsedAt": "2026-05-27T15:00:00.000Z",
                        "revokedAt": null,
                        "status": "active"
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/companies/{companyId}/pats/{patId}/revoke": {
      "post": {
        "operationId": "patRevoke",
        "summary": "Revoke a Personal Access Token",
        "description": "Soft-revoke (the row is preserved for the audit trail). The PAT stops working on the next request — no grace period. The optional reason lands in the audit log.\n\nRole gate: owner / admin (or the token owner).\n\nScope: `any`.",
        "tags": [
          "Tokens"
        ],
        "security": [
          {
            "cognitoIdToken": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "patId",
            "in": "path",
            "required": true,
            "description": "The PAT id (sha256 hash), not the plaintext token.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "description": "Why the token was revoked (e.g. rotation, offboarding)."
                  }
                }
              },
              "example": {
                "reason": "rotation"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Revoke a Personal Access Token",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "revoked": true,
                    "alreadyRevoked": false,
                    "patId": "<sha256-hash>"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/frameworks": {
      "get": {
        "operationId": "frameworksList",
        "summary": "List framework controls",
        "description": "Returns the control catalog across active frameworks (or one framework via `?framework=`). Global, not tenant-scoped — a valid bearer is required to discourage scraping.\n\nScope: `compliance:read`.",
        "tags": [
          "Frameworks"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "framework",
            "in": "query",
            "required": false,
            "description": "Filter to one framework id (e.g. soc2). Omit for all.",
            "schema": {
              "type": "string",
              "default": "all"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List framework controls",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "framework": "all",
                  "controls": [
                    {
                      "id": "soc2-cc6.1",
                      "frameworkId": "soc2",
                      "controlId": "CC6.1",
                      "title": "Logical access controls",
                      "category": "Logical & Physical Access",
                      "riskLevel": "high"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/controls": {
      "get": {
        "operationId": "controlsList",
        "summary": "List controls with completion",
        "description": "All controls for the company with completion % and the binary readiness signal.\n\nScope: `compliance:read`.",
        "tags": [
          "Controls"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "framework",
            "in": "query",
            "required": false,
            "description": "Filter by framework id (e.g. soc2).",
            "schema": {
              "type": "string",
              "default": "all"
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Filter by control category (exact match on the category field).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Exact-match on the workflow status label (URL-encode the space). NOT about people: Unassigned/Assigned/Needs reassignment track whether the control has TESTS linked to it, not who owns it — human ownership is the separate `assignedTo` field. Needs evidence and In progress are derived at read time from a stored Completed that readiness contradicts, so they never appear in stored data. The readiness signal is the separate `auditReadiness` field.",
            "schema": {
              "type": "string",
              "enum": [
                "Unassigned",
                "Assigned",
                "Needs reassignment",
                "In progress",
                "Needs evidence",
                "Completed"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List controls with completion",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "count": 1,
                  "data": [
                    {
                      "id": "soc2-cc6.1",
                      "title": "Logical access controls",
                      "category": "Logical & Physical Access",
                      "status": "Needs evidence",
                      "framework": "SOC 2",
                      "frameworkId": "soc2",
                      "frameworkReference": "CC6.1",
                      "notApplicable": false,
                      "completionPercentage": 67,
                      "auditReadiness": "gap",
                      "testsPassed": 4,
                      "testsTotal": 5,
                      "linkedTestCount": 5,
                      "linkedPolicyCount": 1,
                      "linkedDocumentCount": 1,
                      "requiredTotal": 3,
                      "requiredMissing": 1,
                      "riskLevel": "high"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/controls/{controlId}": {
      "get": {
        "operationId": "controlDetail",
        "summary": "One control + evidence summary",
        "description": "A single control with its linked tests, policies, documents, and any Not-Applicable metadata.\n\nScope: `compliance:read`.",
        "tags": [
          "Controls"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "controlId",
            "in": "path",
            "required": true,
            "description": "Control id, e.g. CC6.1. URL-encode `#` as %23.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One control + evidence summary",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "id": "soc2-cc6.1",
                    "title": "Logical access controls",
                    "description": "The entity implements logical access security controls...",
                    "category": "Logical & Physical Access",
                    "status": "Needs evidence",
                    "framework": "SOC2",
                    "frameworkId": "soc2",
                    "frameworkReference": "CC6.1",
                    "completionPercentage": 67,
                    "auditReadiness": "gap",
                    "auditGaps": [
                      "No approved access-review policy within the review window"
                    ],
                    "testsPassed": 4,
                    "testsTotal": 5,
                    "notApplicable": false,
                    "markedNAAt": null,
                    "markedNABy": null,
                    "linkedTests": [
                      {
                        "testId": "aws-s3-encryption",
                        "name": "S3 Encryption Check",
                        "status": "failing"
                      }
                    ],
                    "linkedPolicies": [
                      {
                        "policyId": "POL-SEC-001",
                        "name": "Information Security Policy"
                      }
                    ],
                    "linkedDocuments": [
                      {
                        "documentId": "DOC-CC1-ORG-CHART",
                        "title": "Company Organization Chart"
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/controls/summary": {
      "get": {
        "operationId": "controlsSummary",
        "summary": "Framework rollup",
        "description": "Org-wide rollup: per-framework control counts + the tests / policies / documents / integrations evidence dimensions, plus overall totals. Can take 5–30s on large tenants. Two keys describe how the numbers were computed: `percentageBasis: \"audit-ready-controls\"` means every `percentage` is a ready-controls ratio (completed / applicable), not an evidence-weighted average; `personnelSignalBasis: \"not-evaluated\"` means this endpoint did not resolve the personnel background-check signal, so a control whose required background-check evidence would be credited from your People view reads unmet here while `GET /controls` — which does resolve it — may show it satisfied. Expect the two endpoints to differ by that amount if you have no background-check integration.\n\nScope: `compliance:read`.",
        "tags": [
          "Controls"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Framework rollup",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "frameworks": [
                      {
                        "frameworkId": "SOC2",
                        "total": 64,
                        "completed": 40,
                        "percentage": 65,
                        "percentageBasis": "audit-ready-controls",
                        "applicable": 62,
                        "notApplicable": 2,
                        "totalTests": 120,
                        "passingTests": 102,
                        "failingTests": 18,
                        "policies": {
                          "total": 14,
                          "approved": 11,
                          "needsAttention": 3
                        },
                        "documents": {
                          "total": 79,
                          "needsAttention": 12
                        },
                        "training": {
                          "completed": 18,
                          "assigned": 20,
                          "applicable": true
                        }
                      }
                    ],
                    "tests": {
                      "total": 120,
                      "passing": 102,
                      "failing": 18,
                      "errors": 0
                    },
                    "policies": {
                      "total": 14,
                      "approved": 11,
                      "needsAttention": 3
                    },
                    "integrations": {
                      "total": 3,
                      "connected": 3
                    },
                    "documents": {
                      "total": 79,
                      "needsAttention": 12
                    },
                    "total": 64,
                    "completed": 40,
                    "averageCompletion": 65,
                    "percentageBasis": "audit-ready-controls",
                    "personnelSignalBasis": "not-evaluated"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/controls/{controlId}/mark-na": {
      "post": {
        "operationId": "controlMarkNa",
        "summary": "Mark a control Not Applicable",
        "description": "Marks a control N/A with a reason. Writes an append-only audit-log row (`v1_mark_control_na`).\n\nRole gate: owner / admin.\n\nScope: `evidence:write`.",
        "tags": [
          "Controls"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "controlId",
            "in": "path",
            "required": true,
            "description": "Control id, e.g. CC6.1.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "description": "Why the control does not apply (the auditor sees this)."
                  }
                },
                "required": [
                  "reason"
                ]
              },
              "example": {
                "reason": "No customer-managed laptops; access is via SSO-only managed devices."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Mark a control Not Applicable",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "markedNAAt": "2026-05-27T16:00:00.000Z",
                    "markedNABy": "admin@example.com"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/controls/{controlId}/restore": {
      "post": {
        "operationId": "controlRestore",
        "summary": "Restore an N/A control to applicable",
        "description": "Reverses a Not-Applicable marking. Writes an audit-log row (`v1_unmark_control_na`).\n\nRole gate: owner / admin.\n\nScope: `evidence:write`.",
        "tags": [
          "Controls"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "controlId",
            "in": "path",
            "required": true,
            "description": "Control id, e.g. CC6.1.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Restore an N/A control to applicable",
            "content": {
              "application/json": {
                "example": {
                  "success": true
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/policies": {
      "get": {
        "operationId": "policiesList",
        "summary": "List policies + status",
        "description": "All policies with lifecycle status and review dates. `lifecycleStatus === \"published\"` is the signal that a policy is approved audit/portal evidence.\n\nScope: `policies:read`.",
        "tags": [
          "Policies"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "framework",
            "in": "query",
            "required": false,
            "description": "Filter by framework.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List policies + status",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "POL-SEC-001",
                      "policyId": "POL-SEC-001",
                      "title": "Information Security Policy",
                      "framework": [
                        "SOC 2"
                      ],
                      "status": "compliant",
                      "lifecycleStatus": "published",
                      "currentVersion": "<version-uuid>",
                      "lastReviewDate": "2026-02-27T00:00:00.000Z",
                      "nextReviewDate": "2027-02-27T00:00:00.000Z",
                      "assignedTo": "ciso@example.com"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/policies/{policyId}": {
      "get": {
        "operationId": "policyDetail",
        "summary": "One policy + version history",
        "description": "A single policy with its full version list (status, uploader, format, approval metadata).\n\nScope: `policies:read`.",
        "tags": [
          "Policies"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "policyId",
            "in": "path",
            "required": true,
            "description": "Policy id, e.g. POL-SEC-001.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One policy + version history",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "id": "POL-SEC-001",
                    "policyId": "POL-SEC-001",
                    "title": "Information Security Policy",
                    "framework": [
                      "SOC 2"
                    ],
                    "lifecycleStatus": "published",
                    "currentVersion": "<version-uuid>",
                    "currentVersionNumber": 3,
                    "linkedControls": [
                      "CC6.1",
                      "CC7.2"
                    ],
                    "versions": [
                      {
                        "id": "<version-uuid>",
                        "version": 3,
                        "status": "approved",
                        "uploadedAt": "2026-02-20T00:00:00.000Z",
                        "uploadedBy": "ciso@example.com",
                        "fileName": "infosec-policy-v3.pdf",
                        "contentFormat": "pdf",
                        "approvedAt": "2026-02-27T00:00:00.000Z",
                        "approvedBy": "ceo@example.com"
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/policies/{policyId}/versions": {
      "post": {
        "operationId": "policyUploadVersion",
        "summary": "Upload a new policy version (draft)",
        "description": "Uploads a new version as a draft. Send the file base64-encoded (≤4 MB raw). Writes audit-log row `v1_upload_policy`.\n\nRole gate: owner / admin.\n\nScope: `policies:write`.",
        "tags": [
          "Policies"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "policyId",
            "in": "path",
            "required": true,
            "description": "Policy id, e.g. POL-SEC-001.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "fileName": {
                    "type": "string",
                    "description": "File name with extension (.pdf, .docx, .doc)."
                  },
                  "fileContent": {
                    "type": "string",
                    "description": "Base64-encoded file bytes, ≤4 MB raw."
                  },
                  "comments": {
                    "type": "string",
                    "description": "Optional changelog note for this version."
                  }
                },
                "required": [
                  "fileName",
                  "fileContent"
                ]
              },
              "example": {
                "fileName": "infosec-policy-v4.pdf",
                "fileContent": "JVBERi0xLjcK...<base64>",
                "comments": "Annual review update"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Upload a new policy version (draft)",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "id": "<version-uuid>",
                    "policyId": "POL-SEC-001",
                    "version": 4,
                    "status": "draft",
                    "uploadedAt": "2026-05-27T16:00:00.000Z",
                    "uploadedBy": "ciso@example.com",
                    "fileName": "infosec-policy-v4.pdf",
                    "contentFormat": "pdf"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/policies/{policyId}/versions/{versionId}/approve": {
      "post": {
        "operationId": "policyApprove",
        "summary": "Approve a draft version → published",
        "description": "Approves a draft policy version, flipping the policy to `published`. Writes audit-log row `v1_approve_policy`.\n\nRole gate: owner / admin.\n\nScope: `policies:approve`.",
        "tags": [
          "Policies"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "policyId",
            "in": "path",
            "required": true,
            "description": "Policy id, e.g. POL-SEC-001.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "versionId",
            "in": "path",
            "required": true,
            "description": "The draft version id to approve.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Approve a draft version → published",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Policy version approved successfully"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/documents": {
      "get": {
        "operationId": "documentsList",
        "summary": "List catalog documents + status",
        "description": "The canonical SOC 2 document catalog with control mappings and lifecycle status. Only `published` docs within their review window count toward completion.\n\nScope: `documents:read`.",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List catalog documents + status",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "DOC-CC1-ORG-CHART",
                      "name": "Organization Chart",
                      "frameworks": [
                        "SOC 2"
                      ],
                      "controlMappings": [
                        {
                          "controlId": "CC1.1",
                          "framework": "SOC 2",
                          "evidenceType": "required"
                        }
                      ],
                      "lifecycleStatus": "published",
                      "currentVersionId": "<version-uuid>",
                      "publishedAt": "2026-05-01T00:00:00.000Z",
                      "nextReviewDate": "2026-08-01T00:00:00.000Z"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/documents/{documentId}": {
      "get": {
        "operationId": "documentDetail",
        "summary": "One document + version history",
        "description": "A single catalog document with its version list.\n\nScope: `documents:read`.",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "documentId",
            "in": "path",
            "required": true,
            "description": "Document id, e.g. DOC-CC1-ORG-CHART.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One document + version history",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "id": "DOC-CC1-ORG-CHART",
                    "name": "Organization Chart",
                    "lifecycleStatus": "published",
                    "versions": [
                      {
                        "id": "<version-uuid>",
                        "versionNumber": 2,
                        "status": "published",
                        "fileName": "org-chart-2026-05.xlsx",
                        "fileSize": 1048576,
                        "uploadedAt": "2026-05-01T00:00:00.000Z",
                        "uploadedBy": "people@example.com",
                        "publishedAt": "2026-05-01T00:00:00.000Z"
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/documents/{documentId}/versions/{versionId}/download-url": {
      "get": {
        "operationId": "documentDownloadUrl",
        "summary": "Presigned download URL for a version",
        "description": "Returns a presigned S3 URL (3600s TTL) for the version blob.\n\nScope: `documents:read`.",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "documentId",
            "in": "path",
            "required": true,
            "description": "Document id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "versionId",
            "in": "path",
            "required": true,
            "description": "Version id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Presigned download URL for a version",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "downloadUrl": "https://s3.amazonaws.com/.../org-chart.xlsx?X-Amz-Signature=...",
                    "expiresIn": 3600
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/documents/{documentId}/versions/upload": {
      "post": {
        "operationId": "documentUploadVersion",
        "summary": "Upload a new document version (draft)",
        "description": "Uploads a new document version as a draft. Send the file base64-encoded (≤4 MB raw). Writes audit-log row `v1_upload_document`.\n\nRole gate: owner / admin.\n\nScope: `documents:write`.",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "documentId",
            "in": "path",
            "required": true,
            "description": "Document id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "fileName": {
                    "type": "string",
                    "description": "File name with extension (pdf/docx/xlsx/pptx/doc/xls/png/jpeg/gif/webp/csv/txt/md/json/zip)."
                  },
                  "fileType": {
                    "type": "string",
                    "description": "MIME type, e.g. application/pdf or application/vnd.openxmlformats-officedocument.spreadsheetml.sheet."
                  },
                  "fileContent": {
                    "type": "string",
                    "description": "Base64-encoded file bytes, ≤4 MB raw."
                  },
                  "comments": {
                    "type": "string",
                    "description": "Optional changelog note."
                  }
                },
                "required": [
                  "fileName",
                  "fileType",
                  "fileContent"
                ]
              },
              "example": {
                "fileName": "org-chart-2026-06.xlsx",
                "fileType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                "fileContent": "UEsDBBQ...<base64>",
                "comments": "Q2 reorg"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Upload a new document version (draft)",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "id": "<version-uuid>",
                    "documentId": "DOC-CC1-ORG-CHART",
                    "versionNumber": 3,
                    "status": "draft",
                    "fileName": "org-chart-2026-06.xlsx",
                    "uploadedAt": "2026-05-27T16:00:00.000Z",
                    "uploadedBy": "people@example.com"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/documents/{documentId}/versions/{versionId}/publish": {
      "post": {
        "operationId": "documentPublish",
        "summary": "Publish a document version",
        "description": "Archives the prior published version and publishes the target. Writes audit-log row `v1_publish_document`.\n\nRole gate: owner / admin.\n\nScope: `documents:write`.",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "documentId",
            "in": "path",
            "required": true,
            "description": "Document id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "versionId",
            "in": "path",
            "required": true,
            "description": "Version id to publish.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Publish a document version",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "id": "<version-uuid>",
                    "documentId": "DOC-CC1-ORG-CHART",
                    "versionNumber": 3,
                    "status": "published",
                    "publishedAt": "2026-05-27T16:00:00.000Z",
                    "publishedBy": "people@example.com"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/audits": {
      "get": {
        "operationId": "auditsList",
        "summary": "List audits + pending counts",
        "description": "All audit binders with lifecycle, period, and pending-evidence breakdown.\n\nScope: `audits:read`.",
        "tags": [
          "Audits"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List audits + pending counts",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": [
                    {
                      "id": "<audit-uuid>",
                      "title": "SOC 2 Type 2 — 2026",
                      "frameworkAudits": [
                        {
                          "frameworkId": "soc2",
                          "framework": "SOC 2",
                          "periodStart": "2026-01-01T00:00:00.000Z",
                          "periodEnd": "2026-03-31T00:00:00.000Z",
                          "auditMode": "Type 2"
                        }
                      ],
                      "lifecycle": "in-flight",
                      "pendingRequestsCount": 5,
                      "pendingBreakdown": {
                        "awaitingAdmin": 2,
                        "awaitingAuditor": 3
                      },
                      "totalEvidenceCount": 127,
                      "approvedEvidenceCount": 120,
                      "createdAt": "2025-11-01T00:00:00.000Z"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/audits/{auditId}": {
      "get": {
        "operationId": "auditDetail",
        "summary": "One audit binder summary",
        "description": "A single audit with sampled controls and per-control auditor status.\n\nScope: `audits:read`.",
        "tags": [
          "Audits"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "description": "Audit id (UUID).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One audit binder summary",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "id": "<audit-uuid>",
                    "title": "SOC 2 Type 2 — 2026",
                    "lifecycle": "in-flight",
                    "periodStart": "2026-01-01T00:00:00.000Z",
                    "periodEnd": "2026-03-31T00:00:00.000Z",
                    "auditorStatus": {
                      "CC6.1": {
                        "status": "submitted",
                        "verdict": null,
                        "notes": ""
                      }
                    },
                    "pendingRequestsCount": 5,
                    "totalEvidenceCount": 127,
                    "approvedEvidenceCount": 120
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/tests/results": {
      "get": {
        "operationId": "testsResults",
        "summary": "List automated test results",
        "description": "Automated evidence-collection results with a summary header. Response is `{summary, results}` (not the `{success,data}` envelope).\n\nScope: `compliance:read`.",
        "tags": [
          "Tests"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter by result status.",
            "schema": {
              "type": "string",
              "enum": [
                "passing",
                "failing",
                "skipped",
                "error",
                "all"
              ],
              "default": "all"
            }
          },
          {
            "name": "severity",
            "in": "query",
            "required": false,
            "description": "Filter by severity.",
            "schema": {
              "type": "string",
              "enum": [
                "critical",
                "high",
                "medium",
                "low",
                "info",
                "all"
              ],
              "default": "all"
            }
          },
          {
            "name": "integrationId",
            "in": "query",
            "required": false,
            "description": "Filter to one integration (e.g. aws-123456789012).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List automated test results",
            "content": {
              "application/json": {
                "example": {
                  "summary": {
                    "total": 145,
                    "passing": 120,
                    "failing": 18,
                    "errors": 7,
                    "lastRun": "2026-05-27T14:32:00.000Z"
                  },
                  "results": [
                    {
                      "id": "<result-uuid>",
                      "testId": "aws-s3-encryption",
                      "testName": "S3 Encryption Check",
                      "status": "failing",
                      "severity": "high",
                      "category": "Security",
                      "integration": "aws",
                      "integrationId": "aws-123456789012",
                      "resourceId": "s3://acme-audit-logs",
                      "finding": "S3 bucket 'acme-audit-logs' does not have default encryption enabled.",
                      "executedAt": "2026-05-27T14:30:00.000Z",
                      "remediationSteps": [
                        "Enable SSE-S3 or SSE-KMS default encryption on the bucket."
                      ]
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/employees": {
      "get": {
        "operationId": "employeesList",
        "summary": "Employee directory",
        "description": "A snapshot from the employees table (not a live IdP call), with status + department filters. Manual employment-status overrides set by an admin in the People page are honored — an overridden termination reads as terminated here even if the IdP still shows the account.\n\nScope: `personnel:read`.",
        "tags": [
          "Personnel"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter by employment status.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "terminated",
                "all"
              ],
              "default": "active"
            }
          },
          {
            "name": "department",
            "in": "query",
            "required": false,
            "description": "Exact, case-sensitive department match.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Max rows (capped at 2000).",
            "schema": {
              "type": "integer",
              "default": 500
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Employee directory",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "total": 1,
                  "truncated": false,
                  "data": [
                    {
                      "employeeId": "<emp-uuid>",
                      "email": "alice@example.com",
                      "name": "Alice Smith",
                      "jobTitle": "Security Engineer",
                      "department": "Engineering",
                      "status": "active",
                      "hireDate": "2024-01-15",
                      "terminationDate": null
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/companies/{companyId}/audit-log": {
      "get": {
        "operationId": "auditLog",
        "summary": "Append-only audit log of v1 writes",
        "description": "Every `/api/v1/*` write (and MCP write) lands here: actor, tool, resource, before/after state. Filter by tool or changeAuthor.\n\nScope: `compliance:read`.",
        "tags": [
          "Audit Log"
        ],
        "security": [
          {
            "patBearer": []
          }
        ],
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "description": "Your organization id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tool",
            "in": "query",
            "required": false,
            "description": "Filter by tool name, e.g. v1_mark_control_na.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "changeAuthor",
            "in": "query",
            "required": false,
            "description": "Filter by actor, e.g. pat:851b5b8dabaa.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Max rows (capped at 200).",
            "schema": {
              "type": "integer",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Append-only audit log of v1 writes",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "data": {
                    "totalCount": 847,
                    "truncated": true,
                    "entries": [
                      {
                        "id": "<log-uuid>",
                        "tool": "v1_mark_control_na",
                        "resource": "CC6.1",
                        "resourceType": "control",
                        "action": "mark_control_na",
                        "changeAuthor": "pat:851b5b8dabaa",
                        "clientType": "pat",
                        "email": "admin@example.com",
                        "role": "admin",
                        "timestamp": "2026-05-27T14:32:00.000Z",
                        "beforeState": null,
                        "afterState": {
                          "markedNAAt": "2026-05-27T14:32:00.000Z",
                          "markedNABy": "admin@example.com",
                          "statusCode": 200
                        }
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
