Skip to content

Notes

Base path: /api/v1/notes

POST /notes

Body:

FieldTypeRequiredDefaultDescription
titlestringNonullNote title. Can be auto-generated from content
contentstringYesNote body
content_formatstringNo"markdown"markdown, html, or plain
tagsstring[]No[]
pinnedbooleanNofalse
custom_fieldsobjectNonullArbitrary key-value data

Response: 201 Created with the full note object.

WebSocket event: note.created

{
"title": "Meeting notes",
"content": "1. Budget review\n2. Q2 planning",
"tags": ["work", "meetings"]
}

GET /notes

Query parameters:

ParameterTypeDefaultDescription
limitinteger20
offsetinteger0
sortstringupdated_atValid: created_at, updated_at, title
orderstringdescasc or desc
searchstringFull-text search on title and content
tagstringFilter by exact tag. Repeatable: ?tag=a&tag=b (AND)
pinnedbooleanFilter pinned notes
archivedbooleanFilter archived notes. Default: excludes archived
sourcestringFilter by origin: local, google_keep, etc.
include_deletedbooleanfalseInclude soft-deleted notes
only_deletedbooleanfalseOnly soft-deleted notes (trash view)

Response: 200 OK with list envelope.

Supports ?format=compact for token-optimized output.

GET /notes/:id

Response: 200 OK with single record envelope.

Returns 404 NOT_FOUND if the note doesn’t exist or is soft-deleted (unless ?include_deleted=true).

PATCH /notes/:id

Send only the fields to update.

Updatable fields: title, content, content_format, tags, pinned, archived, custom_fields

Response: 200 OK with the full updated note.

WebSocket event: note.updated

PATCH /notes/:id/custom

Incremental update via shallow merge.

Body: key-value pairs to merge.

  • Existing keys are preserved
  • New keys are added
  • Keys with null value are removed
{
"category": "blog",
"priority": null
}

If the note had {"priority": "high"}, the result is {"category": "blog"}.

Response: 200 OK with the full note including updated custom_fields.

WebSocket event: note.updated

POST /notes/:id/archive — sets archived: true

POST /notes/:id/unarchive — sets archived: false

Response: 200 OK

WebSocket event: note.updated

DELETE /notes/:id — soft delete (sets deleted_at)

DELETE /notes/:id?permanent=true — permanent delete (irreversible)

See Soft Deletes for details on delete behavior and restoration.

WebSocket event: note.deleted

POST /notes/:id/restore — clears deleted_at, note reappears in listings.

WebSocket event: note.restored