From f9a3606ca2aa1dde53eb5dfbc3548ed02aea348f Mon Sep 17 00:00:00 2001 From: perf3ct Date: Wed, 20 Aug 2025 17:11:54 +0000 Subject: [PATCH] feat(docs): implement swagger ui endpoint for internal api --- apps/server/src/assets/api-openapi.yaml | 4112 +++++++++++++++++++++++ apps/server/src/routes/api_docs.ts | 17 +- 2 files changed, 4126 insertions(+), 3 deletions(-) create mode 100644 apps/server/src/assets/api-openapi.yaml diff --git a/apps/server/src/assets/api-openapi.yaml b/apps/server/src/assets/api-openapi.yaml new file mode 100644 index 000000000..f8b5ebf81 --- /dev/null +++ b/apps/server/src/assets/api-openapi.yaml @@ -0,0 +1,4112 @@ +openapi: 3.1.0 +info: + title: Trilium Notes Internal API + version: 0.94.0 + description: | + This is the internal API used by the Trilium Notes client application. + + **Important:** This API is primarily intended for internal use by the Trilium client. + For external integrations, please use the [ETAPI (External Trilium API)](https://triliumnext.github.io/Docs/Wiki/etapi.html) instead. + + ## Authentication + + Most endpoints require session-based authentication. You can authenticate using: + - **Password login**: POST to `/api/login` with password + - **Token authentication**: Generate a token via `/api/login/token` + - **Sync authentication**: Use document secret for sync operations + + ## Rate Limiting + + Authentication endpoints are rate-limited to prevent brute force attacks. + + ## CSRF Protection + + State-changing operations require CSRF tokens when using session authentication. + + contact: + name: TriliumNext Issue Tracker + url: https://github.com/TriliumNext/Notes/issues + license: + name: GNU Affero General Public License v3.0 + url: https://www.gnu.org/licenses/agpl-3.0.html + +servers: + - url: http://localhost:8080 + description: Default local server + - url: https://your-trilium-server.com + description: Your Trilium server + +tags: + - name: Authentication + description: Login, logout, and session management + - name: Notes + description: Core note operations + - name: Tree + description: Note tree structure and branches + - name: Attributes + description: Note attributes and metadata + - name: Attachments + description: File attachments + - name: Revisions + description: Note revision history + - name: Search + description: Search and discovery + - name: Import/Export + description: Import and export operations + - name: Sync + description: Synchronization between instances + - name: Scripting + description: Script execution and automation + - name: Configuration + description: System options and settings + - name: Database + description: Database operations + - name: LLM + description: AI/LLM integration + - name: Security + description: Security features (2FA, tokens) + - name: Special Notes + description: Special note types (calendar, inbox) + - name: Visualization + description: Maps and visualizations + - name: External + description: External integrations (clipper, sender) + - name: Utilities + description: Miscellaneous utilities + +security: + - sessionAuth: [] + - tokenAuth: [] + +paths: + # Authentication endpoints + /api/login: + post: + tags: [Authentication] + summary: Login with password + operationId: login + security: [] + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + required: [password] + properties: + password: + type: string + format: password + totpToken: + type: string + description: TOTP token if 2FA is enabled + responses: + '200': + description: Login successful + headers: + Set-Cookie: + schema: + type: string + example: trilium.sid=s%3A... + '401': + description: Invalid credentials or TOTP token + + /api/login/token: + post: + tags: [Authentication] + summary: Generate API token + operationId: generateToken + security: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [password] + properties: + password: + type: string + format: password + tokenName: + type: string + description: Optional name for the token + responses: + '201': + description: Token created + content: + application/json: + schema: + type: object + properties: + authToken: + type: string + description: API authentication token + + /api/login/sync: + post: + tags: [Authentication, Sync] + summary: Sync login using document secret + operationId: loginSync + security: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [timestamp, hash, syncVersion] + properties: + timestamp: + type: string + format: date-time + hash: + type: string + description: HMAC hash of document secret and timestamp + syncVersion: + type: integer + responses: + '200': + description: Login successful + content: + application/json: + schema: + type: object + properties: + instanceId: + type: string + maxEntityChangeId: + type: string + + /api/login/protected: + post: + tags: [Authentication, Security] + summary: Enter protected session + operationId: enterProtectedSession + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [password] + properties: + password: + type: string + format: password + responses: + '200': + description: Protected session entered + '401': + description: Invalid password + + /api/logout/protected: + post: + tags: [Authentication, Security] + summary: Exit protected session + operationId: exitProtectedSession + responses: + '204': + description: Protected session exited + + /api/login/protected/touch: + post: + tags: [Authentication, Security] + summary: Keep protected session alive + operationId: touchProtectedSession + responses: + '204': + description: Session refreshed + + # App Info + /api/app-info: + get: + tags: [Configuration] + summary: Get application information + operationId: getAppInfo + responses: + '200': + description: Application information + content: + application/json: + schema: + $ref: '#/components/schemas/AppInfo' + + # Setup endpoints + /api/setup/status: + get: + tags: [Configuration] + summary: Get setup status + operationId: getSetupStatus + security: [] + responses: + '200': + description: Setup status + content: + application/json: + schema: + type: object + properties: + isInitialized: + type: boolean + schemaExists: + type: boolean + syncVersion: + type: integer + + /api/setup/new-document: + post: + tags: [Configuration] + summary: Initialize new document + operationId: initNewDocument + security: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [password] + properties: + password: + type: string + format: password + theme: + type: string + responses: + '201': + description: Document initialized + + /api/setup/sync-from-server: + post: + tags: [Configuration, Sync] + summary: Setup sync from server + operationId: setupSyncFromServer + security: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [syncServerHost, password] + properties: + syncServerHost: + type: string + format: uri + syncProxy: + type: string + password: + type: string + format: password + responses: + '200': + description: Sync setup successful + + # Note operations + /api/notes/{noteId}: + get: + tags: [Notes] + summary: Get note metadata + operationId: getNote + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note metadata + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + '404': + description: Note not found + + delete: + tags: [Notes] + summary: Delete note + operationId: deleteNote + parameters: + - $ref: '#/components/parameters/noteId' + - name: taskId + in: query + required: true + schema: + type: string + - name: eraseNotes + in: query + schema: + type: boolean + default: false + - name: last + in: query + required: true + schema: + type: boolean + responses: + '204': + description: Note deleted + '404': + description: Note not found + + /api/notes/{noteId}/blob: + get: + tags: [Notes] + summary: Get note content + operationId: getNoteContent + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note content + content: + text/html: + schema: + type: string + text/plain: + schema: + type: string + application/json: + schema: + type: object + application/octet-stream: + schema: + type: string + format: binary + '404': + description: Note not found + + /api/notes/{noteId}/data: + put: + tags: [Notes] + summary: Update note content + operationId: updateNoteContent + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [content] + properties: + content: + type: string + attachments: + type: array + items: + $ref: '#/components/schemas/Attachment' + responses: + '204': + description: Content updated + '404': + description: Note not found + + /api/notes/{noteId}/metadata: + get: + tags: [Notes] + summary: Get note timestamps + operationId: getNoteMetadata + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note timestamps + content: + application/json: + schema: + $ref: '#/components/schemas/Timestamps' + '404': + description: Note not found + + /api/notes/{noteId}/title: + put: + tags: [Notes] + summary: Change note title + operationId: updateNoteTitle + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [title] + properties: + title: + type: string + responses: + '204': + description: Title updated + '404': + description: Note not found + + /api/notes/{noteId}/type: + put: + tags: [Notes] + summary: Change note type and MIME + operationId: updateNoteType + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [type, mime] + properties: + type: + $ref: '#/components/schemas/NoteType' + mime: + type: string + responses: + '204': + description: Type updated + '404': + description: Note not found + + /api/notes/{noteId}/protect/{isProtected}: + put: + tags: [Notes, Security] + summary: Protect or unprotect note + operationId: protectNote + parameters: + - $ref: '#/components/parameters/noteId' + - name: isProtected + in: path + required: true + schema: + type: boolean + - name: subtree + in: query + schema: + type: boolean + default: false + responses: + '204': + description: Protection status updated + '404': + description: Note not found + + /api/notes/{noteId}/undelete: + put: + tags: [Notes] + summary: Undelete note + operationId: undeleteNote + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '204': + description: Note undeleted + '404': + description: Note not found + + /api/notes/{parentNoteId}/children: + post: + tags: [Notes, Tree] + summary: Create new note + operationId: createNote + parameters: + - name: parentNoteId + in: path + required: true + schema: + type: string + - name: target + in: query + schema: + type: string + enum: [after, into] + - name: targetBranchId + in: query + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateNoteRequest' + responses: + '201': + description: Note created + content: + application/json: + schema: + type: object + properties: + note: + $ref: '#/components/schemas/Note' + branch: + $ref: '#/components/schemas/Branch' + + /api/notes/{noteId}/duplicate/{parentNoteId}: + post: + tags: [Notes, Tree] + summary: Duplicate note subtree + operationId: duplicateNote + parameters: + - $ref: '#/components/parameters/noteId' + - name: parentNoteId + in: path + required: true + schema: + type: string + responses: + '201': + description: Note duplicated + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/notes/{noteId}/revision: + post: + tags: [Notes, Revisions] + summary: Force save revision + operationId: saveRevision + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '201': + description: Revision saved + content: + application/json: + schema: + $ref: '#/components/schemas/Revision' + + /api/notes/{noteId}/sort-children: + put: + tags: [Notes, Tree] + summary: Sort child notes + operationId: sortChildren + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + sortBy: + type: string + enum: [title, dateCreated, dateModified] + sortDirection: + type: string + enum: [asc, desc] + foldersFirst: + type: boolean + sortNatural: + type: boolean + sortLocale: + type: string + responses: + '204': + description: Children sorted + + /api/notes/{noteId}/convert-to-attachment: + post: + tags: [Notes, Attachments] + summary: Convert note to attachment + operationId: convertToAttachment + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note converted to attachment + content: + application/json: + schema: + $ref: '#/components/schemas/Attachment' + + # File operations + /api/notes/{noteId}/file: + put: + tags: [Notes] + summary: Upload file to note + operationId: uploadFileToNote + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: string + format: binary + responses: + '204': + description: File uploaded + + /api/notes/{noteId}/open: + get: + tags: [Notes] + summary: Open file note + operationId: openFileNote + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: File content + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/notes/{noteId}/download: + get: + tags: [Notes] + summary: Download file note + operationId: downloadFileNote + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: File content + headers: + Content-Disposition: + schema: + type: string + example: attachment; filename="document.pdf" + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/notes/{noteId}/open-partial: + get: + tags: [Notes] + summary: Stream file with partial content support + operationId: openPartialFileNote + parameters: + - $ref: '#/components/parameters/noteId' + - name: Range + in: header + schema: + type: string + example: bytes=0-1023 + responses: + '206': + description: Partial content + headers: + Content-Range: + schema: + type: string + example: bytes 0-1023/146515 + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/notes/{noteId}/save-to-tmp-dir: + post: + tags: [Notes] + summary: Save note to temp directory + operationId: saveToTmpDir + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: File saved to temp directory + content: + application/json: + schema: + type: object + properties: + filePath: + type: string + + /api/notes/{noteId}/upload-modified-file: + post: + tags: [Notes] + summary: Update note from modified temp file + operationId: uploadModifiedFile + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [filePath] + properties: + filePath: + type: string + responses: + '204': + description: Note updated from file + + # Tree and branch operations + /api/tree: + get: + tags: [Tree] + summary: Get tree structure + operationId: getTree + parameters: + - name: subTreeNoteId + in: query + schema: + type: string + description: Limit tree to this note and descendants + responses: + '200': + description: Tree structure + content: + application/json: + schema: + type: object + properties: + notes: + type: array + items: + $ref: '#/components/schemas/Note' + branches: + type: array + items: + $ref: '#/components/schemas/Branch' + attributes: + type: array + items: + $ref: '#/components/schemas/Attribute' + + /api/tree/load: + post: + tags: [Tree] + summary: Load specific notes + operationId: loadNotes + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [noteIds] + properties: + noteIds: + type: array + items: + type: string + responses: + '200': + description: Loaded notes + content: + application/json: + schema: + type: object + properties: + notes: + type: array + items: + $ref: '#/components/schemas/Note' + branches: + type: array + items: + $ref: '#/components/schemas/Branch' + attributes: + type: array + items: + $ref: '#/components/schemas/Attribute' + + /api/branches/{branchId}: + delete: + tags: [Tree] + summary: Delete branch + operationId: deleteBranch + parameters: + - name: branchId + in: path + required: true + schema: + type: string + - name: taskId + in: query + required: true + schema: + type: string + - name: eraseNotes + in: query + schema: + type: boolean + - name: last + in: query + required: true + schema: + type: boolean + responses: + '200': + description: Branch deleted + content: + application/json: + schema: + type: object + properties: + noteDeleted: + type: boolean + + /api/branches/{branchId}/move-to/{parentBranchId}: + put: + tags: [Tree] + summary: Move branch to new parent + operationId: moveBranchToParent + parameters: + - name: branchId + in: path + required: true + schema: + type: string + - name: parentBranchId + in: path + required: true + schema: + type: string + responses: + '204': + description: Branch moved + + /api/branches/{branchId}/move-before/{beforeBranchId}: + put: + tags: [Tree] + summary: Move branch before another + operationId: moveBranchBefore + parameters: + - name: branchId + in: path + required: true + schema: + type: string + - name: beforeBranchId + in: path + required: true + schema: + type: string + responses: + '204': + description: Branch moved + + /api/branches/{branchId}/move-after/{afterBranchId}: + put: + tags: [Tree] + summary: Move branch after another + operationId: moveBranchAfter + parameters: + - name: branchId + in: path + required: true + schema: + type: string + - name: afterBranchId + in: path + required: true + schema: + type: string + responses: + '204': + description: Branch moved + + /api/branches/{branchId}/expanded/{expanded}: + put: + tags: [Tree] + summary: Set branch expanded state + operationId: setBranchExpanded + parameters: + - name: branchId + in: path + required: true + schema: + type: string + - name: expanded + in: path + required: true + schema: + type: boolean + responses: + '204': + description: Expanded state updated + + /api/branches/{branchId}/expanded-subtree/{expanded}: + put: + tags: [Tree] + summary: Set subtree expanded state + operationId: setSubtreeExpanded + parameters: + - name: branchId + in: path + required: true + schema: + type: string + - name: expanded + in: path + required: true + schema: + type: boolean + responses: + '204': + description: Subtree expanded state updated + + /api/branches/{branchId}/set-prefix: + put: + tags: [Tree] + summary: Set branch prefix + operationId: setBranchPrefix + parameters: + - name: branchId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + prefix: + type: string + nullable: true + responses: + '204': + description: Prefix updated + + # Cloning operations + /api/notes/{noteId}/clone-to-branch/{parentBranchId}: + put: + tags: [Tree, Notes] + summary: Clone note to branch + operationId: cloneToBranch + parameters: + - $ref: '#/components/parameters/noteId' + - name: parentBranchId + in: path + required: true + schema: + type: string + responses: + '200': + description: Note cloned + content: + application/json: + schema: + $ref: '#/components/schemas/Branch' + + /api/notes/{noteId}/clone-to-note/{parentNoteId}: + put: + tags: [Tree, Notes] + summary: Clone note to parent note + operationId: cloneToNote + parameters: + - $ref: '#/components/parameters/noteId' + - name: parentNoteId + in: path + required: true + schema: + type: string + responses: + '200': + description: Note cloned + content: + application/json: + schema: + $ref: '#/components/schemas/Branch' + + /api/notes/{noteId}/clone-after/{afterBranchId}: + put: + tags: [Tree, Notes] + summary: Clone note after branch + operationId: cloneAfterBranch + parameters: + - $ref: '#/components/parameters/noteId' + - name: afterBranchId + in: path + required: true + schema: + type: string + responses: + '200': + description: Note cloned + content: + application/json: + schema: + $ref: '#/components/schemas/Branch' + + /api/notes/{noteId}/toggle-in-parent/{parentNoteId}/{present}: + put: + tags: [Tree, Notes] + summary: Toggle note presence in parent + operationId: toggleInParent + parameters: + - $ref: '#/components/parameters/noteId' + - name: parentNoteId + in: path + required: true + schema: + type: string + - name: present + in: path + required: true + schema: + type: boolean + responses: + '204': + description: Presence toggled + + # Attributes + /api/notes/{noteId}/attributes: + get: + tags: [Attributes] + summary: Get effective note attributes + operationId: getNoteAttributes + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note attributes + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Attribute' + + post: + tags: [Attributes] + summary: Add note attribute + operationId: addNoteAttribute + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Attribute' + responses: + '201': + description: Attribute added + content: + application/json: + schema: + $ref: '#/components/schemas/Attribute' + + put: + tags: [Attributes] + summary: Update all note attributes + operationId: updateNoteAttributes + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Attribute' + responses: + '204': + description: Attributes updated + + /api/notes/{noteId}/attributes/{attributeId}: + delete: + tags: [Attributes] + summary: Delete attribute + operationId: deleteAttribute + parameters: + - $ref: '#/components/parameters/noteId' + - name: attributeId + in: path + required: true + schema: + type: string + responses: + '204': + description: Attribute deleted + + /api/notes/{noteId}/attribute: + put: + tags: [Attributes] + summary: Update single attribute + operationId: updateAttribute + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Attribute' + responses: + '204': + description: Attribute updated + + /api/notes/{noteId}/set-attribute: + put: + tags: [Attributes] + summary: Set attribute value + operationId: setAttribute + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [type, name, value] + properties: + type: + type: string + enum: [label, relation] + name: + type: string + value: + type: string + responses: + '204': + description: Attribute set + + /api/notes/{noteId}/relations/{name}/to/{targetNoteId}: + put: + tags: [Attributes] + summary: Create relation + operationId: createRelation + parameters: + - $ref: '#/components/parameters/noteId' + - name: name + in: path + required: true + schema: + type: string + - name: targetNoteId + in: path + required: true + schema: + type: string + responses: + '204': + description: Relation created + + delete: + tags: [Attributes] + summary: Delete relation + operationId: deleteRelation + parameters: + - $ref: '#/components/parameters/noteId' + - name: name + in: path + required: true + schema: + type: string + - name: targetNoteId + in: path + required: true + schema: + type: string + responses: + '204': + description: Relation deleted + + /api/attribute-names: + get: + tags: [Attributes] + summary: Get attribute name suggestions + operationId: getAttributeNames + parameters: + - name: type + in: query + required: true + schema: + type: string + enum: [label, relation] + - name: query + in: query + schema: + type: string + responses: + '200': + description: Attribute names + content: + application/json: + schema: + type: array + items: + type: string + + /api/attribute-values/{attributeName}: + get: + tags: [Attributes] + summary: Get values for attribute + operationId: getAttributeValues + parameters: + - name: attributeName + in: path + required: true + schema: + type: string + responses: + '200': + description: Attribute values + content: + application/json: + schema: + type: array + items: + type: string + + # Attachments + /api/notes/{noteId}/attachments: + get: + tags: [Attachments] + summary: Get note attachments + operationId: getNoteAttachments + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note attachments + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Attachment' + + post: + tags: [Attachments] + summary: Save attachment + operationId: saveAttachment + parameters: + - $ref: '#/components/parameters/noteId' + - name: matchBy + in: query + schema: + type: string + enum: [attachmentId, title] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Attachment' + responses: + '201': + description: Attachment saved + content: + application/json: + schema: + $ref: '#/components/schemas/Attachment' + + /api/notes/{noteId}/attachments/upload: + post: + tags: [Attachments] + summary: Upload attachment file + operationId: uploadAttachment + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: string + format: binary + responses: + '201': + description: Attachment uploaded + content: + application/json: + schema: + $ref: '#/components/schemas/Attachment' + + /api/attachments/{attachmentId}: + get: + tags: [Attachments] + summary: Get attachment metadata + operationId: getAttachment + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + responses: + '200': + description: Attachment metadata + content: + application/json: + schema: + $ref: '#/components/schemas/Attachment' + + delete: + tags: [Attachments] + summary: Delete attachment + operationId: deleteAttachment + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + responses: + '204': + description: Attachment deleted + + /api/attachments/{attachmentId}/blob: + get: + tags: [Attachments] + summary: Get attachment content + operationId: getAttachmentBlob + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + - name: preview + in: query + schema: + type: boolean + responses: + '200': + description: Attachment content + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/attachments/{attachmentId}/rename: + put: + tags: [Attachments] + summary: Rename attachment + operationId: renameAttachment + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [title] + properties: + title: + type: string + responses: + '204': + description: Attachment renamed + + /api/attachments/{attachmentId}/convert-to-note: + post: + tags: [Attachments, Notes] + summary: Convert attachment to note + operationId: convertAttachmentToNote + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + responses: + '200': + description: Attachment converted to note + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/attachments/{attachmentId}/file: + put: + tags: [Attachments] + summary: Update attachment file + operationId: updateAttachmentFile + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: string + format: binary + responses: + '204': + description: Attachment file updated + + /api/attachments/{attachmentId}/open: + get: + tags: [Attachments] + summary: Open attachment + operationId: openAttachment + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + responses: + '200': + description: Attachment content + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/attachments/{attachmentId}/download: + get: + tags: [Attachments] + summary: Download attachment + operationId: downloadAttachment + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + responses: + '200': + description: Attachment content + headers: + Content-Disposition: + schema: + type: string + example: attachment; filename="document.pdf" + content: + application/octet-stream: + schema: + type: string + format: binary + + # Revisions + /api/notes/{noteId}/revisions: + get: + tags: [Revisions] + summary: Get note revisions + operationId: getNoteRevisions + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note revisions + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Revision' + + delete: + tags: [Revisions] + summary: Erase all note revisions + operationId: eraseNoteRevisions + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '204': + description: Revisions erased + + /api/revisions/{revisionId}: + get: + tags: [Revisions] + summary: Get revision details + operationId: getRevision + parameters: + - name: revisionId + in: path + required: true + schema: + type: string + responses: + '200': + description: Revision details + content: + application/json: + schema: + $ref: '#/components/schemas/Revision' + + delete: + tags: [Revisions] + summary: Erase revision + operationId: eraseRevision + parameters: + - name: revisionId + in: path + required: true + schema: + type: string + responses: + '204': + description: Revision erased + + /api/revisions/{revisionId}/blob: + get: + tags: [Revisions] + summary: Get revision content + operationId: getRevisionBlob + parameters: + - name: revisionId + in: path + required: true + schema: + type: string + - name: preview + in: query + schema: + type: boolean + responses: + '200': + description: Revision content + content: + text/html: + schema: + type: string + text/plain: + schema: + type: string + application/octet-stream: + schema: + type: string + format: binary + + /api/revisions/{revisionId}/restore: + post: + tags: [Revisions, Notes] + summary: Restore revision + operationId: restoreRevision + parameters: + - name: revisionId + in: path + required: true + schema: + type: string + responses: + '200': + description: Revision restored + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/revisions/{revisionId}/download: + get: + tags: [Revisions] + summary: Download revision + operationId: downloadRevision + parameters: + - name: revisionId + in: path + required: true + schema: + type: string + responses: + '200': + description: Revision content + headers: + Content-Disposition: + schema: + type: string + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/revisions/erase-all-excess-revisions: + post: + tags: [Revisions] + summary: Cleanup old revisions + operationId: eraseExcessRevisions + responses: + '204': + description: Excess revisions erased + + /api/edited-notes/{date}: + get: + tags: [Revisions] + summary: Get notes edited on date + operationId: getEditedNotes + parameters: + - name: date + in: path + required: true + schema: + type: string + format: date + example: '2024-01-15' + responses: + '200': + description: Edited notes + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Note' + + # Search + /api/search/{searchString}: + get: + tags: [Search] + summary: Full text search + operationId: search + parameters: + - name: searchString + in: path + required: true + schema: + type: string + responses: + '200': + description: Search results + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SearchResult' + + /api/quick-search/{searchString}: + get: + tags: [Search] + summary: Quick search with highlighting + operationId: quickSearch + parameters: + - name: searchString + in: path + required: true + schema: + type: string + responses: + '200': + description: Quick search results + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SearchResult' + + /api/search-note/{noteId}: + get: + tags: [Search] + summary: Execute search note + operationId: executeSearchNote + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Search results + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SearchResult' + + /api/search-and-execute-note/{noteId}: + post: + tags: [Search, Scripting] + summary: Search and execute actions + operationId: searchAndExecute + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Execution results + + /api/search-related: + post: + tags: [Search] + summary: Find related notes by attributes + operationId: searchRelated + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Attribute' + responses: + '200': + description: Related notes + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Note' + + /api/search-templates: + get: + tags: [Search] + summary: Search template notes + operationId: searchTemplates + responses: + '200': + description: Template notes + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Note' + + /api/autocomplete: + get: + tags: [Search] + summary: Get autocomplete suggestions + operationId: autocomplete + parameters: + - name: query + in: query + required: true + schema: + type: string + - name: fastSearch + in: query + schema: + type: boolean + - name: activeNoteId + in: query + schema: + type: string + responses: + '200': + description: Autocomplete suggestions + content: + application/json: + schema: + type: array + items: + type: object + properties: + noteId: + type: string + title: + type: string + path: + type: string + + /api/autocomplete/notesCount: + get: + tags: [Search] + summary: Get total notes count + operationId: getNotesCount + responses: + '200': + description: Notes count + content: + application/json: + schema: + type: object + properties: + count: + type: integer + + /api/similar-notes/{noteId}: + get: + tags: [Search] + summary: Find similar notes + operationId: findSimilarNotes + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Similar notes + content: + application/json: + schema: + type: array + items: + type: object + properties: + noteId: + type: string + title: + type: string + similarity: + type: number + + # Images + /api/images/{noteId}/{filename}: + get: + tags: [Notes] + summary: Get image from note + operationId: getNoteImage + parameters: + - $ref: '#/components/parameters/noteId' + - name: filename + in: path + required: true + schema: + type: string + responses: + '200': + description: Image content + content: + image/*: + schema: + type: string + format: binary + + /api/images/{noteId}: + put: + tags: [Notes] + summary: Update image note + operationId: updateImageNote + parameters: + - $ref: '#/components/parameters/noteId' + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: string + format: binary + responses: + '204': + description: Image updated + + /api/attachments/{attachmentId}/image/{filename}: + get: + tags: [Attachments] + summary: Get attached image + operationId: getAttachmentImage + parameters: + - name: attachmentId + in: path + required: true + schema: + type: string + - name: filename + in: path + required: true + schema: + type: string + responses: + '200': + description: Image content + content: + image/*: + schema: + type: string + format: binary + + /api/revisions/{revisionId}/image/{filename}: + get: + tags: [Revisions] + summary: Get image from revision + operationId: getRevisionImage + parameters: + - name: revisionId + in: path + required: true + schema: + type: string + - name: filename + in: path + required: true + schema: + type: string + responses: + '200': + description: Image content + content: + image/*: + schema: + type: string + format: binary + + # Import/Export + /api/branches/{branchId}/export/{type}/{format}/{version}/{taskId}: + get: + tags: [Import/Export] + summary: Export branch + operationId: exportBranch + parameters: + - name: branchId + in: path + required: true + schema: + type: string + - name: type + in: path + required: true + schema: + type: string + enum: [subtree, single] + - name: format + in: path + required: true + schema: + type: string + enum: [html, markdown, opml] + - name: version + in: path + required: true + schema: + type: string + - name: taskId + in: path + required: true + schema: + type: string + responses: + '200': + description: Exported content + content: + application/octet-stream: + schema: + type: string + format: binary + + /api/notes/{parentNoteId}/notes-import: + post: + tags: [Import/Export] + summary: Import notes + operationId: importNotes + parameters: + - name: parentNoteId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: string + format: binary + safeImport: + type: boolean + shrinkImages: + type: boolean + textImportedAsText: + type: boolean + codeImportedAsCode: + type: boolean + explodeArchives: + type: boolean + replaceUnderscoresWithSpaces: + type: boolean + responses: + '200': + description: Import results + content: + application/json: + schema: + type: object + properties: + noteId: + type: string + note: + $ref: '#/components/schemas/Note' + + /api/notes/{parentNoteId}/attachments-import: + post: + tags: [Import/Export, Attachments] + summary: Import attachments + operationId: importAttachments + parameters: + - name: parentNoteId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: array + items: + type: string + format: binary + responses: + '200': + description: Import results + + # Options + /api/options: + get: + tags: [Configuration] + summary: Get system options + operationId: getOptions + responses: + '200': + description: System options + content: + application/json: + schema: + type: object + additionalProperties: + type: string + + put: + tags: [Configuration] + summary: Update multiple options + operationId: updateOptions + requestBody: + required: true + content: + application/json: + schema: + type: object + additionalProperties: + type: string + responses: + '204': + description: Options updated + + /api/options/{name}/{value}: + put: + tags: [Configuration] + summary: Update single option + operationId: updateOption + parameters: + - name: name + in: path + required: true + schema: + type: string + - name: value + in: path + required: true + schema: + type: string + responses: + '204': + description: Option updated + + /api/options/user-themes: + get: + tags: [Configuration] + summary: Get user-defined themes + operationId: getUserThemes + responses: + '200': + description: User themes + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + label: + type: string + + /api/options/locales: + get: + tags: [Configuration] + summary: Get supported locales + operationId: getLocales + responses: + '200': + description: Supported locales + content: + application/json: + schema: + type: array + items: + type: object + properties: + code: + type: string + name: + type: string + + # Password management + /api/password/change: + post: + tags: [Security] + summary: Change password + operationId: changePassword + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [new_password] + properties: + current_password: + type: string + format: password + new_password: + type: string + format: password + responses: + '204': + description: Password changed + + /api/password/reset: + post: + tags: [Security] + summary: Reset password (destructive) + operationId: resetPassword + parameters: + - name: really + in: query + required: true + schema: + type: string + example: yesIReallyWantToResetMyPassword + responses: + '204': + description: Password reset + + # Sync + /api/sync/test: + post: + tags: [Sync] + summary: Test sync connection + operationId: testSync + responses: + '200': + description: Sync test results + + /api/sync/now: + post: + tags: [Sync] + summary: Trigger sync now + operationId: syncNow + responses: + '200': + description: Sync started + + /api/sync/check: + get: + tags: [Sync] + summary: Get sync status + operationId: checkSync + responses: + '200': + description: Sync status + content: + application/json: + schema: + type: object + properties: + synced: + type: boolean + lastSyncedPush: + type: string + format: date-time + lastSyncedPull: + type: string + format: date-time + + /api/sync/changed: + get: + tags: [Sync] + summary: Get sync changes + operationId: getSyncChanges + parameters: + - name: instanceId + in: query + required: true + schema: + type: string + - name: lastEntityChangeId + in: query + required: true + schema: + type: integer + - name: logMarkerId + in: query + required: true + schema: + type: string + responses: + '200': + description: Sync changes + content: + application/json: + schema: + type: object + properties: + entityChanges: + type: array + items: + $ref: '#/components/schemas/EntityChange' + lastEntityChangeId: + type: integer + outstandingPullCount: + type: integer + + /api/sync/update: + put: + tags: [Sync] + summary: Push sync changes + operationId: pushSyncChanges + parameters: + - name: logMarkerId + in: query + required: true + schema: + type: string + - name: pageCount + in: header + required: true + schema: + type: integer + - name: pageIndex + in: header + required: true + schema: + type: integer + - name: requestId + in: header + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + instanceId: + type: string + entities: + type: array + items: + $ref: '#/components/schemas/EntityChange' + responses: + '200': + description: Changes processed + + /api/sync/finished: + post: + tags: [Sync] + summary: Mark sync as finished + operationId: finishSync + responses: + '204': + description: Sync finished + + /api/sync/stats: + get: + tags: [Sync] + summary: Get sync statistics + operationId: getSyncStats + security: [] + responses: + '200': + description: Sync statistics + content: + application/json: + schema: + type: object + properties: + initialized: + type: boolean + stats: + type: object + + /api/sync/fill-entity-changes: + post: + tags: [Sync] + summary: Fill entity changes + operationId: fillEntityChanges + responses: + '204': + description: Entity changes filled + + /api/sync/force-full-sync: + post: + tags: [Sync] + summary: Force full sync + operationId: forceFullSync + responses: + '204': + description: Full sync forced + + /api/sync/check-entity-changes: + post: + tags: [Sync] + summary: Check entity changes consistency + operationId: checkEntityChanges + responses: + '200': + description: Consistency check results + + /api/sync/queue-sector/{entityName}/{sector}: + post: + tags: [Sync] + summary: Queue sector for sync + operationId: queueSyncSector + parameters: + - name: entityName + in: path + required: true + schema: + type: string + - name: sector + in: path + required: true + schema: + type: string + responses: + '204': + description: Sector queued + + # Scripting + /api/script/exec: + post: + tags: [Scripting] + summary: Execute script + operationId: executeScript + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [script] + properties: + script: + type: string + params: + type: array + items: + type: string + startNoteId: + type: string + currentNoteId: + type: string + originEntityName: + type: string + originEntityId: + type: string + transactional: + type: boolean + responses: + '200': + description: Script execution results + content: + application/json: + schema: + type: object + + /api/script/run/{noteId}: + post: + tags: [Scripting] + summary: Run script note + operationId: runScriptNote + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Script execution results + + /api/script/startup: + get: + tags: [Scripting] + summary: Get startup script bundles + operationId: getStartupScripts + parameters: + - name: mobile + in: query + schema: + type: boolean + responses: + '200': + description: Startup scripts + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ScriptBundle' + + /api/script/widgets: + get: + tags: [Scripting] + summary: Get widget script bundles + operationId: getWidgetScripts + responses: + '200': + description: Widget scripts + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ScriptBundle' + + /api/script/bundle/{noteId}: + post: + tags: [Scripting] + summary: Get script bundle for note + operationId: getScriptBundle + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Script bundle + content: + application/json: + schema: + $ref: '#/components/schemas/ScriptBundle' + + /api/script/relation/{noteId}/{relationName}: + get: + tags: [Scripting] + summary: Get relation script bundles + operationId: getRelationScripts + parameters: + - $ref: '#/components/parameters/noteId' + - name: relationName + in: path + required: true + schema: + type: string + responses: + '200': + description: Relation scripts + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ScriptBundle' + + # Database + /api/sql/schema: + get: + tags: [Database] + summary: Get database schema + operationId: getDatabaseSchema + responses: + '200': + description: Database schema + content: + text/plain: + schema: + type: string + + /api/sql/execute/{noteId}: + post: + tags: [Database] + summary: Execute SQL from note + operationId: executeSql + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: SQL execution results + content: + application/json: + schema: + type: array + items: + type: object + + /api/database/backup-database: + post: + tags: [Database] + summary: Create database backup + operationId: backupDatabase + responses: + '204': + description: Backup created + + /api/database/backups: + get: + tags: [Database] + summary: List existing backups + operationId: listBackups + responses: + '200': + description: Backup list + content: + application/json: + schema: + type: array + items: + type: string + + /api/database/vacuum-database: + post: + tags: [Database] + summary: Vacuum database + operationId: vacuumDatabase + responses: + '204': + description: Database vacuumed + + /api/database/anonymize/{type}: + post: + tags: [Database] + summary: Anonymize database + operationId: anonymizeDatabase + parameters: + - name: type + in: path + required: true + schema: + type: string + enum: [save-as-file, save-and-send] + responses: + '200': + description: Anonymization results + + /api/database/anonymized-databases: + get: + tags: [Database] + summary: List anonymized databases + operationId: listAnonymizedDatabases + responses: + '200': + description: Anonymized database list + content: + application/json: + schema: + type: array + items: + type: string + + /api/database/find-and-fix-consistency-issues: + post: + tags: [Database] + summary: Fix consistency issues + operationId: fixConsistencyIssues + responses: + '200': + description: Consistency check results + + /api/database/check-integrity: + get: + tags: [Database] + summary: Check database integrity + operationId: checkIntegrity + responses: + '200': + description: Integrity check results + content: + application/json: + schema: + type: object + properties: + results: + type: array + items: + type: string + + # System + /api/metrics: + get: + tags: [Utilities] + summary: Get system metrics + operationId: getMetrics + parameters: + - name: format + in: query + schema: + type: string + enum: [prometheus, json] + default: json + responses: + '200': + description: System metrics + content: + application/json: + schema: + type: object + text/plain: + schema: + type: string + + /api/system-checks: + get: + tags: [Utilities] + summary: Run system diagnostics + operationId: runSystemChecks + responses: + '200': + description: System check results + content: + application/json: + schema: + type: array + items: + type: object + properties: + name: + type: string + status: + type: string + enum: [pass, fail] + message: + type: string + + /api/health-check: + get: + tags: [Utilities] + summary: Health check endpoint + operationId: healthCheck + security: [] + responses: + '200': + description: Service is healthy + content: + text/plain: + schema: + type: string + example: OK + + /api/backend-log: + get: + tags: [Utilities] + summary: Get backend log + operationId: getBackendLog + responses: + '200': + description: Backend log entries + content: + application/json: + schema: + type: array + items: + type: object + properties: + timestamp: + type: string + format: date-time + level: + type: string + message: + type: string + + # Bulk operations + /api/bulk-action/execute: + post: + tags: [Notes] + summary: Execute bulk action + operationId: executeBulkAction + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + action: + type: string + noteIds: + type: array + items: + type: string + responses: + '200': + description: Bulk action results + + /api/bulk-action/affected-notes: + post: + tags: [Notes] + summary: Get affected notes count + operationId: getAffectedNotesCount + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + action: + type: string + noteIds: + type: array + items: + type: string + responses: + '200': + description: Affected notes count + content: + application/json: + schema: + type: object + properties: + count: + type: integer + + /api/delete-notes-preview: + post: + tags: [Notes] + summary: Preview note deletion + operationId: previewNoteDeletion + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + branchIdsToDelete: + type: array + items: + type: string + deleteAllClones: + type: boolean + responses: + '200': + description: Deletion preview + content: + application/json: + schema: + type: object + properties: + notesToDelete: + type: array + items: + type: string + + /api/notes/erase-deleted-notes-now: + post: + tags: [Notes] + summary: Erase deleted notes + operationId: eraseDeletedNotes + responses: + '204': + description: Deleted notes erased + + /api/notes/erase-unused-attachments-now: + post: + tags: [Attachments] + summary: Erase unused attachments + operationId: eraseUnusedAttachments + responses: + '204': + description: Unused attachments erased + + # Special notes + /api/special-notes/inbox/{date}: + get: + tags: [Special Notes] + summary: Get/create inbox note + operationId: getInboxNote + parameters: + - name: date + in: path + required: true + schema: + type: string + format: date + responses: + '200': + description: Inbox note + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/days/{date}: + get: + tags: [Special Notes] + summary: Get/create day note + operationId: getDayNote + parameters: + - name: date + in: path + required: true + schema: + type: string + format: date + responses: + '200': + description: Day note + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/weeks/{week}: + get: + tags: [Special Notes] + summary: Get/create week note + operationId: getWeekNote + parameters: + - name: week + in: path + required: true + schema: + type: string + pattern: ^\d{4}-\d{2}$ + example: '2024-03' + responses: + '200': + description: Week note + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/months/{month}: + get: + tags: [Special Notes] + summary: Get/create month note + operationId: getMonthNote + parameters: + - name: month + in: path + required: true + schema: + type: string + pattern: ^\d{4}-\d{2}$ + example: '2024-01' + responses: + '200': + description: Month note + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/years/{year}: + get: + tags: [Special Notes] + summary: Get/create year note + operationId: getYearNote + parameters: + - name: year + in: path + required: true + schema: + type: string + pattern: ^\d{4}$ + example: '2024' + responses: + '200': + description: Year note + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/sql-console: + post: + tags: [Special Notes, Database] + summary: Create SQL console note + operationId: createSqlConsole + responses: + '201': + description: SQL console created + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/search-note: + post: + tags: [Special Notes, Search] + summary: Create search note + operationId: createSearchNote + responses: + '201': + description: Search note created + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/special-notes/launchers/{parentNoteId}/{launcherType}: + post: + tags: [Special Notes] + summary: Create launcher + operationId: createLauncher + parameters: + - name: parentNoteId + in: path + required: true + schema: + type: string + - name: launcherType + in: path + required: true + schema: + type: string + responses: + '201': + description: Launcher created + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + # Maps + /api/note-map/{noteId}/tree: + post: + tags: [Visualization] + summary: Get tree map + operationId: getTreeMap + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Tree map data + content: + application/json: + schema: + type: object + + /api/note-map/{noteId}/link: + post: + tags: [Visualization] + summary: Get link map + operationId: getLinkMap + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Link map data + content: + application/json: + schema: + type: object + + /api/note-map/{noteId}/backlinks: + get: + tags: [Visualization] + summary: Get backlinks + operationId: getBacklinks + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Backlinks + content: + application/json: + schema: + type: array + items: + type: object + properties: + noteId: + type: string + title: + type: string + + /api/relation-map: + post: + tags: [Visualization] + summary: Get relation map data + operationId: getRelationMap + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + noteId: + type: string + maxDepth: + type: integer + excludeArchived: + type: boolean + responses: + '200': + description: Relation map data + content: + application/json: + schema: + type: object + + # External integrations + /api/clipper/handshake: + get: + tags: [External] + summary: Clipper handshake + operationId: clipperHandshake + responses: + '200': + description: Handshake successful + content: + application/json: + schema: + type: object + properties: + protocolVersion: + type: string + + /api/clipper/clippings: + post: + tags: [External] + summary: Add web clipping + operationId: addClipping + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + content: + type: string + url: + type: string + responses: + '201': + description: Clipping created + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/clipper/notes: + post: + tags: [External] + summary: Create clipper note + operationId: createClipperNote + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + content: + type: string + parentNoteId: + type: string + responses: + '201': + description: Note created + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/sender/login: + post: + tags: [External] + summary: Sender login + operationId: senderLogin + security: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [username, password] + properties: + username: + type: string + password: + type: string + responses: + '200': + description: Login successful + content: + application/json: + schema: + type: object + properties: + token: + type: string + + /api/sender/image: + post: + tags: [External] + summary: Upload image from sender + operationId: uploadSenderImage + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + upload: + type: string + format: binary + responses: + '201': + description: Image uploaded + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + /api/sender/note: + post: + tags: [External] + summary: Save note from sender + operationId: saveSenderNote + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + content: + type: string + responses: + '201': + description: Note saved + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + + # LLM endpoints + /api/llm/chat: + post: + tags: [LLM] + summary: Create new chat session + operationId: createChatSession + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + systemPrompt: + type: string + temperature: + type: number + minimum: 0 + maximum: 1 + maxTokens: + type: integer + model: + type: string + provider: + type: string + enum: [openai, anthropic, ollama] + contextNoteId: + type: string + responses: + '201': + description: Chat session created + content: + application/json: + schema: + $ref: '#/components/schemas/ChatSession' + + get: + tags: [LLM] + summary: List all chat sessions + operationId: listChatSessions + responses: + '200': + description: Chat sessions + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ChatSession' + + /api/llm/chat/{chatNoteId}: + get: + tags: [LLM] + summary: Get specific chat session + operationId: getChatSession + parameters: + - name: chatNoteId + in: path + required: true + schema: + type: string + responses: + '200': + description: Chat session details + content: + application/json: + schema: + $ref: '#/components/schemas/ChatSession' + + patch: + tags: [LLM] + summary: Update chat session + operationId: updateChatSession + parameters: + - name: chatNoteId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + systemPrompt: + type: string + temperature: + type: number + maxTokens: + type: integer + model: + type: string + provider: + type: string + contextNoteId: + type: string + responses: + '200': + description: Session updated + content: + application/json: + schema: + $ref: '#/components/schemas/ChatSession' + + delete: + tags: [LLM] + summary: Delete chat session + operationId: deleteChatSession + parameters: + - name: chatNoteId + in: path + required: true + schema: + type: string + responses: + '204': + description: Session deleted + + /api/llm/chat/{chatNoteId}/messages: + post: + tags: [LLM] + summary: Send message to LLM + operationId: sendChatMessage + parameters: + - name: chatNoteId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [message] + properties: + message: + type: string + options: + type: object + properties: + temperature: + type: number + maxTokens: + type: integer + model: + type: string + provider: + type: string + includeContext: + type: boolean + useNoteContext: + type: boolean + responses: + '200': + description: LLM response + content: + application/json: + schema: + type: object + properties: + response: + type: string + sources: + type: array + items: + type: object + properties: + noteId: + type: string + title: + type: string + similarity: + type: number + + /api/llm/chat/{chatNoteId}/messages/stream: + post: + tags: [LLM] + summary: Stream message to LLM + operationId: streamChatMessage + parameters: + - name: chatNoteId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [content] + properties: + content: + type: string + useAdvancedContext: + type: boolean + showThinking: + type: boolean + mentions: + type: array + items: + type: string + responses: + '200': + description: Streaming started + + /api/llm/providers/ollama/models: + get: + tags: [LLM] + summary: List Ollama models + operationId: listOllamaModels + parameters: + - name: baseUrl + in: query + schema: + type: string + responses: + '200': + description: Ollama models + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + models: + type: array + items: + type: object + + /api/llm/providers/openai/models: + get: + tags: [LLM] + summary: List OpenAI models + operationId: listOpenAIModels + responses: + '200': + description: OpenAI models + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + chatModels: + type: array + items: + type: object + properties: + id: + type: string + name: + type: string + type: + type: string + embeddingModels: + type: array + items: + type: object + properties: + id: + type: string + name: + type: string + type: + type: string + + /api/llm/providers/anthropic/models: + get: + tags: [LLM] + summary: List Anthropic models + operationId: listAnthropicModels + responses: + '200': + description: Anthropic models + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + chatModels: + type: array + items: + type: object + properties: + id: + type: string + name: + type: string + type: + type: string + + # TOTP/2FA + /api/totp/generate: + get: + tags: [Security] + summary: Generate TOTP secret + operationId: generateTotpSecret + responses: + '200': + description: TOTP secret generated + content: + application/json: + schema: + type: object + properties: + secret: + type: string + qrCode: + type: string + + /api/totp/status: + get: + tags: [Security] + summary: Get TOTP status + operationId: getTotpStatus + responses: + '200': + description: TOTP status + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + + # ETAPI tokens + /api/etapi-tokens: + get: + tags: [Security] + summary: List ETAPI tokens + operationId: listEtapiTokens + responses: + '200': + description: ETAPI tokens + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/EtapiToken' + + post: + tags: [Security] + summary: Create ETAPI token + operationId: createEtapiToken + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [name] + properties: + name: + type: string + responses: + '201': + description: Token created + content: + application/json: + schema: + $ref: '#/components/schemas/EtapiToken' + + /api/etapi-tokens/{etapiTokenId}: + patch: + tags: [Security] + summary: Update ETAPI token + operationId: updateEtapiToken + parameters: + - name: etapiTokenId + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + responses: + '200': + description: Token updated + content: + application/json: + schema: + $ref: '#/components/schemas/EtapiToken' + + delete: + tags: [Security] + summary: Delete ETAPI token + operationId: deleteEtapiToken + parameters: + - name: etapiTokenId + in: path + required: true + schema: + type: string + responses: + '204': + description: Token deleted + + # Other utilities + /api/stats/note-size/{noteId}: + get: + tags: [Utilities] + summary: Get note size + operationId: getNoteSize + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Note size + content: + application/json: + schema: + type: object + properties: + size: + type: integer + + /api/stats/subtree-size/{noteId}: + get: + tags: [Utilities] + summary: Get subtree size + operationId: getSubtreeSize + parameters: + - $ref: '#/components/parameters/noteId' + responses: + '200': + description: Subtree size + content: + application/json: + schema: + type: object + properties: + size: + type: integer + + /api/keyboard-actions: + get: + tags: [Utilities] + summary: Get keyboard actions + operationId: getKeyboardActions + responses: + '200': + description: Keyboard actions + content: + application/json: + schema: + type: array + items: + type: object + properties: + actionName: + type: string + shortcut: + type: string + description: + type: string + + /api/fonts: + get: + tags: [Utilities] + summary: Get font CSS + operationId: getFonts + responses: + '200': + description: Font CSS + content: + text/css: + schema: + type: string + + /api/recent-notes: + post: + tags: [Utilities] + summary: Add recent note + operationId: addRecentNote + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [noteId] + properties: + noteId: + type: string + responses: + '204': + description: Note added to recent + + /api/recent-changes/{ancestorNoteId}: + get: + tags: [Utilities] + summary: Get recent changes + operationId: getRecentChanges + parameters: + - name: ancestorNoteId + in: path + required: true + schema: + type: string + responses: + '200': + description: Recent changes + content: + application/json: + schema: + type: array + items: + type: object + properties: + noteId: + type: string + title: + type: string + dateModified: + type: string + format: date-time + + /api/other/icon-usage: + get: + tags: [Utilities] + summary: Get icon usage statistics + operationId: getIconUsage + responses: + '200': + description: Icon usage stats + content: + application/json: + schema: + type: object + additionalProperties: + type: integer + + /api/other/render-markdown: + post: + tags: [Utilities] + summary: Render markdown to HTML + operationId: renderMarkdown + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [markdownContent] + properties: + markdownContent: + type: string + responses: + '200': + description: Rendered HTML + content: + text/html: + schema: + type: string + +components: + securitySchemes: + sessionAuth: + type: apiKey + in: cookie + name: trilium.sid + description: Session cookie obtained from login + + tokenAuth: + type: apiKey + in: header + name: Authorization + description: API token in format "Bearer {token}" + + parameters: + noteId: + name: noteId + in: path + required: true + schema: + type: string + description: 12-character note ID + + schemas: + Note: + type: object + required: + - noteId + - title + - type + - mime + - isProtected + properties: + noteId: + type: string + description: 12-character note ID + example: ur11rSfHkzeV + title: + type: string + description: Note title + type: + $ref: '#/components/schemas/NoteType' + mime: + type: string + description: MIME type + example: text/html + isProtected: + type: boolean + description: Whether note is protected + blobId: + type: string + description: ID of content blob + dateCreated: + type: string + format: date-time + dateModified: + type: string + format: date-time + utcDateCreated: + type: string + format: date-time + utcDateModified: + type: string + format: date-time + + NoteType: + type: string + enum: + - text + - code + - render + - file + - image + - search + - relationMap + - book + - noteMap + - mermaid + - canvas + - webView + - launcher + - doc + - contentWidget + - mindMap + - geoMap + + Branch: + type: object + required: + - branchId + - noteId + - parentNoteId + - notePosition + properties: + branchId: + type: string + description: Branch ID (parentNoteId_noteId) + noteId: + type: string + parentNoteId: + type: string + notePosition: + type: integer + prefix: + type: string + nullable: true + isExpanded: + type: boolean + + Attribute: + type: object + required: + - attributeId + - noteId + - type + - name + - value + properties: + attributeId: + type: string + noteId: + type: string + type: + type: string + enum: [label, relation] + name: + type: string + value: + type: string + position: + type: integer + isInheritable: + type: boolean + + Attachment: + type: object + required: + - attachmentId + - ownerId + - role + - mime + - title + properties: + attachmentId: + type: string + ownerId: + type: string + role: + type: string + enum: [image, file] + mime: + type: string + title: + type: string + blobId: + type: string + dateModified: + type: string + format: date-time + utcDateModified: + type: string + format: date-time + + Revision: + type: object + properties: + revisionId: + type: string + noteId: + type: string + title: + type: string + type: + $ref: '#/components/schemas/NoteType' + mime: + type: string + dateCreated: + type: string + format: date-time + utcDateCreated: + type: string + format: date-time + + SearchResult: + type: object + properties: + noteId: + type: string + title: + type: string + path: + type: string + score: + type: number + highlights: + type: array + items: + type: string + + EntityChange: + type: object + properties: + entityChange: + type: object + properties: + entityName: + type: string + changeId: + type: string + entity: + type: object + + Timestamps: + type: object + properties: + dateCreated: + type: string + format: date-time + dateModified: + type: string + format: date-time + utcDateCreated: + type: string + format: date-time + utcDateModified: + type: string + format: date-time + + CreateNoteRequest: + type: object + required: + - title + - type + properties: + title: + type: string + content: + type: string + type: + $ref: '#/components/schemas/NoteType' + mime: + type: string + isProtected: + type: boolean + isExpanded: + type: boolean + notePosition: + type: integer + prefix: + type: string + parentNoteId: + type: string + templateNoteId: + type: string + + ScriptBundle: + type: object + properties: + noteId: + type: string + script: + type: string + html: + type: string + css: + type: string + + AppInfo: + type: object + properties: + appVersion: + type: string + example: 0.91.6 + dbVersion: + type: integer + example: 228 + nodeVersion: + type: string + syncVersion: + type: integer + example: 34 + buildDate: + type: string + format: date-time + buildRevision: + type: string + dataDirectory: + type: string + clipperProtocolVersion: + type: string + utcDateTime: + type: string + format: date-time + + ChatSession: + type: object + properties: + sessionId: + type: string + title: + type: string + messages: + type: array + items: + type: object + properties: + role: + type: string + enum: [user, assistant, system] + content: + type: string + timestamp: + type: string + format: date-time + createdAt: + type: string + format: date-time + lastActive: + type: string + format: date-time + messageCount: + type: integer + + EtapiToken: + type: object + properties: + etapiTokenId: + type: string + name: + type: string + token: + type: string + dateCreated: + type: string + format: date-time + isDeleted: + type: boolean \ No newline at end of file diff --git a/apps/server/src/routes/api_docs.ts b/apps/server/src/routes/api_docs.ts index 122ae44b0..4b0b9f0ca 100644 --- a/apps/server/src/routes/api_docs.ts +++ b/apps/server/src/routes/api_docs.ts @@ -3,12 +3,22 @@ import swaggerUi from "swagger-ui-express"; import { join } from "path"; import yaml from "js-yaml"; import type { JsonObject } from "swagger-ui-express"; -import { readFileSync } from "fs"; +import { readFileSync, existsSync } from "fs"; import { RESOURCE_DIR } from "../services/resource_dir"; export default function register(app: Application) { const etapiDocument = yaml.load(readFileSync(join(RESOURCE_DIR, "etapi.openapi.yaml"), "utf8")) as JsonObject; - const apiDocument = JSON.parse(readFileSync(join(RESOURCE_DIR, "openapi.json"), "utf-8")); + + // Load the comprehensive API documentation (YAML) if available, otherwise fall back to JSON + const apiYamlPath = join(RESOURCE_DIR, "api-openapi.yaml"); + const apiJsonPath = join(RESOURCE_DIR, "openapi.json"); + + let apiDocument: JsonObject; + if (existsSync(apiYamlPath)) { + apiDocument = yaml.load(readFileSync(apiYamlPath, "utf8")) as JsonObject; + } else { + apiDocument = JSON.parse(readFileSync(apiJsonPath, "utf-8")); + } app.use( "/etapi/docs/", @@ -24,7 +34,8 @@ export default function register(app: Application) { swaggerUi.serveFiles(apiDocument), swaggerUi.setup(apiDocument, { explorer: true, - customSiteTitle: "TriliumNext Internal API Documentation" + customSiteTitle: "TriliumNext Internal API Documentation", + customCss: '.swagger-ui .topbar { display: none }' }) ); }