Notes

Rich-text note editor with end-to-end encrypted content. User-facing content (titles, preview text, full body) is encrypted client-side before reaching the server. Metadata used for filtering and smart lists (pinned, trashed, shared flags) is stored in the clear.

Notes support split field projections: list views fetch only enc_title and enc_preview for fast rendering, while the full enc_content body is loaded on demand when a note is opened.

All methods use the JSON-RPC 2.0 protocol over WebSocket. See Enbox API for transport details, error codes, query operators, and encryption model.

Service: notes.notes

Fields

Field Type Required Description
id string Primary key. Read-only, auto-generated
folder_id string? Parent folder id. null = unfiled
owner_id string Owner user id. Read-only, auto-set on create
owner_wrapped_key string Content key wrapped by owner’s account key (base64)
folder_wrapped_key string? Content key wrapped by folder key. null when not in a shared folder
pinned boolean Pinned to top. Default false
trashed boolean Moved to trash. Default false
shared boolean Shared with other users. Default false
position float Fractional drag-sort position within a folder
enc_title string Encrypted note title. Plain string after decryption
enc_preview string Encrypted plain-text excerpt for list display. Plain string after decryption (~200 chars, no HTML)
enc_content string? Encrypted full body. Plain string after decryption (Markdown). Nullable — loaded via detail projection only
created_at string ISO 8601 creation timestamp. Read-only
updated_at string ISO 8601 last update timestamp. Read-only
note_tag string[] Assigned tag IDs
note_attachment Attachment[] File metadata. Returned in detail view

Filterable: folder_id · pinned · trashed · shared

Attachment

File metadata within a note. Binary content is uploaded and downloaded via the Attachments service using presigned URLs.

Field Type Required Description
id string Primary key. Read-only. Omit when creating
size_bytes integer Logical plaintext file size in bytes
status string Upload state. Read-only. Values: pending (uploading) · ready (finalized)
enc_name string Encrypted file name. Plain string after decryption
enc_mime_type string Encrypted MIME type. Plain string after decryption (e.g. "image/png", "application/pdf")
thumbnail_128_id string? Chunk id of the encrypted 128 px thumbnail. Read-only. null for non-image files
chunk_count integer Number of uploaded chunks. Read-only, computed

AttachmentChunk

Ordered chunk reference for a file attachment. Created by confirmChunk.

Field Type Required Description
id string Primary key. Read-only
attachment_id string Parent Attachment id
chunk_index integer 0-based chunk order
chunk_id string Reference to the stored encrypted blob

Encrypted field details

Each enc_* column is an AES-GCM blob. After decryption the plaintext is a JSON value.

Danger: The server cannot validate encrypted field structures. Writing an incorrect schema will produce corrupted data for all clients. Follow the type definitions below exactly.

Field Decrypted type Description
enc_title string Note title. Plain text, no HTML
enc_preview string First ~200 characters of the note body, stripped of Markdown formatting. Used for list rendering without decrypting the full body
enc_content string Full note body as Markdown (e.g. "## Title\n\nBody text\n\n- Item"). Supports standard Markdown: headings (# … ######), paragraphs, lists (- …, 1. …), bold (**text**), italic (*text*), links ([text](url)), code (`inline`, fenced blocks), blockquotes (>), images (![alt](url)), checklists (- [ ] …)

Warning: When saving a note, always update both enc_title and enc_preview alongside enc_content. The enc_preview must be a plain-text excerpt stripped of all Markdown formatting (~200 characters). Clients that rely on list view will display stale data if enc_preview is not kept in sync.

find

List notes with filtering, sorting, and pagination. Uses list projection — enc_content is excluded for performance.

WebSocket

Request

{
  "jsonrpc": "2.0",
  "method": "notes.notes.find",
  "params": {
    "filter": { "trashed": { "$eq": false } },
    "sort": [{ "field": "updated_at", "dir": "desc" }],
    "limit": 100,
    "fields": [
      "id", "folder_id", "pinned", "trashed", "shared", "position",
      "created_at", "updated_at",
      "enc_title", "enc_preview",
      "owner_id", "owner_wrapped_key", "folder_wrapped_key",
      "note_tag.tag_id"
    ]
  },
  "id": 1
}

Response

{
  "jsonrpc": "2.0",
  "result": {
    "items": [
      {
        "id": "1920438291738",
        "folder_id": "1920438291700",
        "pinned": true,
        "trashed": false,
        "shared": false,
        "position": 1000.0,
        "created_at": "2026-05-01T10:30:00Z",
        "updated_at": "2026-05-13T18:30:00Z",
        "enc_title": "<base64>",
        "enc_preview": "<base64>",
        "owner_id": "42",
        "owner_wrapped_key": "<base64>",
        "folder_wrapped_key": null,
        "note_tag": ["1920438291800"]
      }
    ],
    "total": 47
  },
  "id": 1
}

findOneById

Fetch a single note with full detail including the encrypted body and attachments.

WebSocket

Request

{
  "jsonrpc": "2.0",
  "method": "notes.notes.findOneById",
  "params": {
    "id": "1920438291738",
    "fields": [
      "id", "folder_id", "pinned", "trashed", "shared", "position",
      "created_at", "updated_at",
      "enc_title", "enc_preview", "enc_content",
      "owner_id", "owner_wrapped_key", "folder_wrapped_key",
      "note_tag.tag_id",
      "note_attachment.id", "note_attachment.size_bytes", "note_attachment.status",
      "note_attachment.enc_name", "note_attachment.enc_mime_type",
      "note_attachment.thumbnail_128_id", "note_attachment.chunk_count"
    ]
  },
  "id": 2
}

Response

{
  "jsonrpc": "2.0",
  "result": {
    "id": "1920438291738",
    "folder_id": "1920438291700",
    "pinned": true,
    "trashed": false,
    "shared": false,
    "position": 1000.0,
    "created_at": "2026-05-01T10:30:00Z",
    "updated_at": "2026-05-13T18:30:00Z",
    "enc_title": "<base64>",
    "enc_preview": "<base64>",
    "enc_content": "<base64>",
    "owner_id": "42",
    "owner_wrapped_key": "<base64>",
    "folder_wrapped_key": null,
    "note_tag": ["1920438291800"],
    "note_attachment": [
      {
        "id": "1920438291760",
        "size_bytes": 102400,
        "status": "ready",
        "enc_name": "<base64>",
        "enc_mime_type": "<base64>",
        "thumbnail_128_id": "1920438291770",
        "chunk_count": 1
      }
    ]
  },
  "id": 2
}

create

Create a new note. The server assigns id, created_at, and updated_at.

WebSocket

Request

{
  "jsonrpc": "2.0",
  "method": "notes.notes.create",
  "params": {
    "document": {
      "folder_id": "1920438291700",
      "pinned": false,
      "position": 1000.0,
      "enc_title": "<base64>",
      "enc_preview": "<base64>",
      "enc_content": "<base64>",
      "owner_wrapped_key": "<base64>",
      "note_tag": ["1920438291800"]
    }
  },
  "id": 3
}

Response

{
  "jsonrpc": "2.0",
  "result": {
    "id": "1920438291738",
    "enc_title": "<base64>",
    "created_at": "2026-05-13T18:30:00Z"
  },
  "id": 3
}

updateOneById

Partial update — only specified fields change; omitted fields are untouched. Nested collections are updated automatically: items with id are updated, items without id are created, items missing from the array are deleted.

WebSocket

Request

{
  "jsonrpc": "2.0",
  "method": "notes.notes.updateOneById",
  "params": {
    "id": "1920438291738",
    "document": {
      "enc_title": "<base64-new>",
      "enc_preview": "<base64-new>",
      "enc_content": "<base64-new>"
    }
  },
  "id": 4
}

Response

{
  "jsonrpc": "2.0",
  "result": {
    "id": "1920438291738",
    "enc_title": "<base64-new>",
    "updated_at": "2026-05-13T18:45:00Z"
  },
  "id": 4
}

replaceOneById

Full replacement — all writable fields must be provided. Unlike updateOneById, omitted fields are reset to defaults. Ownership fields (owner_id, owner_wrapped_key) and nested collections (note_tag, note_attachment) are not accepted in this method — use updateOneById to modify them.

WebSocket

Request

{
  "jsonrpc": "2.0",
  "method": "notes.notes.replaceOneById",
  "params": {
    "id": "1920438291738",
    "document": {
      "folder_id": "1920438291700",
      "pinned": true,
      "position": 1000.0,
      "enc_title": "<base64>",
      "enc_preview": "<base64>",
      "enc_content": "<base64>"
    }
  },
  "id": 4
}

update

Batch update multiple notes in a single transaction (all-or-nothing). See Batch operations.

WebSocket

Request

{
  "jsonrpc": "2.0",
  "method": "notes.notes.update",
  "params": {
    "items": [
      { "id": "1920438291738", "document": { "folder_id": "1920438291710" } },
      { "id": "1920438291739", "document": { "folder_id": "1920438291710" } }
    ]
  },
  "id": 5
}

Response

{
  "jsonrpc": "2.0",
  "result": {
    "affected": 2,
    "items": [
      { "id": "1920438291738", "folder_id": "1920438291710" },
      { "id": "1920438291739", "folder_id": "1920438291710" }
    ]
  },
  "id": 5
}

deleteOneById

Delete a note. All attachments and tag assignments are deleted with it.

WebSocket

Request

{
  "jsonrpc": "2.0",
  "method": "notes.notes.deleteOneById",
  "params": {
    "id": "1920438291738"
  },
  "id": 6
}

Response

{
  "jsonrpc": "2.0",
  "result": {
    "id": "1920438291738",
    "enc_title": "<base64>"
  },
  "id": 6
}

delete

Batch delete notes in a single transaction (all-or-nothing). See Batch operations.

WebSocket

Request

{
  "jsonrpc": "2.0",
  "method": "notes.notes.delete",
  "params": {
    "items": [
      { "id": "1920438291738" },
      { "id": "1920438291739" }
    ]
  },
  "id": 7
}

Response

{
  "jsonrpc": "2.0",
  "result": {
    "affected": 2,
    "items": [
      { "id": "1920438291738" },
      { "id": "1920438291739" }
    ]
  },
  "id": 7
}