{ "openapi": "3.1.0", "info": { "title": "RawMark API", "version": "1", "description": "RawMark single-user API. Ordinary JSON uses {code,data,message}, with code=0 for success; HTTP semantics are preserved. Login sessions last a fixed 30 days; API tokens retain read/write permissions. Protected APIs accept Bearer authentication only, not Cookies. Files, downloads, events, 204 responses, and OpenAPI are not wrapped. Messages support Accept-Language: en or zh-CN (selected by q weight; default English), and Content-Language reports the selected language; HTTP statuses and business codes do not change. The /settings locale field stores account language (en or zh-CN); null removes the override." }, "servers": [ { "url": "/api/v1" } ], "security": [ { "bearer": [] } ], "paths": { "/health": { "get": { "summary": "Health check", "tags": [ "System" ], "security": [ {} ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Ok" }, "message": { "type": "string" } } } } } } } } }, "/openapi.json": { "get": { "summary": "This document", "tags": [ "System" ], "security": [ {} ], "responses": { "200": { "description": "OpenAPI document", "content": { "application/json": { "schema": { "type": "object" } } } } } } }, "/auth/state": { "get": { "summary": "Query initialization status", "tags": [ "Authentication" ], "security": [ {} ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "required": [ "setUp" ], "properties": { "setUp": { "type": "boolean" } } }, "message": { "type": "string" } } } } } } } } }, "/auth/setup": { "post": { "summary": "Set the initial password and return a Bearer session", "tags": [ "Authentication" ], "security": [ {} ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "password" ], "properties": { "password": { "type": "string" } } } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "required": [ "token", "expiresAt" ], "properties": { "token": { "type": "string" }, "expiresAt": { "type": "string", "format": "date-time" } } }, "message": { "type": "string" } } } } } }, "400": { "description": "Password too short", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Already initialized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "description": "Only uninitialized instances may set a password. The first successful setup signs in automatically; initialized instances return 409." } }, "/auth/login": { "post": { "summary": "Sign in with captcha and password; return a Bearer session", "tags": [ "Authentication" ], "security": [ {} ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "password", "captchaId", "captchaCode" ], "properties": { "password": { "type": "string" }, "captchaId": { "type": "string" }, "captchaCode": { "type": "string" } } } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "required": [ "token", "expiresAt" ], "properties": { "token": { "type": "string" }, "expiresAt": { "type": "string", "format": "date-time" } } }, "message": { "type": "string" } } } } } }, "401": { "description": "Incorrect password", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Too many failed attempts", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "400": { "description": "Incorrect, used, or expired captcha (40001/40002)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/logout": { "post": { "summary": "Sign out", "tags": [ "Authentication" ], "security": [ { "bearer": [] } ], "responses": { "204": { "description": "Server session revoked" } } } }, "/auth/password": { "post": { "summary": "Change the login password; retain the current session and require other devices to sign in again", "tags": [ "Authentication" ], "security": [ { "bearer": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "current": { "type": "string" }, "next": { "type": "string" } }, "required": [ "current", "next" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Ok" }, "message": { "type": "string" } } } } } }, "400": { "description": "New password too short", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Incorrect current password", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Too many failed attempts", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/settings": { "get": { "summary": "Application settings (one JSON object shared across devices)", "tags": [ "Settings" ], "responses": { "200": { "description": "Settings", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "additionalProperties": true }, "message": { "type": "string" } } } } } } } }, "patch": { "summary": "Merge settings changes", "tags": [ "Settings" ], "security": [ { "bearer": [] } ], "description": "Merge top-level keys: supplied values replace existing values, and null removes a key. On success, broadcast a settings event over WebSocket. trashRetentionDays is a nonnegative safe integer (default 30; 0 disables automatic deletion); null restores the default. Retention applies to existing and new recycle-bin entries. Startup and hourly cleanup permanently delete expired entries based on their original deletion times.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "additionalProperties": true, "properties": { "trashRetentionDays": { "type": [ "integer", "null" ], "minimum": 0, "maximum": 9007199254740991, "default": 30 } } } } } }, "responses": { "200": { "description": "Merged settings", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "additionalProperties": true }, "message": { "type": "string" } } } } } }, "400": { "description": "Not a JSON object, or invalid retention period", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "413": { "description": "Exceeds 1 MB", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tree": { "get": { "summary": "All notes, images, and folders (including .assets, excluding hidden entries and symlinks)", "tags": [ "Notes" ], "responses": { "200": { "description": "Directory tree", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "properties": { "entries": { "type": "array", "items": { "$ref": "#/components/schemas/Entry" } } } }, "message": { "type": "string" } } } } } } } } }, "/files/{path}": { "parameters": [ { "name": "path", "in": "path", "required": true, "description": "Vault-relative path, such as `folder/note.md` (URL-encode each segment)", "schema": { "type": "string" } } ], "get": { "summary": "Read a note", "tags": [ "Notes" ], "responses": { "200": { "description": "Original Markdown", "headers": { "ETag": { "description": "Content revision (rev), enclosed in double quotes", "schema": { "type": "string" } } }, "content": { "text/markdown": { "schema": { "type": "string" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "put": { "summary": "Write a note (missing parent folders are created automatically)", "tags": [ "Notes" ], "description": "Use the entire request body as note content. `If-Match: \"rev\"` requires the current revision; otherwise return 412 with the latest rev. `If-None-Match: *` requires a new note. Omitting both overwrites unconditionally.", "parameters": [ { "name": "If-Match", "in": "header", "schema": { "type": "string" } }, { "name": "If-None-Match", "in": "header", "schema": { "type": "string", "enum": [ "*" ] } } ], "requestBody": { "required": true, "content": { "text/markdown": { "schema": { "type": "string" } } } }, "responses": { "200": { "description": "Written", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "properties": { "rev": { "type": "string" } } }, "message": { "type": "string" } } } } }, "headers": { "ETag": { "description": "Content revision (rev), enclosed in double quotes", "schema": { "type": "string" } } } }, "400": { "description": "Invalid path", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Already exists with If-None-Match", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "412": { "description": "Revision conflict", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "type": "integer", "minimum": 1 }, "data": { "type": "object", "properties": { "error": { "type": "string" }, "rev": { "type": "string", "description": "Current server revision; empty if the file no longer exists" } } }, "message": { "type": "string" } } } } } }, "413": { "description": "Exceeds 20 MB", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "summary": "Move a note, image, or folder to the recycle bin (notes include their .assets directory)", "tags": [ "Notes" ], "responses": { "200": { "description": "Recycle-bin entry", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/TrashItem" }, "message": { "type": "string" } } } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/move": { "post": { "summary": "Move or rename a note, image, or folder", "tags": [ "Notes" ], "description": "A note's .assets directory follows its move; renaming rewrites links to that image directory. Image moves/renames preserve the extension and update local references in vault notes. Maintain local inbound links and relative outbound links.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Ok" }, "message": { "type": "string" } } } } } }, "404": { "description": "Source not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Destination already exists", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/folders": { "post": { "summary": "Create a folder", "tags": [ "Notes" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "path": { "type": "string" } }, "required": [ "path" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Ok" }, "message": { "type": "string" } } } } } }, "409": { "description": "Already exists", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/assets": { "post": { "summary": "Upload an image to the note's sibling assets directory", "tags": [ "Images" ], "parameters": [ { "name": "note", "in": "query", "required": false, "description": "Owning note path", "schema": { "type": "string" } }, { "name": "folder", "in": "query", "description": "Folder upload destination for image management; an empty string means the root. Mutually exclusive with note.", "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "file": { "type": "string", "format": "binary" } }, "required": [ "file" ] } } } }, "responses": { "200": { "description": "Link relative to the note's folder, ready for Markdown", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "properties": { "link": { "type": "string" } } }, "message": { "type": "string" } } } } } }, "413": { "description": "Exceeds 50 MB", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "description": "Specify exactly one of note and folder. note uploads to the note's sibling assets directory; folder uploads to that folder's assets subdirectory." } }, "/assets/import": { "post": { "summary": "Download a public image to the note's sibling assets directory", "tags": [ "Images" ], "description": "Accept only public HTTP/HTTPS URLs; validate actual connections and redirects. Do not forward login credentials or use environment proxies. At most 5 requests per redirect chain, 2 download attempts, and a 10-second timeout per attempt; retry only timeouts, 429, and 5xx. Support PNG/JPEG/GIF/WebP, detected by file signature, up to 50 MB.", "parameters": [ { "name": "note", "in": "query", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "url" ], "properties": { "url": { "type": "string", "format": "uri" } } } } } }, "responses": { "200": { "description": "Image link relative to the note's folder", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "properties": { "link": { "type": "string" } } }, "message": { "type": "string" } } } } } }, "400": { "description": "Invalid source URL or note path, or nonpublic destination", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Owning note not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "413": { "description": "Image exceeds 50 MB", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Unsupported image type", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "502": { "description": "Source request failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/raw/{path}": { "parameters": [ { "name": "path", "in": "path", "required": true, "description": "Vault-relative path, such as `folder/note.md` (URL-encode each segment)", "schema": { "type": "string" } } ], "get": { "summary": "Read a raw vault file, such as an image", "tags": [ "Images" ], "responses": { "200": { "description": "File contents", "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/search": { "get": { "summary": "Full-text search", "tags": [ "Notes" ], "description": "Space-separated terms must all match; return at most 50 results.", "parameters": [ { "name": "q", "in": "query", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Results", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "properties": { "results": { "type": "array", "items": { "$ref": "#/components/schemas/SearchResult" } } } }, "message": { "type": "string" } } } } } } } } }, "/trash": { "get": { "summary": "List the recycle bin", "tags": [ "Recycle bin" ], "responses": { "200": { "description": "Entries", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/TrashItem" } } } }, "message": { "type": "string" } } } } } } } }, "delete": { "summary": "Empty all recycle-bin entries", "description": "Permanent and irreversible deletion. Report per-entry results and retain failed entries. Read-only tokens are forbidden.", "tags": [ "Recycle bin" ], "responses": { "200": { "description": "Per-entry success and failure results", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/TrashPurgeResult" }, "message": { "type": "string" } } } } } } } } }, "/trash/{id}/restore": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "post": { "summary": "Restore from the recycle bin", "tags": [ "Recycle bin" ], "responses": { "200": { "description": "Restored entry", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/TrashItem" }, "message": { "type": "string" } } } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "A file already exists at the original path", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/trash/{id}": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "delete": { "summary": "Permanently delete a recycle-bin entry", "tags": [ "Recycle bin" ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Ok" }, "message": { "type": "string" } } } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/events": { "get": { "summary": "WebSocket vault-change events", "tags": [ "Notes" ], "description": "After upgrading to WebSocket, the server sends JSON arrays of Event objects. Clients send no messages.", "responses": { "101": { "description": "Upgrade to WebSocket" } } } }, "/tokens": { "get": { "summary": "List API tokens", "tags": [ "API tokens" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Tokens", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "properties": { "tokens": { "type": "array", "items": { "$ref": "#/components/schemas/APIToken" } } } }, "message": { "type": "string" } } } } } } } }, "post": { "summary": "Create an API token", "tags": [ "API tokens" ], "security": [ { "bearer": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "scope": { "type": "string", "enum": [ "read", "write" ] } }, "required": [ "name", "scope" ] } } } }, "responses": { "200": { "description": "Plaintext token is returned only once", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "properties": { "token": { "type": "string" }, "info": { "$ref": "#/components/schemas/APIToken" } } }, "message": { "type": "string" } } } } } }, "400": { "description": "Invalid name or scope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/tokens/{id}": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "delete": { "summary": "Revoke an API token", "tags": [ "API tokens" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Ok" }, "message": { "type": "string" } } } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/themes": { "get": { "summary": "List themes, including built-in defaults", "tags": [ "Appearance" ], "responses": { "200": { "description": "Theme list", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "properties": { "themes": { "type": "array", "items": { "$ref": "#/components/schemas/Theme" } } } }, "message": { "type": "string" } } } } } } } } }, "/themes/{id}": { "get": { "summary": "Read theme CSS", "tags": [ "Appearance" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Theme metadata and CSS", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "allOf": [ { "$ref": "#/components/schemas/Theme" }, { "type": "object", "properties": { "css": { "type": "string" } } } ] }, "message": { "type": "string" } } } } } }, "404": { "description": "Theme not found or incomplete files" } } } }, "/plugins": { "get": { "summary": "List installed plugins and their enabled state", "tags": [ "Plugins" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "properties": { "plugins": { "type": "array", "items": { "$ref": "#/components/schemas/Plugin" } } } }, "message": { "type": "string" } } } } } }, "401": { "description": "Login session required" }, "400": { "description": "Invalid request or plugin archive" }, "403": { "description": "API tokens are not accepted" } } }, "post": { "summary": "Install a ZIP plugin; disabled by default after installation; reject an existing id", "tags": [ "Plugins" ], "security": [ { "bearer": [] } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Plugin" }, "message": { "type": "string" } } } } } }, "401": { "description": "Login session required" }, "400": { "description": "Invalid request or plugin archive" }, "403": { "description": "API tokens are not accepted" }, "409": { "description": "A plugin with this name is already installed" }, "413": { "description": "ZIP exceeds 10 MiB" } }, "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "required": [ "file" ], "properties": { "file": { "type": "string", "format": "binary" } } } } } } } }, "/plugins/{id}": { "patch": { "summary": "Change plugin enablement preferences across devices", "tags": [ "Plugins" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Plugin" }, "message": { "type": "string" } } } } } }, "401": { "description": "Login session required" }, "400": { "description": "Invalid request or plugin archive" }, "403": { "description": "API tokens are not accepted" }, "404": { "description": "Plugin or requested resource version not found" } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "enabled" ], "properties": { "enabled": { "type": "boolean" } } } } } } }, "delete": { "summary": "Disable and uninstall a plugin package while retaining private plugin data", "tags": [ "Plugins" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Ok" }, "message": { "type": "string" } } } } } }, "401": { "description": "Login session required" }, "400": { "description": "Invalid request or plugin archive" }, "403": { "description": "API tokens are not accepted" }, "404": { "description": "Plugin or requested resource version not found" } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ] } }, "/plugins/{id}/data": { "get": { "summary": "Read private plugin JSON; null when no data exists", "tags": [ "Plugins" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "required": [ "data" ], "properties": { "data": {} } }, "message": { "type": "string" } } } } } }, "401": { "description": "Login session required" }, "400": { "description": "Invalid request or plugin archive" }, "403": { "description": "API tokens are not accepted" }, "404": { "description": "Plugin or requested resource version not found" } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ] }, "put": { "summary": "Replace private plugin JSON, up to 1 MiB", "tags": [ "Plugins" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "required": [ "data" ], "properties": { "data": {} } }, "message": { "type": "string" } } } } } }, "401": { "description": "Login session required" }, "400": { "description": "Invalid request or plugin archive" }, "403": { "description": "API tokens are not accepted" }, "404": { "description": "Plugin or requested resource version not found" } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "data" ], "properties": { "data": {} } } } } } } }, "/plugins/{id}/assets/{revision}/{path}": { "get": { "summary": "Read authenticated package resources for a specific installed version", "tags": [ "Plugins" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success" }, "401": { "description": "Login session required" }, "400": { "description": "Invalid request or plugin archive" }, "403": { "description": "API tokens are not accepted" }, "404": { "description": "Plugin or requested resource version not found" } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "revision", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "path", "in": "path", "required": true, "schema": { "type": "string" } } ] } }, "/import": { "post": { "summary": "Import Markdown files or a ZIP vault", "tags": [ "Files" ], "description": "Accept multiple .md files or one ZIP, up to 100 MB total. ZIP imports require a new folder name. The destination directory must exist; conflicts do not overwrite. After extraction and organization: up to 512 MiB, 10,000 entries, 20 MiB per note, and 50 MiB per attachment. Markdown and ZIP filenames must be UTF-8. Preserve ZIP hierarchy; normalize local images into sibling assets directories and rewrite references. Remove migrated originals only when unreferenced; retain other attachments. Do not download external links; return warnings for missing local targets.", "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "required": [ "files" ], "properties": { "dir": { "type": "string", "description": "Destination folder; an empty string means the root" }, "folder": { "type": "string", "description": "New folder name for ZIP import; leave empty for plain Markdown" }, "files": { "type": "array", "items": { "type": "string", "format": "binary" } } } } } } }, "responses": { "201": { "description": "Import succeeded", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "required": [ "paths", "notes", "assets", "warnings" ], "properties": { "paths": { "type": "array", "items": { "type": "string" } }, "notes": { "type": "integer" }, "assets": { "type": "integer", "description": "Total retained attachment files, including shared images and other original attachments" }, "warnings": { "type": "array", "items": { "type": "string" } } } }, "message": { "type": "string" } } } } } }, "400": { "description": "Invalid format, path, or encoding" }, "401": { "description": "Not signed in or invalid token" }, "403": { "description": "Read-only tokens cannot import" }, "404": { "description": "Destination folder not found" }, "409": { "description": "Destination already exists; no overwrite" }, "413": { "description": "Upload, expanded-size, entry-count, or per-file size limit exceeded" } } } }, "/assets/{path}": { "put": { "summary": "Replace an existing image in place, preserving its path and references", "tags": [ "Images" ], "parameters": [ { "name": "path", "in": "path", "required": true, "description": "Image path within the vault", "schema": { "type": "string" } } ], "description": "The multipart file extension must match the target image. Do not create new files; maximum 50 MB. The old image is not sent to the recycle bin.", "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "file": { "type": "string", "format": "binary" } }, "required": [ "file" ] } } } }, "responses": { "200": { "description": "Replacement succeeded", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Ok" }, "message": { "type": "string" } } } } } }, "400": { "description": "Invalid path, empty file, or mismatched extension" }, "404": { "description": "Target image not found" }, "413": { "description": "Exceeds 50 MB" } } } }, "/export": { "post": { "summary": "Export original Markdown and local attachments", "description": "Accept a nonempty path list. Return .md for a single note without attachments; folders, multiple selections, or notes with attachments return ZIP. ZIP preserves vault-relative paths. Do not download external resources or follow unselected notes. Missing attachments or invalid paths return errors. This POST does not modify data and accepts read-only tokens.", "tags": [ "Files" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "paths" ], "properties": { "paths": { "type": "array", "minItems": 1, "items": { "type": "string" } } } } } } }, "responses": { "200": { "description": "Original Markdown or ZIP attachment", "content": { "application/zip": { "schema": { "type": "string", "format": "binary" } }, "text/markdown": { "schema": { "type": "string" } } } }, "400": { "description": "Invalid path" }, "404": { "description": "File or attachment not found" } } } }, "/metadata": { "get": { "summary": "Read the note-relationship, tag, and resource-reference index", "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Index readiness and metadata list, excluding note contents", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "required": [ "notes", "ready" ], "properties": { "notes": { "type": "array", "items": { "$ref": "#/components/schemas/NoteMetadata" } }, "ready": { "type": "boolean" } } }, "message": { "type": "string" } } } } } } } } }, "/assets/cleanup": { "post": { "summary": "Recheck vault-wide references and move unreferenced images to the recycle bin", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "paths" ], "properties": { "paths": { "type": "array", "minItems": 1, "maxItems": 1000, "items": { "type": "string" } } } } } } }, "responses": { "200": { "description": "Images moved to the recycle bin and reasons for skipped items", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/CleanupImagesResult" }, "message": { "type": "string" } } } } } }, "400": { "description": "Invalid request or note metadata prevents reference verification" } } } }, "/tree-icon": { "put": { "summary": "Set a file or folder icon; null restores the default", "tags": [ "Files" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "path", "icon" ], "properties": { "path": { "type": "string" }, "icon": { "oneOf": [ { "$ref": "#/components/schemas/TreeIcon" }, { "type": "null" } ] } } } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Ok" }, "message": { "type": "string" } } } } } }, "400": { "description": "Invalid path or icon" }, "404": { "description": "File not found" } } } }, "/fonts": { "get": { "summary": "List imported fonts", "tags": [ "Settings" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "required": [ "fonts" ], "properties": { "fonts": { "type": "array", "items": { "$ref": "#/components/schemas/CustomFont" } } } }, "message": { "type": "string" } } } } } }, "401": { "description": "Not signed in" }, "403": { "description": "Login sessions only" } } }, "post": { "summary": "Import a font with content deduplication (TTF/OTF/WOFF/WOFF2, up to 30 MB)", "tags": [ "Settings" ], "security": [ { "bearer": [] } ], "responses": { "201": { "description": "New font imported", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/CustomFont" }, "message": { "type": "string" } } } } } }, "401": { "description": "Not signed in" }, "403": { "description": "Login sessions only" }, "200": { "description": "Identical font contents already exist; return the original font", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/CustomFont" }, "message": { "type": "string" } } } } } } }, "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "required": [ "file" ], "properties": { "file": { "type": "string", "format": "binary" } } } } } } } }, "/fonts/{id}": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "delete": { "summary": "Delete an imported font and reset interface, text, and code fonts using it to Maple; Maple cannot be deleted", "tags": [ "Settings" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Ok" }, "message": { "type": "string" } } } } } }, "401": { "description": "Not signed in" }, "403": { "description": "Login sessions only" } } } }, "/fonts/{id}/file": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "get": { "summary": "Read an imported font file", "tags": [ "Settings" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success" }, "401": { "description": "Not signed in" }, "403": { "description": "Login sessions only" } } } }, "/storage": { "get": { "summary": "Calculate storage usage on demand", "description": "Login sessions only. Count regular-file bytes in the data directory and actual vault, deduplicating nested roots and ignoring internal symlinks. Attachments/recycle bin are subsets of the vault and do not add to totalSize twice. calculatedAt is the completion time in Unix milliseconds. Scanning failures return errors, not partial results.", "tags": [ "Settings" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Storage totals", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/StorageUsage" }, "message": { "type": "string" } } } } } }, "403": { "description": "Login sessions only" }, "500": { "description": "Scan failed" } } } }, "/maintenance/status": { "get": { "summary": "Maintenance status", "tags": [ "Maintenance" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/MaintenanceStatus" }, "message": { "type": "string" } } } } } }, "401": { "description": "Not signed in", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API tokens are not accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/maintenance/export/{kind}": { "post": { "summary": "Export a full instance or settings archive", "tags": [ "Maintenance" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "ZIP download", "content": { "application/zip": { "schema": { "type": "string", "format": "binary" } } } }, "400": { "description": "Invalid operation or input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not signed in", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API tokens are not accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Maintenance in progress, insufficient disk space, or operation unsupported by the current service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Filesystem, database, or other internal failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "parameters": [ { "name": "kind", "in": "path", "required": true, "schema": { "type": "string" } } ] } }, "/maintenance/notes/export": { "post": { "summary": "Export a plain Markdown vault", "tags": [ "Maintenance" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "ZIP download", "content": { "application/zip": { "schema": { "type": "string", "format": "binary" } } } }, "400": { "description": "Invalid operation or input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not signed in", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API tokens are not accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Maintenance in progress, insufficient disk space, or operation unsupported by the current service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Filesystem, database, or other internal failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/maintenance/uploads": { "post": { "summary": "Create a backup upload, up to 2 GiB compressed and 8 MiB per chunk", "tags": [ "Maintenance" ], "security": [ { "bearer": [] } ], "responses": { "400": { "description": "Invalid operation or input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not signed in", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API tokens are not accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Maintenance in progress, insufficient disk space, or operation unsupported by the current service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "201": { "description": "Return upload id", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "required": [ "id" ], "properties": { "id": { "type": "string" } } }, "message": { "type": "string" } } } } } }, "500": { "description": "Filesystem, database, or other internal failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "kind", "size" ], "properties": { "kind": { "type": "string", "enum": [ "full", "settings" ] }, "size": { "type": "integer", "minimum": 1, "maximum": 2147483648 } } } } } } } }, "/maintenance/uploads/{id}": { "put": { "summary": "Append backup chunks sequentially", "tags": [ "Maintenance" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "required": [ "offset" ], "properties": { "offset": { "type": "integer" } } }, "message": { "type": "string" } } } } } }, "400": { "description": "Invalid operation or input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not signed in", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API tokens are not accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Maintenance in progress, insufficient disk space, or operation unsupported by the current service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Filesystem, database, or other internal failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "Upload-Offset", "in": "header", "required": true, "schema": { "type": "integer", "minimum": 0 } } ], "requestBody": { "required": true, "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } } } }, "delete": { "summary": "Cancel an upload owned by the current session", "tags": [ "Maintenance" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Ok" }, "message": { "type": "string" } } } } } }, "400": { "description": "Invalid operation or input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not signed in", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API tokens are not accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Maintenance in progress, insufficient disk space, or operation unsupported by the current service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Filesystem, database, or other internal failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ] } }, "/maintenance/uploads/{id}/validate": { "post": { "summary": "Validate an archive and produce a summary, up to 8 GiB expanded and 100,000 entries", "tags": [ "Maintenance" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/BackupSummary" }, "message": { "type": "string" } } } } } }, "400": { "description": "Invalid operation or input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not signed in", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API tokens are not accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Maintenance in progress, insufficient disk space, or operation unsupported by the current service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Filesystem, database, or other internal failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ] } }, "/maintenance/settings/import": { "post": { "summary": "Import confirmed settings and resources after creating a backup", "tags": [ "Maintenance" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Ok" }, "message": { "type": "string" } } } } } }, "400": { "description": "Invalid operation or input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not signed in", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API tokens are not accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Maintenance in progress, insufficient disk space, or operation unsupported by the current service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Filesystem, database, or other internal failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "confirmed", "id" ], "properties": { "confirmed": { "type": "boolean", "const": true }, "id": { "type": "string" } } } } } } } }, "/maintenance/settings/reset": { "post": { "summary": "Reset confirmed preferences while retaining plugin storage", "tags": [ "Maintenance" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Ok" }, "message": { "type": "string" } } } } } }, "400": { "description": "Invalid operation or input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not signed in", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API tokens are not accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Maintenance in progress, insufficient disk space, or operation unsupported by the current service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Filesystem, database, or other internal failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "confirmed" ], "properties": { "confirmed": { "type": "boolean", "const": true } } } } } } } }, "/maintenance/restore": { "post": { "summary": "Restore a confirmed full instance after backup; require signing in again", "tags": [ "Maintenance" ], "security": [ { "bearer": [] } ], "responses": { "400": { "description": "Invalid operation or input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not signed in", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API tokens are not accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Maintenance in progress, insufficient disk space, or operation unsupported by the current service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "202": { "description": "Restore submitted; the service will briefly enter maintenance and require signing in again", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "required": [ "restarting" ], "properties": { "restarting": { "type": "boolean" } } }, "message": { "type": "string" } } } } } }, "500": { "description": "Filesystem, database, or other internal failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "confirmed", "id" ], "properties": { "confirmed": { "type": "boolean", "const": true }, "id": { "type": "string" } } } } } } } }, "/maintenance/index/{operation}": { "post": { "summary": "Optimize or rebuild the index", "tags": [ "Maintenance" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/Ok" }, "message": { "type": "string" } } } } } }, "400": { "description": "Invalid operation or input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not signed in", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API tokens are not accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Maintenance in progress, insufficient disk space, or operation unsupported by the current service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Filesystem, database, or other internal failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "parameters": [ { "name": "operation", "in": "path", "required": true, "schema": { "type": "string" } } ] } }, "/maintenance/temp/clear": { "post": { "summary": "Clean unused application temporary files", "tags": [ "Maintenance" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "$ref": "#/components/schemas/ClearTempResult" }, "message": { "type": "string" } } } } } }, "400": { "description": "Invalid operation or input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not signed in", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API tokens are not accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Maintenance in progress, insufficient disk space, or operation unsupported by the current service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Filesystem, database, or other internal failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/maintenance/logs/export": { "post": { "summary": "Export application logs and a runtime summary", "tags": [ "Maintenance" ], "security": [ { "bearer": [] } ], "responses": { "200": { "description": "ZIP download", "content": { "application/zip": { "schema": { "type": "string", "format": "binary" } } } }, "400": { "description": "Invalid operation or input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not signed in", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "API tokens are not accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Maintenance in progress, insufficient disk space, or operation unsupported by the current service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Filesystem, database, or other internal failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/me": { "get": { "summary": "Restore login-session identity and permissions", "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "required": [ "permissions", "expiresAt" ], "properties": { "permissions": { "type": "array", "items": { "type": "string" } }, "expiresAt": { "type": "string", "format": "date-time" } } }, "message": { "type": "string" } } } } } }, "401": { "description": "Invalid or expired login credential", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Login session required; API tokens cannot call this endpoint", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/captcha": { "post": { "summary": "Issue a single-use sign-in captcha valid for 5 minutes", "security": [ {} ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [], "properties": { "replaceId": { "type": "string" } } } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "required": [ "captchaId", "imageDataUrl", "expiresAt" ], "properties": { "captchaId": { "type": "string" }, "imageDataUrl": { "type": "string" }, "expiresAt": { "type": "string", "format": "date-time" } } }, "message": { "type": "string" } } } } } }, "429": { "description": "Captcha issuance rate or capacity limit reached", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/auth/tickets": { "post": { "summary": "Issue resource-read or one-use event tickets bound to the current session", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "kind" ], "properties": { "kind": { "enum": [ "images", "fonts", "plugin", "events" ] }, "pluginId": { "type": "string" }, "revision": { "type": "string" } } } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "const": 0 }, "data": { "type": "object", "required": [ "url", "expiresAt" ], "properties": { "url": { "type": "string" }, "expiresAt": { "type": "string", "format": "date-time" } } }, "message": { "type": "string" } } } } } }, "401": { "description": "Invalid or expired login credential", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Login session required; API tokens cannot call this endpoint", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/resources/{ticket}/{kind}/{path}": { "get": { "summary": "Restricted native resource. Event tickets are single-use and expire after 60 seconds; other tickets expire with the parent session. Check the parent session on every request.", "security": [ {} ], "parameters": [ { "name": "ticket", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "kind", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "path", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Raw resource contents" }, "101": { "description": "WebSocket event upgrade" } } } } }, "components": { "securitySchemes": { "bearer": { "type": "http", "scheme": "bearer", "description": "API token (prefixed with rm_)" } }, "schemas": { "Error": { "type": "object", "required": [ "code", "data", "message" ], "properties": { "code": { "type": "integer", "minimum": 1 }, "data": { "type": [ "object", "null" ] }, "message": { "type": "string" } } }, "Ok": { "type": "object", "properties": { "ok": { "type": "boolean" } }, "required": [ "ok" ] }, "Entry": { "type": "object", "properties": { "path": { "type": "string" }, "dir": { "type": "boolean" }, "size": { "type": "integer" }, "mtime": { "type": "integer", "description": "Modification time (Unix milliseconds)" }, "icon": { "$ref": "#/components/schemas/TreeIcon" } } }, "TrashItem": { "type": "object", "properties": { "id": { "type": "string" }, "path": { "type": "string", "description": "Original path" }, "dir": { "type": "boolean" }, "deletedAt": { "type": "integer", "description": "Unix milliseconds" }, "assets": { "type": "string", "description": "Legacy image directory retained with the entry; optional" } }, "required": [ "id", "path", "dir", "deletedAt" ] }, "SearchResult": { "type": "object", "properties": { "path": { "type": "string" }, "line": { "type": "integer", "description": "First matching line, starting at 1; 0 when only the path matches" }, "snippet": { "type": "string" } } }, "Event": { "type": "object", "description": "tree: directory structure changed; changed: contents changed (rev is the new revision); deleted: deletion; moved: move (from -> path); settings: settings changed", "properties": { "type": { "type": "string", "enum": [ "tree", "changed", "deleted", "moved", "settings" ] }, "path": { "type": "string" }, "from": { "type": "string" }, "rev": { "type": "string" } } }, "APIToken": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "scope": { "type": "string", "enum": [ "read", "write" ] }, "createdAt": { "type": "integer" }, "lastUsedAt": { "type": "integer", "description": "Unix milliseconds; 0 means never used" } } }, "Theme": { "type": "object", "required": [ "id", "name", "version" ], "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "version": { "type": "string" } } }, "Plugin": { "type": "object", "required": [ "id", "name", "version", "apiVersion", "revision", "enabled" ], "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "version": { "type": "string" }, "revision": { "type": "string" }, "apiVersion": { "type": "integer", "const": 1 }, "enabled": { "type": "boolean" } } }, "TreeIcon": { "type": "object", "required": [ "kind", "value" ], "properties": { "kind": { "type": "string", "enum": [ "emoji", "builtin" ] }, "value": { "type": "string", "description": "Emoji character or built-in outline icon name, up to 64 bytes" } } }, "TrashPurgeResult": { "type": "object", "required": [ "deleted", "failed" ], "properties": { "deleted": { "type": "array", "items": { "type": "string" } }, "failed": { "type": "array", "items": { "type": "object", "required": [ "id", "error" ], "properties": { "id": { "type": "string" }, "error": { "type": "string" } } } } } }, "StorageUsage": { "type": "object", "required": [ "totalSize", "categories", "assetsSize", "trashSize", "calculatedAt", "builtinFontsSize", "customFontsSize" ], "properties": { "totalSize": { "type": "integer", "minimum": 0 }, "assetsSize": { "type": "integer", "minimum": 0 }, "trashSize": { "type": "integer", "minimum": 0 }, "calculatedAt": { "type": "integer", "minimum": 0 }, "categories": { "type": "array", "items": { "type": "object", "required": [ "id", "size" ], "properties": { "id": { "type": "string", "enum": [ "vault", "databases", "fonts", "themes", "plugins", "other" ] }, "size": { "type": "integer", "minimum": 0 } } } }, "builtinFontsSize": { "type": "integer", "minimum": 0 }, "customFontsSize": { "type": "integer", "minimum": 0 } } }, "NoteReference": { "type": "object", "required": [ "target", "line" ], "properties": { "target": { "type": "string" }, "line": { "type": "integer" } } }, "NoteMetadata": { "type": "object", "required": [ "path", "rev", "title", "tags", "links", "assets", "warnings" ], "properties": { "path": { "type": "string" }, "rev": { "type": "string" }, "title": { "type": "string" }, "tags": { "type": "array", "items": { "type": "string" } }, "links": { "type": "array", "items": { "$ref": "#/components/schemas/NoteReference" } }, "assets": { "type": "array", "items": { "$ref": "#/components/schemas/NoteReference" } }, "warnings": { "type": "array", "items": { "type": "string" } } } }, "CleanupImagesResult": { "type": "object", "required": [ "deleted", "skipped" ], "properties": { "deleted": { "type": "array", "items": { "$ref": "#/components/schemas/TrashItem" } }, "skipped": { "type": "array", "items": { "type": "object", "required": [ "path", "reason" ], "properties": { "path": { "type": "string" }, "reason": { "type": "string" } } } } } }, "CustomFont": { "type": "object", "required": [ "id", "name", "format" ], "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "format": { "type": "string", "enum": [ "ttf", "otf", "woff", "woff2" ] } } }, "MaintenanceStatus": { "type": "object", "required": [ "busy", "operation", "error", "finishedAt" ], "properties": { "busy": { "type": "boolean" }, "operation": { "type": "string" }, "error": { "type": "string" }, "finishedAt": { "type": "integer" }, "backup": { "type": "string" } } }, "BackupSummary": { "type": "object", "required": [ "kind", "createdAt", "entries", "size" ], "properties": { "kind": { "type": "string", "enum": [ "full", "settings" ] }, "createdAt": { "type": "integer" }, "entries": { "type": "integer" }, "size": { "type": "integer" } } }, "ClearTempResult": { "type": "object", "required": [ "files", "bytes", "failed" ], "properties": { "files": { "type": "integer" }, "bytes": { "type": "integer" }, "failed": { "type": "array", "items": { "type": "string" } } } } } }, "x-business-codes": { "0": "Success", "40000": "Invalid parameters", "40001": "Incorrect or already-used captcha", "40002": "Expired captcha", "40003": "Incorrect current password", "40100": "Invalid authentication", "40101": "Incorrect sign-in password", "40300": "Insufficient permissions", "40400": "Resource not found", "40900": "Resource conflict", "41200": "Document revision conflict; data.rev is the latest revision", "41300": "Size limit exceeded", "42900": "Too many requests", "50000": "Server error", "50300": "Maintenance in progress" } }