Files

5117 lines
134 KiB
JSON

{
"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"
}
}