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 (), checklists (- [ ] …) |
Warning: When saving a note, always update both
enc_titleandenc_previewalongsideenc_content. Theenc_previewmust be a plain-text excerpt stripped of all Markdown formatting (~200 characters). Clients that rely on list view will display stale data ifenc_previewis 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
}