--- openapi: 3.0.3 info: title: Query Orchestration API description: API documentation for the Query Orchestration services. version: 0.0.1 contact: email: piragavarapu@aarete.com name: Aarete Inc. url: https://aarete.com license: name: Aarete Inc.internal use url: https://aarete.com servers: - url: https://doczy.com/v1 description: Production server tags: - name: ClientService description: Operations related to clients - name: CollectorService description: Operations related to collectors - name: DocumentsService description: Operations related to documents - name: FolderService description: Operations related to document folders and organization - name: LabelService description: Operations related to document labels and workflow tracking - name: FieldExtractionService description: Operations related to document field extractions - name: ExportService description: Operations related to exports - name: AuthService description: Operations related to authentication - name: AdminService description: Operations related to user management and administration - name: EulaService description: Operations related to End User License Agreement management and tracking - name: UISettingsService description: Generic UI key-value settings (e.g. demo-dashboard:{userId}, feature-flags:global, saved-filters:{clientId}) paths: /client: post: operationId: createClient tags: - ClientService summary: Create a new client description: Creates a new client with the provided details. security: - jwtAuth: [] requestBody: description: The details required to create a client required: true content: application/json: schema: $ref: "#/components/schemas/ClientCreate" responses: "201": description: Client created successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/ClientIDBody" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /clients: get: operationId: listClients tags: - ClientService summary: List all clients description: Returns a list of all clients in the system. security: - jwtAuth: [] responses: "200": description: List of clients retrieved successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/ClientListResponse" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /client/{id}: parameters: - $ref: "#/components/parameters/ClientID" get: operationId: getClient tags: - ClientService summary: Get a client by ID description: Retrieves a specific client by its ID. security: - jwtAuth: [] responses: "200": description: Client details. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/DocClient" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" patch: operationId: updateClient tags: - ClientService summary: Update a client description: Updates an existing client with new details. security: - jwtAuth: [] requestBody: description: The details to update required: true content: application/json: schema: $ref: "#/components/schemas/ClientUpdate" responses: "200": description: Client updated successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" delete: operationId: deleteClient tags: - ClientService summary: Hard-delete a client and all its data description: >- Permanently deletes a client and all associated data including documents, folders, collectors, batch uploads, and sync records. Source documents in S3 are NOT deleted but their paths are logged. This operation is irreversible. Requires confirm=true query parameter. security: - jwtAuth: [] parameters: - name: confirm in: query description: Must be set to true to confirm deletion required: true schema: type: boolean - name: verbose in: query required: false description: When true, returns S3 paths of orphaned source documents in the response body schema: type: boolean default: false responses: "200": description: Client deleted successfully (verbose mode). headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/DeleteResponse" "204": description: Client deleted successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" # Query paths have been removed - see remove_query_plan.md /client/{id}/status: parameters: - $ref: "#/components/parameters/ClientID" get: operationId: getStatusByClientId tags: - ClientService summary: Get client sync status description: Retrieves the sync status by its client ID. security: - jwtAuth: [] responses: "200": description: Client status details. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/ClientStatusBody" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /client/{id}/collector: parameters: - $ref: "#/components/parameters/ClientID" get: operationId: getCollectorByClientId tags: - CollectorService summary: Get a collector by client ID description: Retrieves a specific collector by its client ID. security: - jwtAuth: [] responses: "200": description: Collector details. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/Collector" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" patch: operationId: setCollectorByClientId tags: - CollectorService summary: Set a collector description: Set client collector with new details. security: - jwtAuth: [] requestBody: description: The details to be set for the collector. required: true content: application/json: schema: $ref: "#/components/schemas/CollectorSet" responses: "204": description: Collector set successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /client/{id}/folders: parameters: - $ref: "#/components/parameters/ClientID" get: operationId: listClientFolders tags: - FolderService summary: List folders for a client description: | Returns all folders belonging to a client. The response includes each folder's ID, path, and parent folder ID, allowing clients to reconstruct the folder hierarchy. Root-level folders will have a null parentId. When metrics=true is specified, each folder will include processing metrics (document counts and label breakdown). This adds overhead so should only be used when metrics are needed. security: - jwtAuth: [] parameters: - name: metrics in: query required: false description: | When true, include processing metrics for each folder (document counts by label). Defaults to false for performance reasons. schema: type: boolean default: false responses: "200": description: List of folders for the client. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/FolderList" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /client/{id}/document: parameters: - $ref: "#/components/parameters/ClientID" get: operationId: listDocumentsByClientId tags: - DocumentsService summary: List the documents for a client description: Retrieves the list of documents by the client ID. security: - jwtAuth: [] responses: "200": description: Client documents list. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/ListDocuments" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" post: operationId: uploadDocument tags: - DocumentsService summary: Upload a file description: Upload a single file to the server with optional metadata security: - jwtAuth: [] requestBody: required: true description: upload file body content: multipart/form-data: schema: type: object required: - file properties: file: type: string format: binary maxLength: 107374182400 description: The file to upload filename: type: string pattern: ".+" maxLength: 4096 description: Optional custom filename example: "document.pdf" encoding: file: contentType: application/pdf style: form explode: false responses: "200": description: Document uploaded. headers: RateLimit: $ref: "#/components/headers/RateLimit" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /client/{id}/document/batch: parameters: - $ref: "#/components/parameters/ClientID" post: operationId: uploadDocumentBatch tags: - DocumentsService summary: Upload multiple PDF documents as ZIP archive description: Upload a ZIP archive containing multiple PDF documents for async batch processing security: - jwtAuth: [] requestBody: required: true description: ZIP archive containing PDF documents content: multipart/form-data: schema: type: object required: - archive properties: archive: type: string format: binary maxLength: 1073741824 # 1GB limit for ZIP files description: The file to be uploaded as a ZIP archive encoding: archive: contentType: application/zip style: form explode: false responses: "202": description: Batch upload accepted for processing headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/BatchUploadResponse" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" get: operationId: listDocumentBatches tags: - DocumentsService summary: List batch uploads for a client description: Retrieves a list of batch uploads for the specified client security: - jwtAuth: [] parameters: - in: query name: limit schema: type: integer format: int32 minimum: 1 maximum: 100 default: 20 description: Maximum number of items to return - in: query name: offset schema: type: integer format: int32 minimum: 0 maximum: 2147483647 default: 0 description: Number of items to skip responses: "200": description: List of batch uploads headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/BatchUploadList" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /client/{id}/document/batch/{batch_id}: parameters: - $ref: "#/components/parameters/ClientID" - $ref: "#/components/parameters/BatchID" get: operationId: getDocumentBatch tags: - DocumentsService summary: Get batch upload status description: Retrieves detailed status information for a specific batch upload security: - jwtAuth: [] responses: "200": description: Batch upload details headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/BatchUploadDetails" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /document/{id}: parameters: - $ref: "#/components/parameters/DocumentID" get: operationId: getDocument tags: - DocumentsService summary: Get document details by its id description: | Retrieves the details of a document by its id, including metadata such as folder, filename, labels, and optionally the full text extraction record. security: - jwtAuth: [] parameters: - name: textRecord in: query required: false description: When true, includes the full text extraction record in the response schema: type: boolean default: false responses: "200": description: Document details. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/DocumentEnriched" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" delete: operationId: deleteDocument tags: - DocumentsService summary: Hard-delete a document description: >- Permanently deletes a document and all dependent data including entries, cleans, text extractions, field extractions, labels, and results. Source documents in S3 are NOT deleted but their paths are logged. security: - jwtAuth: [] parameters: - name: verbose in: query required: false description: When true, returns S3 paths of orphaned source documents in the response body schema: type: boolean default: false responses: "200": description: Document deleted successfully (verbose mode). headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/DeleteResponse" "204": description: Document deleted successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /document/{id}/download: parameters: - $ref: "#/components/parameters/DocumentID" get: operationId: downloadDocument tags: - DocumentsService summary: Download the original document file description: | Streams the original uploaded document file. The response Content-Type is auto-detected from the stored filename extension. No query parameters are required; the system resolves the file type automatically. security: - jwtAuth: [] responses: "200": description: Document file bytes. headers: RateLimit: $ref: "#/components/headers/RateLimit" Content-Disposition: schema: type: string maxLength: 4096 description: 'Attachment header with original filename, e.g. attachment; filename="report.pdf"' content: application/octet-stream: schema: type: string format: binary maxLength: 107374182400 "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /folders: post: operationId: createFolder tags: - FolderService summary: Create a new folder description: Creates a new folder for organizing documents. security: - jwtAuth: [] requestBody: description: The details required to create a folder required: true content: application/json: schema: $ref: "#/components/schemas/FolderCreate" responses: "201": description: Folder created successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/Folder" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /folders/{folderId}: parameters: - name: folderId in: path required: true description: The folder ID schema: type: string format: uuid maxLength: 50 patch: operationId: renameFolder tags: - FolderService summary: Rename a folder description: Updates the folder path/name. security: - jwtAuth: [] requestBody: description: The new folder path required: true content: application/json: schema: $ref: "#/components/schemas/FolderRename" responses: "200": description: Folder renamed successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/Folder" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" delete: operationId: deleteFolder tags: - FolderService summary: Hard-delete a folder tree description: >- Permanently deletes a folder and all its child folders recursively. The root folder (path '/') cannot be deleted. If the folder tree contains documents, include_documents=true is required or a 409 Conflict is returned. When include_documents=true, all documents in the tree are also permanently deleted. Source documents in S3 are NOT deleted but their paths are logged. security: - jwtAuth: [] parameters: - name: include_documents in: query required: false description: When true, also deletes all documents in the folder tree schema: type: boolean default: false - name: verbose in: query required: false description: When true, returns S3 paths of orphaned source documents in the response body schema: type: boolean default: false responses: "200": description: Folder tree deleted successfully (verbose mode). headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/DeleteResponse" "204": description: Folder tree deleted successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "409": $ref: "#/components/responses/Conflict" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /folders/{folderId}/documents: parameters: - name: folderId in: path required: true description: The folder ID schema: type: string format: uuid maxLength: 50 get: operationId: getFolderDocuments tags: - FolderService summary: Get documents in a folder description: | Retrieves all documents within a specific folder, including filename and labels. Optionally includes the full text extraction record for each document. Returns a lighter-weight format than GET /document/{id} (excludes client_id and computed fields). security: - jwtAuth: [] parameters: - name: textRecord in: query required: false description: When true, includes the full text extraction record for each document schema: type: boolean default: false responses: "200": description: List of documents in folder. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: type: object properties: documents: type: array maxItems: 10000 items: $ref: "#/components/schemas/DocumentInFolder" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /folders/{folderId}/metrics: parameters: - name: folderId in: path required: true description: The folder ID schema: type: string format: uuid maxLength: 50 get: operationId: getFolderMetrics tags: - FolderService summary: Get folder processing metrics description: Retrieves processing progress metrics for documents in a folder. security: - jwtAuth: [] responses: "200": description: Folder metrics. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/FolderMetrics" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /documents/{documentId}/labels: parameters: - name: documentId in: path required: true description: The document ID schema: type: string format: uuid maxLength: 50 post: operationId: applyLabel tags: - LabelService summary: Apply a label to a document description: Applies a workflow label to a document for tracking processing state. security: - jwtAuth: [] requestBody: description: The label to apply required: true content: application/json: schema: $ref: "#/components/schemas/LabelApplication" responses: "201": description: Label applied successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/LabelRecord" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" get: operationId: getDocumentLabels tags: - LabelService summary: Get all labels for a document description: Retrieves all labels that have been applied to a document, ordered by most recent first. security: - jwtAuth: [] responses: "200": description: List of labels. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: type: object properties: labels: type: array maxItems: 1000 items: $ref: "#/components/schemas/LabelRecord" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /labels/{labelName}/documents: parameters: - name: labelName in: path required: true description: The label name schema: type: string maxLength: 100 pattern: "^[A-Za-z0-9_]+$" - name: clientId in: query required: true description: The client ID to filter documents schema: $ref: "#/components/schemas/ClientID" get: operationId: getDocumentsByLabel tags: - LabelService summary: Get all documents with a specific label description: Retrieves all documents that have been tagged with a specific label. security: - jwtAuth: [] responses: "200": description: List of documents with this label. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: type: object properties: documents: type: array maxItems: 10000 items: $ref: "#/components/schemas/DocumentSummary" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /client/{id}/export: parameters: - $ref: "#/components/parameters/ClientID" post: operationId: triggerExport tags: - ExportService summary: Trigger an export description: Initiates the export process. security: - jwtAuth: [] requestBody: description: The export requirements. required: true content: application/json: schema: $ref: "#/components/schemas/ExportTrigger" responses: "201": description: Export triggered successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/IdMessage" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /export/{id}: parameters: - $ref: "#/components/parameters/ExportID" get: operationId: exportState tags: - ExportService summary: Check export state. description: Checks the current state of an export. security: - jwtAuth: [] responses: "200": description: Export has been completed. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/ExportDetails" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /field-extractions: post: operationId: createFieldExtraction tags: - FieldExtractionService summary: Create a new field extraction description: Creates a new field extraction with single-value and array fields for a document. security: - jwtAuth: [] requestBody: description: The field extraction data required: true content: application/json: schema: $ref: "#/components/schemas/FieldExtractionRequest" responses: "201": description: Field extraction created successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/FieldExtractionResponse" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" get: operationId: getCurrentFieldExtraction tags: - FieldExtractionService summary: Get current field extraction description: Retrieves the most recent field extraction for a document. security: - jwtAuth: [] parameters: - name: documentId in: query required: true description: The document ID schema: type: string format: uuid maxLength: 50 responses: "200": description: Current field extraction. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/FieldExtractionResponse" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /field-extractions/version: get: operationId: getFieldExtractionByVersion tags: - FieldExtractionService summary: Get field extraction by version description: Retrieves a specific version of field extraction for a document. security: - jwtAuth: [] parameters: - name: documentId in: query required: true description: The document ID schema: type: string format: uuid maxLength: 50 - name: version in: query required: true description: The version number to retrieve schema: type: integer format: int64 minimum: 1 maximum: 9223372036854775807 responses: "200": description: Field extraction for the specified version. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/FieldExtractionResponse" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /field-extractions/history: get: operationId: getFieldExtractionHistory tags: - FieldExtractionService summary: Get field extraction version history description: Retrieves all versions of field extractions for a document, ordered by most recent first. security: - jwtAuth: [] parameters: - name: documentId in: query required: true description: The document ID schema: type: string format: uuid maxLength: 50 responses: "200": description: Field extraction history. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: type: object properties: versions: type: array maxItems: 1000 items: $ref: "#/components/schemas/FieldExtractionVersion" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /login: get: operationId: login tags: - AuthService summary: Login to the application description: >- Initiates the login flow by redirecting to Cognito IDP login page. security: - {} - cognitoAuth: [openid, email, profile] responses: "302": description: Redirect to Cognito login page headers: Location: schema: type: string format: uri maxLength: 2048 pattern: "^https://.*" description: URL to the Cognito login page RateLimit: $ref: "#/components/headers/RateLimit" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /login-callback: get: operationId: loginCallback tags: - AuthService summary: OAuth2 callback endpoint description: >- Handles the OAuth2 callback during the login process. Receives the authorization code from Cognito IDP and exchanges it for tokens. security: - {} parameters: - name: code in: query description: Authorization code from Cognito required: true schema: type: string maxLength: 2048 pattern: "^[A-Za-z0-9\\-_]+$" - name: state in: query description: State parameter for CSRF protection required: true schema: type: string maxLength: 1024 pattern: "^[A-Za-z0-9\\-_]+$" responses: "302": description: Redirect to application after successful login headers: Location: schema: type: string format: uri maxLength: 2048 pattern: "^https?://.*" description: URL to redirect after successful login "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /logout: get: operationId: logout tags: - AuthService summary: Logout from the application description: >- Logs the user out by invalidating the session and redirecting to Cognito logout endpoint. security: - jwtAuth: [] responses: "302": description: Redirect to Cognito logout page or application home page headers: Location: schema: type: string format: uri maxLength: 2048 pattern: "^https?://.*" description: URL to redirect after logout "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /ui-settings: post: operationId: createUISetting tags: - UISettingsService summary: Create a UI setting description: > Creates a new UI setting (namespace, key, value). Use namespace to scope data (e.g. demo-dashboard:{userId}, feature-flags:global). Returns 201 with the created resource. security: - jwtAuth: [] requestBody: description: UI setting payload. required: true content: application/json: schema: $ref: "#/components/schemas/UISettingCreate" responses: "201": description: Setting created successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/UISetting" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" get: operationId: listUISettings tags: - UISettingsService summary: List UI settings description: Returns settings where isDeleted is false. Optional query param namespace filters by namespace (e.g. demo-dashboard:user123). security: - jwtAuth: [] parameters: - name: namespace in: query required: false schema: type: string maxLength: 255 description: Filter by namespace (omit to list all). responses: "200": description: List of settings. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/UISettingListResponse" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /ui-settings/{id}: parameters: - $ref: "#/components/parameters/UISettingID" get: operationId: getUISetting tags: - UISettingsService summary: Get a UI setting by ID description: Returns a single setting by id. Returns 404 if not found or soft-deleted. security: - jwtAuth: [] responses: "200": description: Setting details. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/UISetting" "400": $ref: "#/components/responses/InvalidRequest" "404": $ref: "#/components/responses/NotFound" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" patch: operationId: updateUISetting tags: - UISettingsService summary: Update a UI setting description: Updates the value of an existing setting. Returns 404 if not found or soft-deleted. security: - jwtAuth: [] requestBody: description: Updated UI setting value payload. required: true content: application/json: schema: $ref: "#/components/schemas/UISettingUpdate" responses: "200": description: Setting updated successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/UISetting" "404": $ref: "#/components/responses/NotFound" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" delete: operationId: deleteUISetting tags: - UISettingsService summary: Soft-delete a UI setting description: Sets isDeleted to true. Returns 204 on success, 404 if not found. security: - jwtAuth: [] responses: "204": description: Setting soft-deleted. headers: RateLimit: $ref: "#/components/headers/RateLimit" "400": $ref: "#/components/responses/InvalidRequest" "404": $ref: "#/components/responses/NotFound" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /identity: get: operationId: getIdentity tags: - AuthService summary: Get current user identity and roles description: >- Returns the authenticated user's assigned roles from Permit.io, including the permissions granted by each role. Any authenticated user can call this endpoint to discover their own roles. security: - jwtAuth: [] responses: "200": description: User roles and permissions retrieved successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/IdentityResponse" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" "502": description: Failed to retrieve roles from Permit.io content: application/json: schema: $ref: "#/components/schemas/ErrorMessage" /home: get: operationId: getHomePage tags: - AuthService summary: Get the home page menu description: >- Returns the HTML menu page for authenticated users. security: - jwtAuth: [] responses: "200": description: Home page HTML headers: RateLimit: $ref: "#/components/headers/RateLimit" content: text/html: schema: type: string description: HTML content for the home page menu maxLength: 1048576 pattern: "^.*$" format: html "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /admin/users: post: operationId: createAdminUser tags: - AdminService summary: Create a new user description: >- Creates a new user in both AWS Cognito and Permit.io systems with optional role assignments. Idempotent - returns 200 OK if user already exists with identical attributes. **Creation Flow:** 1. User is created in AWS Cognito (primary authentication system) 2. If Cognito creation fails, operation fails with HTTP 502 (no user created) 3. User is created in Permit.io (authorization/role system) 4. If Permit.io creation fails, user still exists in Cognito but permit_synced=false 5. Roles are assigned in Permit.io (best-effort, continues on failures) **Role Assignment Behavior:** - Roles must exist in your Permit.io environment (e.g., super_admin, user_admin, auditor, client_user) - Invalid/non-existent roles fail silently and are logged server-side - Only successfully assigned roles appear in the roles_assigned response field - The roles_assigned array may be a subset of the requested roles array - If all roles fail, roles_assigned will be null or empty (user has no permissions) **Partial Success Scenarios:** - Returns HTTP 201 even if Permit.io creation or some role assignments fail - Check permit_synced field: false indicates user was not created in Permit.io - Compare roles_assigned vs requested roles to detect role assignment failures - User can authenticate (Cognito) but may lack authorization (Permit.io) if sync fails security: - jwtAuth: [] requestBody: description: The user details required to create a user required: true content: application/json: schema: $ref: "#/components/schemas/AdminUserCreate" responses: "201": description: User created successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/AdminUserCreateResponse" "200": description: User already exists with matching attributes (idempotent). headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/AdminUserCreateResponse" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "409": $ref: "#/components/responses/Conflict" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" "502": $ref: "#/components/responses/BadGateway" get: operationId: listAdminUsers tags: - AdminService summary: List users description: >- Lists users from AWS Cognito with pagination, filtering, and sorting support. Note: The roles field is not populated in this response. To retrieve roles for a specific user, call GET /admin/users/{email} which returns the full user details including Permit.io roles. security: - jwtAuth: [] parameters: - name: page in: query description: Page number for pagination schema: type: integer format: int32 minimum: 1 default: 1 maximum: 10000 - name: page_size in: query description: Number of results per page schema: type: integer format: int32 minimum: 1 maximum: 100 default: 50 - name: search in: query description: Search term for email/name filtering schema: type: string maxLength: 256 pattern: "^.+$" - name: status in: query description: Filter by user status schema: type: string enum: [enabled, disabled, all] default: all - name: sort_by in: query description: Field to sort by schema: type: string enum: [email, created_at, last_name] default: email - name: sort_order in: query description: Sort direction schema: type: string enum: [asc, desc] default: asc responses: "200": description: List of users. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/AdminUserList" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /admin/users/{email}: parameters: - $ref: "#/components/parameters/UserEmail" get: operationId: getAdminUser tags: - AdminService summary: Get user by email description: >- Retrieves user details from both AWS Cognito and Permit.io by email address. security: - jwtAuth: [] responses: "200": description: User details. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/AdminUserDetails" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" head: operationId: checkAdminUserExists tags: - AdminService summary: Check if user exists description: >- Checks if a user exists in Cognito and/or Permit.io without returning full details. security: - jwtAuth: [] responses: "200": description: User exists. headers: RateLimit: $ref: "#/components/headers/RateLimit" X-User-Exists-Cognito: schema: type: boolean description: Whether user exists in Cognito X-User-Exists-PermitIO: schema: type: boolean description: Whether user exists in Permit.io "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": description: User does not exist in either system headers: RateLimit: $ref: "#/components/headers/RateLimit" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" patch: operationId: updateAdminUser tags: - AdminService summary: Update user attributes and roles description: >- Updates user attributes (first_name, last_name) in Cognito and manages role assignments in Permit.io. Email address cannot be changed (use email path parameter to identify user). **Attribute Updates:** - first_name and last_name are updated in AWS Cognito - Omit fields you don't want to change (e.g., send only roles to change roles) **Role Management (REPLACE Strategy):** - Providing a roles array REPLACES all existing roles (not additive) - To add a role: include ALL current roles PLUS the new role - To remove a role: include only the roles you want to keep - To remove all roles: send an empty array [] - Omitting the roles field leaves role assignments unchanged **Role Assignment Behavior:** - Roles must exist in your Permit.io environment - Invalid/non-existent roles fail silently and are logged server-side - Response.roles field shows the final state after successful assignments - Compare response.roles vs requested roles to detect failures **Example - Add a Role:** Current roles: ["client_user"] To add "auditor": send roles: ["client_user", "auditor"] Result: ["client_user", "auditor"] **Example - Replace All Roles:** Current roles: ["auditor", "client_user"] To change to just "super_admin": send roles: ["super_admin"] Result: ["super_admin"] (auditor and client_user removed) security: - jwtAuth: [] requestBody: description: The user attributes to update required: true content: application/json: schema: $ref: "#/components/schemas/AdminUserUpdate" responses: "200": description: User updated successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/AdminUserDetails" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" delete: operationId: deleteAdminUser tags: - AdminService summary: Delete user permanently description: >- Permanently deletes a user from both AWS Cognito and Permit.io. This operation is irreversible. Requires confirm=true query parameter. security: - jwtAuth: [] parameters: - name: confirm in: query description: Must be set to true to confirm deletion required: true schema: type: boolean responses: "200": description: User deleted successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/AdminUserDeleteResponse" "207": description: User partially deleted (multi-status). headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/AdminUserDeleteResponse" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /admin/users/{email}/disable: parameters: - $ref: "#/components/parameters/UserEmail" post: operationId: disableAdminUser tags: - AdminService summary: Disable user description: >- Disables a user in AWS Cognito, preventing authentication. User data and roles are preserved. Idempotent. security: - jwtAuth: [] responses: "200": description: User disabled successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/AdminUserActionResponse" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /admin/users/{email}/enable: parameters: - $ref: "#/components/parameters/UserEmail" post: operationId: enableAdminUser tags: - AdminService summary: Enable user description: >- Re-enables a previously disabled user in AWS Cognito. Restores authentication capability. Idempotent. security: - jwtAuth: [] responses: "200": description: User enabled successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/AdminUserActionResponse" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" # EULA Public Endpoints /eula: get: operationId: getCurrentEula tags: - EulaService summary: Get current EULA version description: Returns the current active End User License Agreement version. This endpoint is public and does not require authentication. security: [] responses: "200": description: Current EULA version retrieved successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/EulaPublicResponse" example: id: "019580df-ef65-7676-8de9-94435a93337a" version: "1.0" title: "Terms of Service v1.0" content: "# Terms of Service\n\n## Section 1: Acceptance of Terms\n\nBy using this service, you agree to these terms..." effectiveDate: "2026-01-01T00:00:00Z" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /eula/status: get: operationId: getEulaStatus tags: - EulaService summary: Check user's EULA agreement status description: | Returns the current user's agreement status for the current EULA version. Designed for the frontend to quickly determine if the user needs to be prompted to agree. security: - jwtAuth: [] responses: "200": description: EULA status retrieved successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/EulaStatusResponse" examples: agreed: summary: User has agreed to current EULA value: hasAgreed: true currentVersion: "1.0" currentVersionId: "019580df-ef65-7676-8de9-94435a93337a" agreedAt: "2026-01-15T10:30:00Z" agreedVersion: "1.0" notAgreed: summary: User has not agreed to current EULA value: hasAgreed: false currentVersion: "2.0" currentVersionId: "019580df-ef65-7676-8de9-94435a93337b" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /eula/agree: post: operationId: agreeToEula tags: - EulaService summary: Record user agreement to current EULA description: | Records the user's agreement to the current EULA version. Returns 201 for first agreement, 200 if user already agreed (idempotent). The IP address is automatically captured from the request. security: - jwtAuth: [] responses: "201": description: Agreement recorded successfully (first agreement). headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/EulaAgreementResponse" example: id: "019580df-ef65-7676-8de9-94435a93337c" eulaVersionId: "019580df-ef65-7676-8de9-94435a93337a" eulaVersion: "1.0" agreedAt: "2026-01-22T14:30:00Z" "200": description: User already agreed to current version (returns existing agreement). headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/EulaAgreementResponse" example: id: "019580df-ef65-7676-8de9-94435a93337c" eulaVersionId: "019580df-ef65-7676-8de9-94435a93337a" eulaVersion: "1.0" agreedAt: "2026-01-15T10:30:00Z" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" # EULA Admin Endpoints /admin/eula: get: operationId: listEulaVersions tags: - EulaService summary: List all EULA versions description: Returns a paginated list of all EULA versions. security: - jwtAuth: [] parameters: - name: page in: query description: Page number for pagination schema: type: integer format: int32 minimum: 1 maximum: 10000 default: 1 - name: page_size in: query description: Number of items per page schema: type: integer format: int32 minimum: 1 maximum: 100 default: 20 responses: "200": description: List of EULA versions retrieved successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/EulaVersionList" example: versions: - id: "019580df-ef65-7676-8de9-94435a93337a" version: "1.0" title: "Terms of Service v1.0" content: "# Terms of Service\n\n## Section 1\n\nBy using this service..." effectiveDate: "2026-01-01T00:00:00Z" createdAt: "2025-12-15T10:30:00Z" createdBy: "admin@example.com" isCurrent: true activatedAt: "2026-01-01T00:00:00Z" activatedBy: "admin@example.com" - id: "019580df-ef65-7676-8de9-94435a93337b" version: "0.9-beta" title: "Terms of Service (Beta)" content: "# Terms of Service (Beta)\n\n## Section 1\n\nThis is a beta version..." effectiveDate: "2025-11-01T00:00:00Z" createdAt: "2025-10-15T10:30:00Z" createdBy: "admin@example.com" isCurrent: false total: 2 page: 1 page_size: 20 has_more: false "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" post: operationId: createEulaVersion tags: - EulaService summary: Create a new EULA version description: Creates a new EULA version. The content should be in Markdown format. security: - jwtAuth: [] requestBody: description: EULA version details required: true content: application/json: schema: $ref: "#/components/schemas/EulaVersionCreate" example: version: "2.0" title: "Terms of Service v2.0" content: "# Terms of Service v2.0\n\n## Section 1\n\nBy using this service..." effectiveDate: "2026-02-01T00:00:00Z" responses: "201": description: EULA version created successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/EulaVersion" example: id: "019580df-ef65-7676-8de9-94435a93337d" version: "2.0" title: "Terms of Service v2.0" content: "# Terms of Service v2.0\n\n## Section 1\n\nBy using this service..." effectiveDate: "2026-02-01T00:00:00Z" createdAt: "2026-01-22T14:30:00Z" createdBy: "admin@example.com" isCurrent: false "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "409": $ref: "#/components/responses/Conflict" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /admin/eula/{version_id}: parameters: - $ref: "#/components/parameters/EulaVersionID" get: operationId: getEulaVersion tags: - EulaService summary: Get a specific EULA version description: Retrieves a specific EULA version by its ID. security: - jwtAuth: [] responses: "200": description: EULA version retrieved successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/EulaVersion" example: id: "019580df-ef65-7676-8de9-94435a93337a" version: "1.0" title: "Terms of Service v1.0" content: "# Terms of Service\n\n## Section 1: Acceptance of Terms\n\nBy using this service, you agree to these terms..." effectiveDate: "2026-01-01T00:00:00Z" createdAt: "2025-12-15T10:30:00Z" createdBy: "admin@example.com" isCurrent: true activatedAt: "2026-01-01T00:00:00Z" activatedBy: "admin@example.com" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" patch: operationId: updateEulaVersion tags: - EulaService summary: Update EULA version metadata description: Updates only the metadata (title and effective date) of an EULA version. Content cannot be modified. security: - jwtAuth: [] requestBody: description: Fields to update required: true content: application/json: schema: $ref: "#/components/schemas/EulaVersionUpdate" example: title: "Terms of Service v1.0 (Revised)" effectiveDate: "2026-01-15T00:00:00Z" responses: "200": description: EULA version updated successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/EulaVersion" example: id: "019580df-ef65-7676-8de9-94435a93337a" version: "1.0" title: "Terms of Service v1.0 (Revised)" content: "# Terms of Service\n\n## Section 1: Acceptance of Terms\n\nBy using this service, you agree to these terms..." effectiveDate: "2026-01-15T00:00:00Z" createdAt: "2025-12-15T10:30:00Z" createdBy: "admin@example.com" isCurrent: true activatedAt: "2026-01-01T00:00:00Z" activatedBy: "admin@example.com" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /admin/eula/{version_id}/activate: parameters: - $ref: "#/components/parameters/EulaVersionID" post: operationId: activateEulaVersion tags: - EulaService summary: Activate an EULA version description: | Sets this version as the current active EULA. Uses a database transaction to atomically clear the previous current flag and set the new one. Returns 409 if another admin activated a different version concurrently. security: - jwtAuth: [] responses: "200": description: EULA version activated successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/EulaVersion" example: id: "019580df-ef65-7676-8de9-94435a93337d" version: "2.0" title: "Terms of Service v2.0" content: "# Terms of Service v2.0\n\n## Section 1: Acceptance of Terms\n\nBy accessing or using our services..." effectiveDate: "2026-02-01T00:00:00Z" createdAt: "2026-01-22T14:30:00Z" createdBy: "admin@example.com" isCurrent: true activatedAt: "2026-01-22T15:00:00Z" activatedBy: "admin@example.com" "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" "409": $ref: "#/components/responses/Conflict" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /admin/eula/agreements: get: operationId: listEulaAgreements tags: - EulaService summary: List EULA agreements description: | Returns a paginated list of user agreements. Use version_id to filter by a specific EULA version. Use user_id to view a specific user's complete EULA agreement history. security: - jwtAuth: [] parameters: - name: page in: query description: Page number for pagination schema: type: integer format: int32 minimum: 1 maximum: 10000 default: 1 - name: page_size in: query description: Number of items per page schema: type: integer format: int32 minimum: 1 maximum: 100 default: 20 - name: version_id in: query description: Filter by specific EULA version ID schema: type: string format: uuid maxLength: 36 - name: user_id in: query description: Filter by Cognito subject ID to see all EULAs a specific user agreed to schema: type: string maxLength: 256 responses: "200": description: List of agreements retrieved successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/EulaAgreementList" example: agreements: - id: "019580df-ef65-7676-8de9-94435a93337c" cognitoSubjectId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" userEmail: "user1@example.com" eulaVersionId: "019580df-ef65-7676-8de9-94435a93337a" eulaVersion: "1.0" eulaVersionTitle: "Terms of Service v1.0" agreedAt: "2026-01-15T10:30:00Z" agreedFromIp: "192.168.1.100" - id: "019580df-ef65-7676-8de9-94435a93337e" cognitoSubjectId: "b2c3d4e5-f6a7-8901-bcde-f12345678901" userEmail: "user2@example.com" eulaVersionId: "019580df-ef65-7676-8de9-94435a93337a" eulaVersion: "1.0" eulaVersionTitle: "Terms of Service v1.0" agreedAt: "2026-01-16T09:15:00Z" agreedFromIp: "10.0.0.50" total: 150 page: 1 page_size: 20 has_more: true "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" /admin/eula/compliance: get: operationId: getEulaCompliance tags: - EulaService summary: Get EULA compliance report description: | Returns a comprehensive compliance report showing which users have and have not agreed to a specific EULA version. Defaults to the current active version if no version_id is provided. User data is fetched from Cognito for accuracy. security: - jwtAuth: [] parameters: - name: page in: query description: Page number for pagination schema: type: integer format: int32 minimum: 1 maximum: 10000 default: 1 - name: page_size in: query description: Number of items per page schema: type: integer format: int32 minimum: 1 maximum: 100 default: 50 - name: version_id in: query description: Specific EULA version to report on. If omitted, uses current active version. schema: type: string format: uuid maxLength: 36 - name: agreed in: query description: Filter by agreement status. True for agreed only, false for not-agreed only. schema: type: boolean responses: "200": description: Compliance report generated successfully. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/EulaComplianceReport" example: eulaVersion: id: "019580df-ef65-7676-8de9-94435a93337a" version: "1.0" title: "Terms of Service v1.0" effectiveDate: "2026-01-01T00:00:00Z" isCurrent: true summary: totalUsers: 150 agreedCount: 120 notAgreedCount: 30 compliancePercentage: 80.0 users: - cognitoSubjectId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" email: "user1@example.com" currentEmail: "user1@example.com" agreed: true agreedAt: "2026-01-15T10:30:00Z" agreedFromIp: "192.168.1.100" - cognitoSubjectId: "b2c3d4e5-f6a7-8901-bcde-f12345678901" currentEmail: "user2@example.com" agreed: false - cognitoSubjectId: "c3d4e5f6-a7b8-9012-cdef-123456789012" email: "user3-old@example.com" currentEmail: "user3-new@example.com" agreed: true agreedAt: "2026-01-16T14:45:00Z" agreedFromIp: "10.0.0.25" pagination: page: 1 pageSize: 50 totalPages: 3 totalItems: 150 "400": $ref: "#/components/responses/InvalidRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalError" components: parameters: ClientID: in: path name: id required: true schema: $ref: "#/components/schemas/ClientID" description: The client ID. ExportID: in: path name: id required: true schema: $ref: "#/components/schemas/ExportID" description: The export ID. # QueryID parameter has been removed - see remove_query_plan.md DocumentID: in: path name: id required: true schema: $ref: "#/components/schemas/DocumentID" description: The document ID. BatchID: in: path name: batch_id required: true schema: $ref: "#/components/schemas/BatchID" description: The batch upload ID. UserEmail: in: path name: email required: true schema: type: string format: email maxLength: 320 description: URL-encoded user email address. EulaVersionID: in: path name: version_id required: true schema: type: string format: uuid maxLength: 36 description: The EULA version ID. UISettingID: in: path name: id required: true schema: type: string format: uuid maxLength: 36 description: The UI setting ID. headers: RateLimit: schema: type: string pattern: "^[0-9]+;window=[0-9]+$" maxLength: 32 example: 100;window=60 description: Rate limit information in format "limit;window=time-window" example: "100;window=10" securitySchemes: jwtAuth: type: http scheme: bearer bearerFormat: JWT description: >- JWT token obtained after Cognito authentication. Implements RFC8725 JWT best practices for security. cognitoAuth: type: oauth2 description: >- Authentication using Amazon Cognito IDP. Implements RFC8725 JWT best practices for security. flows: authorizationCode: authorizationUrl: >- https://doczy.auth.us-east-1.amazoncognito.com/oauth2/authorize tokenUrl: >- https://doczy.auth.us-east-1.amazoncognito.com/oauth2/token scopes: openid: Get OIDC token email: Access to user's email profile: Access to user's profile responses: InvalidRequest: description: Invalid request body. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/ErrorMessage" InternalError: description: Internal server error. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/ErrorMessage" TooManyRequests: description: Response upon too many requests. headers: RateLimit: $ref: "#/components/headers/RateLimit" Retry-After: schema: type: integer format: int32 minimum: 0 maximum: 86400 description: Number of seconds before trying again. example: 120 content: application/json: schema: $ref: "#/components/schemas/ErrorMessage" Unauthorized: description: Response when unauthorized. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/ErrorMessage" NotFound: description: Resource not found. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/ErrorMessage" Forbidden: description: Insufficient permissions to perform this action. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/ErrorMessage" Conflict: description: Resource already exists or state conflict. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/ErrorMessage" BadGateway: description: External service error. headers: RateLimit: $ref: "#/components/headers/RateLimit" content: application/json: schema: $ref: "#/components/schemas/ErrorMessage" schemas: # Query API schemas ClientID: type: string description: The client external id example: AAA maxLength: 36 pattern: "^.+$" DocumentID: type: string format: uuid description: The document id. example: 019580df-b3f8-7348-9ab1-1e55b3f18ed7 maxLength: 36 ExportID: type: string format: uuid description: The export id. example: 019580de-4d51-713c-98ee-464e83811f13 maxLength: 36 BatchID: type: string format: uuid description: The batch upload id. example: 019580df-ef65-7676-8de9-94435a93337a maxLength: 36 BatchStatus: type: string enum: - processing - completed - failed - cancelled description: The status of a batch upload BatchUploadResponse: type: object description: Response returned when a batch upload is accepted for processing required: - batch_id - status - status_url properties: batch_id: $ref: "#/components/schemas/BatchID" status: $ref: "#/components/schemas/BatchStatus" status_url: type: string format: uri-reference maxLength: 512 description: URL to check batch status example: "/client/AAA/document/batch/019580df-ef65-7676-8de9-94435a93337a" BatchUploadSummary: type: object description: Summary information about a batch upload required: - batch_id - client_id - original_filename - status - total_documents - processed_documents - failed_documents - invalid_type_documents - progress_percent - created_at properties: batch_id: $ref: "#/components/schemas/BatchID" client_id: $ref: "#/components/schemas/ClientID" original_filename: type: string maxLength: 4096 pattern: "^.+$" description: Original filename of the uploaded ZIP archive example: "documents.zip" status: $ref: "#/components/schemas/BatchStatus" total_documents: type: integer format: int32 minimum: 0 maximum: 2147483647 description: Total number of documents in the batch example: 100 processed_documents: type: integer format: int32 minimum: 0 maximum: 2147483647 description: Number of documents processed so far example: 42 failed_documents: type: integer format: int32 minimum: 0 maximum: 2147483647 description: Number of documents that failed processing example: 2 invalid_type_documents: type: integer format: int32 minimum: 0 maximum: 2147483647 description: Number of non-PDF files found in archive example: 1 progress_percent: type: integer format: int32 minimum: 0 maximum: 100 description: Processing progress percentage example: 42 created_at: type: string format: date-time maxLength: 50 description: When the batch upload was created completed_at: type: string format: date-time maxLength: 50 nullable: true description: When the batch upload completed processing BatchDocumentOutcome: type: object description: Per-file outcome from batch extraction and pipeline processing required: [filename, outcome] properties: filename: type: string maxLength: 4096 description: Original filename from the ZIP archive outcome: type: string enum: [ submitted, duplicate, failed_open, failed_read, failed_s3_upload, failed_upload, invalid_type, init_complete, init_duplicate, sync_complete, sync_skipped, clean_passed, clean_failed, ] description: Current processing status error_detail: type: string maxLength: 2048 nullable: true description: Human-readable error message for failure outcomes document_id: type: string format: uuid maxLength: 36 nullable: true description: Assigned document ID (null for files that never became documents) clean_fail_reason: type: string maxLength: 2048 nullable: true description: > Specific clean validation failure reason when outcome is clean_failed. Null otherwise. created_at: type: string format: date-time maxLength: 50 description: When the file was first extracted from the ZIP updated_at: type: string format: date-time maxLength: 50 description: When the outcome was last updated by a pipeline stage BatchUploadDetails: description: Detailed information about a batch upload including failed filenames and per-file outcomes allOf: - $ref: "#/components/schemas/BatchUploadSummary" - type: object properties: failed_filenames: type: array maxItems: 10000 items: type: string maxLength: 4096 pattern: "^.+$" description: List of filenames that failed processing example: ["doc3.pdf", "doc17.pdf"] document_outcomes: type: array maxItems: 10000 items: $ref: "#/components/schemas/BatchDocumentOutcome" description: Per-file outcome tracking for all files in the batch BatchUploadList: type: object description: List of batch uploads for a client required: - batches - total_count properties: batches: type: array maxItems: 100 items: $ref: "#/components/schemas/BatchUploadSummary" total_count: type: integer format: int32 minimum: 0 maximum: 2147483647 description: Total number of batches for this client example: 25 ClientName: type: string description: The client name example: AArete maxLength: 256 pattern: "^.+$" ClientCanSync: type: boolean description: If the client is allowing active syncs DocClient: description: The properties of a client. type: object properties: id: $ref: "#/components/schemas/ClientID" name: $ref: "#/components/schemas/ClientName" can_sync: $ref: "#/components/schemas/ClientCanSync" required: - id - name - can_sync ClientStatus: type: string enum: - IN_SYNC - NOT_SYNCED - NOT_SYNCING description: Specifies the status of a client. ClientStatusBody: description: A client status information object. type: object properties: status: $ref: "#/components/schemas/ClientStatus" required: - status ClientIDBody: description: The client id. type: object properties: id: $ref: "#/components/schemas/ClientID" required: - id ClientListResponse: description: Response containing a list of all clients. type: object properties: clients: type: array description: List of clients in the system. maxItems: 10000 items: $ref: "#/components/schemas/DocClient" totalCount: type: integer format: int32 description: Total number of clients. minimum: 0 maximum: 2147483647 required: - clients - totalCount UISettingCreate: type: object description: Request body for creating a UI setting required: - namespace - key - value properties: namespace: type: string maxLength: 255 description: Scope for the setting (e.g. demo-dashboard:{userId}, feature-flags:global, saved-filters:{clientId}) key: type: string maxLength: 255 description: Setting key within the namespace value: type: object description: JSON value (object) for the setting UISetting: type: object description: A UI setting record required: - id - namespace - key - value - isDeleted - createdAt - updatedAt properties: id: type: string format: uuid maxLength: 36 namespace: type: string maxLength: 255 key: type: string maxLength: 255 value: type: object isDeleted: type: boolean createdAt: type: string format: date-time maxLength: 32 updatedAt: type: string format: date-time maxLength: 32 UISettingUpdate: type: object description: Request body for updating a UI setting required: - value properties: value: type: object description: New JSON value for the setting UISettingListResponse: type: object description: List of UI settings required: - settings - totalCount properties: settings: type: array maxItems: 10000 items: $ref: "#/components/schemas/UISetting" totalCount: type: integer format: int32 minimum: 0 maximum: 10000 ListDocuments: type: array description: The documents in the client. maxItems: 256 items: $ref: "#/components/schemas/DocumentSummary" Hash: type: string description: The document hash maxLength: 2048 pattern: "^.+$" DocumentSummary: description: The document summary properties. type: object properties: id: $ref: "#/components/schemas/DocumentID" hash: $ref: "#/components/schemas/Hash" required: - id - hash DocumentEnriched: description: Enriched document details with additional metadata type: object required: - id - client_id - hash - hasTextRecord - labels properties: id: $ref: "#/components/schemas/DocumentID" client_id: $ref: "#/components/schemas/ClientID" hash: $ref: "#/components/schemas/Hash" hasTextRecord: type: boolean description: "Whether a text extraction (field extraction) record exists for this document" folderId: type: string format: uuid maxLength: 50 description: "Parent folder ID, null if document is not in a folder" filename: type: string maxLength: 4096 description: "Original filename of the document" originalPath: type: string maxLength: 4096 description: "Original path provided during upload (immutable)" labels: type: array maxItems: 1000 items: $ref: "#/components/schemas/LabelRecord" description: "All labels applied to this document" textRecord: $ref: "#/components/schemas/FieldExtractionResponse" fileSizeBytes: type: integer format: int64 minimum: 0 maximum: 4294967295 description: "File size in bytes (null for legacy documents)" DocumentInFolder: description: Document within a folder with enriched metadata (lighter format, excludes client_id and fields) type: object required: - id - hash - hasTextRecord - labels properties: id: $ref: "#/components/schemas/DocumentID" hash: $ref: "#/components/schemas/Hash" hasTextRecord: type: boolean description: "Whether a text extraction record exists for this document" folderId: type: string format: uuid maxLength: 50 description: "Parent folder ID" filename: type: string maxLength: 4096 description: "Original filename of the document" originalPath: type: string maxLength: 4096 description: "Original path provided during upload (immutable)" labels: type: array maxItems: 1000 items: $ref: "#/components/schemas/LabelRecord" description: "All labels applied to this document" textRecord: $ref: "#/components/schemas/FieldExtractionResponse" fileSizeBytes: type: integer format: int64 minimum: 0 maximum: 4294967295 description: "File size in bytes (null for legacy documents)" ClientCreate: description: The properties for creation. type: object properties: id: $ref: "#/components/schemas/ClientID" name: $ref: "#/components/schemas/ClientName" required: - id - name ClientUpdate: description: The properties that may be updated. type: object properties: name: $ref: "#/components/schemas/ClientName" can_sync: $ref: "#/components/schemas/ClientCanSync" IdMessage: description: A single uuid. type: object properties: id: type: string format: uuid description: Unique identifier for entity. maxLength: 36 required: - id CodeVersion: type: integer format: int64 minimum: 1 maximum: 9223372036854775808 description: The desired code version. Version: type: integer format: int32 minimum: 0 maximum: 2147483647 description: The desired version. Collector: type: object properties: client_id: $ref: "#/components/schemas/ClientID" active_version: $ref: "#/components/schemas/Version" latest_version: $ref: "#/components/schemas/Version" minimum_cleaner_version: $ref: "#/components/schemas/CodeVersion" description: Collector model. Note - minimum_text_version has been removed since text extraction is deprecated. required: - client_id - minimum_cleaner_version - latest_version - active_version CollectorSet: type: object properties: minimum_cleaner_version: $ref: "#/components/schemas/CodeVersion" active_version: $ref: "#/components/schemas/Version" description: Payload for updating a Collector. Note - minimum_text_version has been removed. CollectorFieldName: type: string pattern: "^.+$" maxLength: 256 description: The output field name. ExportTrigger: type: object properties: ingestion_filters: type: object description: Filter the scope based on ingestion parameters. properties: start_date: type: string format: date-time maxLength: 32 description: This first date of ingestion. end_date: type: string format: date-time maxLength: 32 description: The last date of ingestion. field_filters: type: array maxItems: 256 description: Filter the scope based on field output values. items: $ref: "#/components/schemas/FieldFilter" description: Payload for triggering an export. FieldFilter: type: object properties: field_name: $ref: "#/components/schemas/CollectorFieldName" condition: $ref: "#/components/schemas/FieldFilterCondition" values: type: array description: The values useful to the filter. maxItems: 100 items: type: string pattern: "^.+$" maxLength: 256 description: Filtering a column required: - field_name - condition - values FieldFilterCondition: type: string enum: - less_than - greater_than - closed_interval - open_interval - left_closed_interval - right_closed_interval - include - exclude description: The possible field filtering conditions. ExportStatus: type: string enum: - completed - in_progress - failed description: The possible export states. ExportDetails: type: object properties: client_id: $ref: "#/components/schemas/ClientID" status: $ref: "#/components/schemas/ExportStatus" output_location: type: string description: The location in which the export zip file will be found. example: s3://a/A/export/20250213/uuid.csv maxLength: 2048 pattern: '^s3://.+/.+/export/[0-9]{8}/.+\.csv$' description: Payload for export trigger response. required: - client_id - status ErrorMessage: description: Description of error type: object properties: message: type: string pattern: "^.+$" description: Message describing the cause. maxLength: 256 example: "you must give me good information" error_type: type: string description: Machine-readable error classification for programmatic handling. maxLength: 64 example: "UserNotFound" details: type: string description: Additional error details for debugging (sanitized). maxLength: 512 example: "The specified user does not exist in Cognito" required: - message example: message: you must include a message error_type: InvalidParameter details: The email format is invalid # Identity API schemas IdentityRole: type: object description: A role assigned to the user with its permissions required: - key - name - permissions properties: key: type: string description: The role key/identifier maxLength: 128 pattern: "^[a-z0-9_-]+$" example: "auditor" name: type: string description: Human-readable role name maxLength: 256 pattern: "^.+$" example: "Auditor" description: type: string description: Optional description of the role maxLength: 1024 example: "Read-only access to view documents and exports" permissions: type: array description: List of permissions granted by this role maxItems: 500 items: type: string maxLength: 128 pattern: "^[a-z0-9_-]+:[a-z0-9_-]+$" example: ["document:read", "document:list", "export:read"] IdentityResponse: type: object description: Response containing the user's roles and their permissions required: - roles properties: roles: type: array description: List of roles assigned to the user with their permissions maxItems: 100 items: $ref: "#/components/schemas/IdentityRole" # Admin API schemas AdminUserCreate: description: Request body for creating a new user with email, name, and role assignments type: object required: - email - first_name - last_name - roles properties: email: type: string format: email maxLength: 320 pattern: '^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$' description: User email address (used as Cognito username) example: john.doe@example.com first_name: type: string minLength: 1 maxLength: 100 pattern: "^.+$" description: User's given name for account creation example: John last_name: type: string minLength: 1 maxLength: 100 pattern: "^.+$" description: User's family name for account creation example: Doe roles: type: array minItems: 1 maxItems: 50 items: type: string pattern: "^.+$" maxLength: 100 description: >- List of role keys to assign in Permit.io (e.g., super_admin, user_admin, auditor, client_user). Roles must exist in your Permit.io environment. Invalid roles fail silently - check roles_assigned in response. example: ["user_admin", "auditor"] AdminUserCreateResponse: description: Response after creating a user, including Cognito subject ID and sync status type: object required: - cognito_subject_id - email - status - permit_synced properties: cognito_subject_id: type: string maxLength: 256 pattern: "^.+$" description: Created user's Cognito unique subject identifier example: a1b2c3d4-e5f6-7890-abcd-ef1234567890 email: type: string format: email maxLength: 320 description: User email address example: john.doe@example.com first_name: type: string maxLength: 100 pattern: "^.+$" description: Created user's given name example: John last_name: type: string maxLength: 100 pattern: "^.+$" description: Created user's family name example: Doe status: type: string maxLength: 50 pattern: "^.+$" description: Cognito user status example: FORCE_CHANGE_PASSWORD enabled: type: boolean description: Whether the created user is enabled in Cognito example: true permit_synced: type: boolean description: >- Whether user was successfully created in Permit.io authorization system. If false, user exists in Cognito (can authenticate) but not in Permit.io (has no authorization/permissions). Manual sync or retry may be required. example: true roles_assigned: type: array maxItems: 50 items: type: string maxLength: 100 pattern: "^.+$" description: >- Roles that were successfully assigned in Permit.io. May be a subset of requested roles if some failed. Compare with requested roles array to detect assignment failures. If null or empty, no roles were assigned (user has no permissions). Only present if permit_synced is true. example: ["user_admin", "auditor"] created_at: type: string format: date-time maxLength: 50 description: Timestamp when the user was created in the system example: "2025-10-16T14:23:45Z" AdminUserDetails: description: Complete user information from Cognito and Permit.io including roles and timestamps type: object required: - cognito_subject_id - email - status - enabled properties: cognito_subject_id: type: string maxLength: 256 pattern: "^.+$" description: User's Cognito unique subject identifier from authentication system example: a1b2c3d4-e5f6-7890-abcd-ef1234567890 email: type: string format: email maxLength: 320 description: Email address of the user account example: john.doe@example.com first_name: type: string maxLength: 100 pattern: "^.+$" description: User's given name retrieved from Cognito example: John last_name: type: string maxLength: 100 pattern: "^.+$" description: User's family name retrieved from Cognito example: Doe status: type: string maxLength: 50 pattern: "^.+$" description: Current Cognito user account status example: CONFIRMED enabled: type: boolean description: Current enabled status of the user in Cognito example: true roles: type: array maxItems: 50 items: type: string maxLength: 100 pattern: "^.+$" description: >- Roles assigned in Permit.io. Only populated by GET /admin/users/{email}. Not populated by GET /admin/users (list endpoint) for performance reasons. example: ["admin", "viewer"] created_at: type: string format: date-time maxLength: 50 description: Timestamp when the user account was created example: "2025-10-15T09:15:30Z" updated_at: type: string format: date-time maxLength: 50 description: Timestamp of last update example: "2025-10-16T14:20:10Z" AdminUserUpdate: description: Request body for updating user attributes (first name, last name, and roles) type: object properties: first_name: type: string minLength: 1 maxLength: 100 pattern: "^.+$" description: Updated given name for the user example: Jonathan last_name: type: string minLength: 1 maxLength: 100 pattern: "^.+$" description: Updated family name for the user example: Doe-Smith roles: type: array minItems: 1 maxItems: 50 items: type: string pattern: "^.+$" maxLength: 100 description: >- Complete list of role keys to assign in Permit.io - REPLACES all existing roles (not additive). To add a role, include all current roles plus the new one. To remove a role, omit it from the array. Roles must exist in Permit.io environment. Invalid roles fail silently - check response.roles for final state. Omit this field entirely to leave roles unchanged. example: ["user_admin", "auditor"] AdminUserList: description: Paginated list of users with total count and pagination metadata type: object required: - users - total - page - page_size properties: users: type: array maxItems: 100 items: $ref: '#/components/schemas/AdminUserDetails' description: List of users for current page total: type: integer format: int32 minimum: 0 maximum: 2147483647 description: Total number of users matching filter example: 147 page: type: integer format: int32 minimum: 1 maximum: 10000 description: Current page number example: 1 page_size: type: integer format: int32 minimum: 1 maximum: 100 description: Number of users per page example: 20 has_more: type: boolean description: Whether more pages are available example: true AdminUserActionResponse: description: Response for user enable/disable actions with success status and timestamp type: object required: - success - email - action properties: success: type: boolean description: Whether the action succeeded example: true email: type: string format: email maxLength: 320 description: Email of the user acted upon example: john.doe@example.com action: type: string enum: [disable, enable] description: Action performed example: disable cognito_subject_id: type: string maxLength: 256 pattern: "^.+$" description: Cognito subject identifier for the action response example: a1b2c3d4-e5f6-7890-abcd-ef1234567890 timestamp: type: string format: date-time maxLength: 50 description: Timestamp of the action example: "2025-10-16T14:25:33Z" AdminUserDeleteResponse: description: Response for user deletion with status from each system (Cognito and Permit.io) type: object required: - success - email - deleted_from properties: success: type: boolean description: Whether the deletion succeeded example: true email: type: string format: email maxLength: 320 description: Email of the deleted user example: john.doe@example.com cognito_subject_id: type: string maxLength: 256 pattern: "^.+$" description: Cognito subject identifier of the deleted user example: a1b2c3d4-e5f6-7890-abcd-ef1234567890 deleted_from: type: object required: - cognito - permit properties: cognito: type: boolean description: Whether user was deleted from Cognito example: true permit: type: boolean description: Whether user was deleted from Permit.io example: true description: Deletion status from each system timestamp: type: string format: date-time maxLength: 50 description: Timestamp of the deletion example: "2025-10-16T14:27:15Z" # Folder schemas FolderCreate: description: Request to create a new folder for organizing documents type: object required: - path - clientId - createdBy properties: path: type: string maxLength: 1000 pattern: "^/.*$" description: Folder path (must start with /). Use "/" for root folder. example: "/documents/2024" parentId: type: string format: uuid maxLength: 50 description: Optional parent folder ID example: "019580df-ef65-7676-8de9-94435a93337a" clientId: $ref: "#/components/schemas/ClientID" createdBy: type: string format: email maxLength: 320 description: Email of user who created the folder example: user@example.com FolderRename: description: Request to rename an existing folder type: object required: - path properties: path: type: string maxLength: 1000 pattern: "^/.*$" description: New folder path (must start with /). Use "/" for root folder. example: "/documents/2024-renamed" Folder: description: Folder information for organizing documents type: object required: - id - path - clientId - createdAt - createdBy properties: id: type: string format: uuid maxLength: 50 description: Folder ID example: "019580df-ef65-7676-8de9-94435a93337a" path: type: string maxLength: 1000 pattern: "^/.*$" description: Folder path (must start with /). Root folder has path "/". example: "/documents/2024" parentId: type: string format: uuid maxLength: 50 nullable: true description: Parent folder ID example: "019580df-ef65-7676-8de9-94435a93337b" clientId: $ref: "#/components/schemas/ClientID" createdAt: type: string format: date-time maxLength: 50 description: Creation timestamp example: "2025-10-16T14:27:15Z" createdBy: type: string format: email maxLength: 320 description: Email of the user who created this folder example: user@example.com metrics: allOf: - $ref: "#/components/schemas/FolderMetricsInline" nullable: true description: | Processing metrics for this folder. Only populated when metrics=true is specified in the request. Null otherwise. FolderList: description: List of folders for a client type: object required: - folders properties: folders: type: array maxItems: 10000 description: | List of folders. Each folder includes its ID, path, and parentId. Root-level folders have parentId set to null. Clients can use parentId to reconstruct the folder hierarchy/tree structure. items: $ref: "#/components/schemas/Folder" FolderMetrics: description: Processing metrics for a folder including document counts type: object required: - folderId - totalDocuments - byLabel properties: folderId: type: string format: uuid maxLength: 50 description: Unique identifier for the folder example: "019580df-ef65-7676-8de9-94435a93337a" totalDocuments: type: integer format: int32 minimum: 0 maximum: 1000000 description: Total number of documents in folder example: 150 byLabel: type: object maxProperties: 100 additionalProperties: type: integer format: int32 minimum: 0 maximum: 1000000 description: Document counts by label example: Ingested: 150 OCR_Processed: 120 Dashboard_Ready: 100 FolderMetricsInline: description: Inline processing metrics for a folder (excludes folderId since it's on parent) type: object required: - totalDocuments - byLabel properties: totalDocuments: type: integer format: int32 minimum: 0 maximum: 1000000 description: Total number of documents in folder example: 150 byLabel: type: object maxProperties: 100 additionalProperties: type: integer format: int32 minimum: 0 maximum: 1000000 description: Document counts by label example: Ingested: 150 OCR_Processed: 120 Dashboard_Ready: 100 # Label schemas LabelApplication: description: Request to apply a workflow label to a document type: object required: - label - appliedBy properties: label: type: string maxLength: 100 pattern: "^[A-Za-z0-9_]+$" description: Label name (alphanumeric and underscore only) example: "OCR_Processed" appliedBy: type: string format: email maxLength: 320 description: Email of user applying the label example: user@example.com LabelRecord: description: Record of a label applied to a document type: object required: - id - documentId - label - appliedBy - appliedAt properties: id: type: string format: uuid maxLength: 50 description: Label record ID example: "019580df-ef65-7676-8de9-94435a93337a" documentId: $ref: "#/components/schemas/DocumentID" label: type: string maxLength: 100 pattern: "^[A-Za-z0-9_]+$" description: Workflow label name (alphanumeric and underscore only) example: "OCR_Processed" appliedBy: type: string format: email maxLength: 320 description: Email of the user who applied this label example: user@example.com appliedAt: type: string format: date-time maxLength: 50 description: Timestamp when label was applied example: "2025-10-16T14:27:15Z" # Field Extraction schemas FieldExtractionRequest: description: Request to create a new field extraction with single and array fields type: object required: - documentId - singleFields - arrayFields - createdBy properties: documentId: $ref: "#/components/schemas/DocumentID" singleFields: $ref: "#/components/schemas/SingleFields" arrayFields: type: array maxItems: 10000 items: $ref: "#/components/schemas/ArrayFieldItem" description: Array of field extraction items (all must have consistent structure) createdBy: type: string format: email maxLength: 320 description: Email of user creating the extraction example: user@example.com SingleFields: description: Single-value fields for a document extraction (1:1 relationship) type: object properties: fileName: type: string maxLength: 500 description: Original file name example: "contract_2024.pdf" contractTitle: type: string maxLength: 500 description: Title of the contract aareteDerivedAmendmentNum: type: integer format: int32 minimum: 0 maximum: 999 description: Amendment number derived by Aarete clientName: type: string maxLength: 500 description: Name of the client payerName: type: string maxLength: 500 description: Name of the payer payerState: type: string maxLength: 2 pattern: "^[A-Z]{2}$" description: Two-letter state code for payer example: "CA" providerState: type: string maxLength: 2 pattern: "^[A-Z]{2}$" description: Two-letter state code for provider example: "NY" filenameTin: type: string maxLength: 20 description: Tax Identification Number from filename provGroupTin: type: string maxLength: 20 description: Provider group TIN provGroupNpi: type: string maxLength: 20 description: Provider group NPI provGroupNameFull: type: string maxLength: 500 description: Full name of provider group provOtherTin: type: string maxLength: 20 description: Other provider TIN provOtherNpi: type: string maxLength: 20 description: Other provider NPI provOtherNameFull: type: string maxLength: 500 description: Full name of other provider aareteDerivedEffectiveDt: type: string format: date maxLength: 50 description: Contract effective date example: "2024-01-01" aareteDerivedTerminationDt: type: string format: date maxLength: 50 description: Contract termination date example: "2025-12-31" autoRenewalInd: type: boolean description: Auto-renewal indicator autoRenewalTerm: type: string maxLength: 200 description: Auto-renewal terms ArrayFieldItem: description: Single row of array field data (112 fields forming one row) type: object properties: exhibitTitle: type: string maxLength: 500 exhibitPage: type: string maxLength: 100 reimbProvTin: type: string maxLength: 20 reimbProvNpi: type: string maxLength: 20 reimbProvName: type: string maxLength: 500 reimbEffectiveDt: type: string format: date maxLength: 50 reimbTerminationDt: type: string format: date maxLength: 50 aareteDerivedClaimTypeCd: type: string maxLength: 100 aareteDerivedProduct: type: string maxLength: 200 aareteDerivedLob: type: string maxLength: 200 aareteDerivedProgram: type: string maxLength: 200 aareteDerivedNetwork: type: string maxLength: 200 aareteDerivedProvType: type: string maxLength: 200 provTaxonomyCd: type: string maxLength: 100 provTaxonomyCdDesc: type: string maxLength: 500 provSpecialtyCd: type: string maxLength: 100 provSpecialtyCdDesc: type: string maxLength: 500 placeOfServiceCd: type: string maxLength: 100 placeOfServiceCdDesc: type: string maxLength: 500 billTypeCd: type: string maxLength: 100 billTypeCdDesc: type: string maxLength: 500 patientAgeMin: type: string maxLength: 50 patientAgeMax: type: string maxLength: 50 reimbTerm: type: string maxLength: 500 lobProgramRelationship: type: string maxLength: 200 lobProductRelationship: type: string maxLength: 200 carveoutInd: type: boolean carveoutCd: type: string maxLength: 100 lesserOfInd: type: boolean greaterOfInd: type: boolean aareteDerivedReimbMethod: type: string maxLength: 200 unitOfMeasure: type: string maxLength: 100 reimbPctRate: type: number format: double minimum: 0 maximum: 999.9999 reimbFeeRate: type: number format: double minimum: 0 maximum: 9999999999.99 reimbConversionFactor: type: number format: double minimum: 0 maximum: 99999999.9999 triggerCapThresholdAmt: type: number format: double minimum: 0 maximum: 9999999999.99 triggerBaseThreshold: type: number format: double minimum: 0 maximum: 9999999999.99 defaultInd: type: boolean additionDesc: type: string maxLength: 1000 additionMaxFeeRateInc: type: number format: double minimum: 0 maximum: 9999999999.99 additionMaxPctRateInc: type: number format: double minimum: 0 maximum: 999.9999 aareteDerivedAdditionRateChangeTimeline: type: string maxLength: 200 aareteDerivedFeeSchedule: type: string maxLength: 200 aareteDerivedFeeScheduleVersion: type: string maxLength: 100 serviceTerm: type: string maxLength: 500 cpt4ProcCd: type: string maxLength: 100 cpt4ProcCdDesc: type: string maxLength: 500 cpt4ProcMod: type: string maxLength: 100 cpt4ProcModDesc: type: string maxLength: 500 revenueCd: type: string maxLength: 100 revenueCdDesc: type: string maxLength: 500 diagCd: type: string maxLength: 100 diagCdDesc: type: string maxLength: 500 ndcCd: type: string maxLength: 100 ndcCdDesc: type: string maxLength: 500 claimAdmitTypeCd: type: string maxLength: 100 authAdmitTypeDesc: type: string maxLength: 500 claimStatusCd: type: string maxLength: 100 claimStatusCdDesc: type: string maxLength: 500 grouperType: type: string maxLength: 100 grouperCd: type: string maxLength: 100 grouperCdDesc: type: string maxLength: 500 grouperPctRate: type: number format: double minimum: 0 maximum: 999.9999 grouperBaseRate: type: number format: double minimum: 0 maximum: 9999999999.99 # Grouper Extended Fields aareteDerivedGrouperVersion: type: string maxLength: 200 grouperAlternativeLevelOfCare: type: string maxLength: 200 grouperSeverityInd: type: boolean grouperSeverity: type: string maxLength: 100 grouperRiskOfMortalitySubclass: type: string maxLength: 100 grouperTransferInd: type: boolean grouperReadmissionsInd: type: boolean grouperHacInd: type: boolean # Outlier Fields outlierTerm: type: string maxLength: 500 outlierFirstDollarInd: type: boolean rangeNbrDays: type: string maxLength: 100 outlierFixedLossNbrDaysThreshold: type: number format: double minimum: 0 maximum: 99999999.99 outlierFixedLossThreshold: type: number format: double minimum: 0 maximum: 9999999999.99 outlierMaximum: type: number format: double minimum: 0 maximum: 9999999999.99 outlierMaximumFrequency: type: number format: double minimum: 0 maximum: 99999999.99 outlierPctRate: type: number format: double minimum: 0 maximum: 999.9999 outlierExclusionCd: type: string maxLength: 100 outlierExclusionCdDesc: type: string maxLength: 500 # Facility Adjustment Fields facilityAdjustmentTerm: type: string maxLength: 500 dshInd: type: boolean dshPctRate: type: number format: double minimum: 0 maximum: 999.9999 dshFeeRate: type: number format: double minimum: 0 maximum: 9999999999.99 imeInd: type: boolean imePctRate: type: number format: double minimum: 0 maximum: 999.9999 imeFeeRate: type: number format: double minimum: 0 maximum: 9999999999.99 ntapInd: type: boolean ntapPctRate: type: number format: double minimum: 0 maximum: 999.9999 ntapFeeRate: type: number format: double minimum: 0 maximum: 9999999999.99 ucInd: type: boolean ucPctRate: type: number format: double minimum: 0 maximum: 999.9999 ucFeeRate: type: number format: double minimum: 0 maximum: 9999999999.99 gmeInd: type: boolean gmePctRate: type: number format: double minimum: 0 maximum: 999.9999 gmeFeeRate: type: number format: double minimum: 0 maximum: 9999999999.99 # Rate Escalator Fields rateEscalatorInd: type: boolean rateEscalatorDesc: type: string maxLength: 500 rateEscalatorMaxRateIncPct: type: number format: double minimum: 0 maximum: 999.9999 rateEscalatorRateChangeTimeline: type: number format: double minimum: 0 maximum: 99999999.99 # Stop Loss Fields stopLossTerm: type: string maxLength: 500 stopLossFirstDollarInd: type: boolean stopLossRangeNbrDays: type: number format: double minimum: 0 maximum: 99999999.99 stopLossFixedLossThreshold: type: number format: double minimum: 0 maximum: 9999999999.99 stopLossMaximum: type: number format: double minimum: 0 maximum: 9999999999.99 stopLossMaximumFrequency: type: number format: double minimum: 0 maximum: 99999999.99 stopLossDailyMaxRate: type: number format: double minimum: 0 maximum: 9999999999.99 stopLossPctRateOnExcessCharges: type: number format: double minimum: 0 maximum: 999.9999 stopLossExclusionCd: type: string maxLength: 100 stopLossExclusionDesc: type: string maxLength: 500 FieldExtractionResponse: description: Field extraction with version information type: object required: - id - documentId - version - singleFields - arrayFields - createdAt - createdBy properties: id: type: string format: uuid maxLength: 50 description: Field extraction ID example: "019580df-ef65-7676-8de9-94435a93337a" documentId: $ref: "#/components/schemas/DocumentID" version: type: integer format: int32 minimum: 1 maximum: 9999 description: Version number (1-based) example: 1 singleFields: $ref: "#/components/schemas/SingleFields" arrayFields: type: array maxItems: 10000 items: $ref: "#/components/schemas/ArrayFieldItem" description: Array of field extraction items createdAt: type: string format: date-time maxLength: 50 description: Creation timestamp example: "2025-10-16T14:27:15Z" createdBy: type: string format: email maxLength: 320 description: Email of user who created this extraction example: user@example.com FieldExtractionVersion: description: Field extraction version summary for history type: object required: - id - documentId - version - createdAt - createdBy properties: id: type: string format: uuid maxLength: 50 description: Field extraction ID example: "019580df-ef65-7676-8de9-94435a93337a" documentId: $ref: "#/components/schemas/DocumentID" version: type: integer format: int32 minimum: 1 maximum: 9999 description: Version number (1-based) example: 1 createdAt: type: string format: date-time maxLength: 50 description: Creation timestamp example: "2025-10-16T14:27:15Z" createdBy: type: string format: email maxLength: 320 description: Email of user who created this version example: user@example.com # EULA Schemas EulaVersion: description: Full EULA version details type: object required: - id - version - title - content - createdAt - createdBy - isCurrent properties: id: type: string format: uuid maxLength: 36 description: EULA version ID version: type: string maxLength: 50 pattern: "^.+$" description: Version string (e.g., "1.0", "2024-01") example: "1.0" title: type: string maxLength: 500 pattern: "^.+$" description: Human-readable title example: "Terms of Service v1.0" content: type: string maxLength: 1048576 description: Full EULA text in Markdown format example: "# Terms of Service\n\n## Section 1\n\nBy using this service..." effectiveDate: type: string format: date-time maxLength: 50 nullable: true description: When this version becomes effective (optional) example: "2026-01-01T00:00:00Z" createdAt: type: string format: date-time maxLength: 50 description: Creation timestamp example: "2025-12-15T10:30:00Z" createdBy: type: string maxLength: 320 description: Identifier of admin who created this version (email, username, or subject ID) example: admin@example.com isCurrent: type: boolean description: Whether this is the current active version example: true activatedAt: type: string format: date-time maxLength: 50 nullable: true description: When this version was activated example: "2026-01-01T00:00:00Z" activatedBy: type: string maxLength: 320 nullable: true description: Identifier of admin who activated this version (email, username, or subject ID) example: admin@example.com EulaVersionSummary: description: Abbreviated EULA version for lists type: object required: - id - version - title - isCurrent properties: id: type: string format: uuid maxLength: 36 description: EULA version ID version: type: string maxLength: 50 pattern: "^.+$" description: Version string example: "1.0" title: type: string maxLength: 500 pattern: "^.+$" description: Human-readable title example: "Terms of Service v1.0" effectiveDate: type: string format: date-time maxLength: 50 nullable: true description: When this version becomes effective (optional) example: "2026-01-01T00:00:00Z" isCurrent: type: boolean description: Whether this is the current active version example: true EulaVersionCreate: description: Request body for creating a new EULA version type: object required: - version - title - content properties: version: type: string maxLength: 50 minLength: 1 pattern: "^.+$" description: Version string (must be unique) example: "1.0" title: type: string maxLength: 500 minLength: 1 pattern: "^.+$" description: Human-readable title example: "Terms of Service v1.0" content: type: string maxLength: 1048576 minLength: 1 description: Full EULA text in Markdown format example: "# Terms of Service\n\n## Section 1\n\nBy using this service..." effectiveDate: type: string format: date-time maxLength: 50 nullable: true description: When this version becomes effective (optional) example: "2026-01-01T00:00:00Z" EulaVersionUpdate: description: Request body for updating EULA version metadata type: object properties: title: type: string maxLength: 500 minLength: 1 pattern: "^.+$" description: Human-readable title example: "Terms of Service v1.0 (Updated)" effectiveDate: type: string format: date-time maxLength: 50 description: When this version becomes effective example: "2026-01-15T00:00:00Z" EulaVersionList: description: Paginated list of EULA versions type: object required: - versions - total - page - page_size properties: versions: type: array maxItems: 100 items: $ref: "#/components/schemas/EulaVersion" description: List of EULA versions total: type: integer format: int32 minimum: 0 maximum: 2147483647 description: Total number of EULA versions example: 5 page: type: integer format: int32 minimum: 1 maximum: 10000 description: Current page number example: 1 page_size: type: integer format: int32 minimum: 1 maximum: 100 description: Number of items per page example: 20 has_more: type: boolean description: Whether more pages are available example: false EulaPublicResponse: description: Public response for current EULA version type: object required: - id - version - title - content properties: id: type: string format: uuid maxLength: 36 description: EULA version ID version: type: string maxLength: 50 pattern: "^.+$" description: Version string example: "1.0" title: type: string maxLength: 500 pattern: "^.+$" description: Human-readable title example: "Terms of Service v1.0" content: type: string maxLength: 1048576 description: Full EULA text in Markdown format example: "# Terms of Service\n\n## Section 1\n\nBy using this service..." effectiveDate: type: string format: date-time maxLength: 50 nullable: true description: When this version became effective (optional) example: "2026-01-01T00:00:00Z" EulaStatusResponse: description: User's EULA agreement status type: object required: - hasAgreed - currentVersion - currentVersionId properties: hasAgreed: type: boolean description: Whether the user has agreed to the current EULA example: true currentVersion: type: string maxLength: 50 pattern: "^.+$" description: Current EULA version string example: "2.0" currentVersionId: type: string format: uuid maxLength: 36 description: EULA version ID agreedAt: type: string format: date-time maxLength: 50 nullable: true description: When the user agreed (null if not agreed) example: "2026-01-15T10:30:00Z" agreedVersion: type: string maxLength: 50 nullable: true description: Version the user agreed to (null if not agreed) example: "2.0" EulaAgreementResponse: description: Response after recording an agreement type: object required: - id - eulaVersionId - eulaVersion - agreedAt properties: id: type: string format: uuid maxLength: 36 description: Agreement record ID example: "019580df-ef65-7676-8de9-94435a93337a" eulaVersionId: type: string format: uuid maxLength: 36 description: EULA version ID eulaVersion: type: string maxLength: 50 pattern: "^.+$" description: EULA version string example: "1.0" agreedAt: type: string format: date-time maxLength: 50 description: When the agreement was recorded example: "2026-01-15T10:30:00Z" EulaAgreement: description: EULA agreement record type: object required: - id - cognitoSubjectId - userEmail - eulaVersionId - eulaVersion - agreedAt - agreedFromIp properties: id: type: string format: uuid maxLength: 36 description: Agreement record ID example: "019580df-ef65-7676-8de9-94435a93337a" cognitoSubjectId: type: string maxLength: 256 pattern: "^.+$" description: User's Cognito subject ID example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" userEmail: type: string maxLength: 320 description: User identifier at time of agreement (email, username, or subject ID) example: user@example.com eulaVersionId: type: string format: uuid maxLength: 36 description: EULA version ID eulaVersion: type: string maxLength: 50 pattern: "^.+$" description: EULA version string example: "1.0" eulaVersionTitle: type: string maxLength: 500 description: EULA version title (for user history view) example: "Terms of Service v1.0" agreedAt: type: string format: date-time maxLength: 50 description: When the agreement was recorded example: "2026-01-15T10:30:00Z" agreedFromIp: type: string maxLength: 45 description: IP address from which the user agreed example: "192.168.1.100" EulaAgreementList: description: Paginated list of EULA agreements type: object required: - agreements - total - page - page_size properties: agreements: type: array maxItems: 100 items: $ref: "#/components/schemas/EulaAgreement" description: List of EULA agreements total: type: integer format: int32 minimum: 0 maximum: 2147483647 description: Total number of agreements matching filter example: 150 page: type: integer format: int32 minimum: 1 maximum: 10000 description: Current page number example: 1 page_size: type: integer format: int32 minimum: 1 maximum: 100 description: Number of items per page example: 20 has_more: type: boolean description: Whether more pages are available example: true EulaComplianceReport: description: EULA compliance report with user agreement status type: object required: - eulaVersion - summary - users - pagination properties: eulaVersion: $ref: "#/components/schemas/EulaVersionSummary" summary: $ref: "#/components/schemas/EulaComplianceSummary" users: type: array maxItems: 100 items: $ref: "#/components/schemas/EulaComplianceUser" description: Unified list of users with agreement status pagination: $ref: "#/components/schemas/EulaCompliancePagination" EulaComplianceSummary: description: Summary statistics for compliance report type: object required: - totalUsers - agreedCount - notAgreedCount - compliancePercentage properties: totalUsers: type: integer format: int32 minimum: 0 maximum: 2147483647 description: Total number of users in the system example: 150 agreedCount: type: integer format: int32 minimum: 0 maximum: 2147483647 description: Number of users who have agreed example: 120 notAgreedCount: type: integer format: int32 minimum: 0 maximum: 2147483647 description: Number of users who have not agreed example: 30 compliancePercentage: type: number format: float minimum: 0 maximum: 100 description: Percentage of users who have agreed example: 80.0 EulaComplianceUser: description: User record in compliance report type: object required: - cognitoSubjectId - currentEmail - agreed properties: cognitoSubjectId: type: string maxLength: 256 pattern: "^.+$" description: User's Cognito subject ID example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" email: type: string maxLength: 320 nullable: true description: User identifier at time of agreement (email, username, or subject ID; null if not agreed) example: user@example.com currentEmail: type: string maxLength: 320 description: User's current email from Cognito (may be empty or a non-email identifier) example: user-updated@example.com agreed: type: boolean description: Whether the user has agreed to this EULA version example: true agreedAt: type: string format: date-time maxLength: 50 nullable: true description: When the user agreed (null if not agreed) example: "2026-01-15T10:30:00Z" agreedFromIp: type: string maxLength: 45 nullable: true description: IP address from which the user agreed (null if not agreed) example: "192.168.1.100" EulaCompliancePagination: description: Pagination information for compliance report type: object required: - page - pageSize - totalPages - totalItems properties: page: type: integer format: int32 minimum: 1 maximum: 10000 description: Current page number example: 1 pageSize: type: integer format: int32 minimum: 1 maximum: 100 description: Number of items per page example: 50 totalPages: type: integer format: int32 minimum: 0 maximum: 10000 description: Total number of pages example: 3 totalItems: type: integer format: int32 minimum: 0 maximum: 2147483647 description: Total number of items example: 150 DeleteResponse: description: Response for hard-delete operations when verbose=true type: object required: - deletedDocuments properties: deletedDocuments: type: array description: S3 paths of orphaned source documents (only populated when verbose=true) maxItems: 100000 items: type: object required: - documentId - s3Path properties: documentId: type: string format: uuid maxLength: 36 description: ID of the deleted document s3Path: type: string maxLength: 1024 description: Full S3 path (s3://bucket/key) of the orphaned source file