API reference

Naute REST API

Stable JSON over HTTPS for server-side automation and integrations. All endpoints live under /api/v1/*, return JSON, and authenticate with a Bearer token.

Quick start

A versioned HTTP API. Send a request with any HTTP client and a Bearer token.

curl https://app.naute.ai/api/v1/notes \
  -H "Authorization: Bearer YOUR_API_KEY"

Base URL: https://app.naute.ai.

Generate an API key in Settings after signing in.

For SDK generation, the machine-readable spec lives at /api/v1/openapi.json — point OpenAPI Generator (or similar) at it.

Authentication

All endpoints under /api/v1/* require a Bearer token in the Authorization header.

Authorization: Bearer ak_live_...

The only exception is attachment downloads, which also accept the token as a ?token= query parameter (handy for embedding signed image URLs in HTML).

Tokens are scoped to a single user. Lost or compromised keys can be revoked from your settings page.

Errors

Errors return a non-2xx status with a JSON body.

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Note not found",
    "request_id": "req_01J..."
  }
}

Common status codes

400 Bad Request
The request body or parameters failed validation. Check the message field.
401 Unauthorized
Missing, invalid, or expired token.
404 Not Found
The resource doesn't exist or has been deleted.
500 Internal Server Error
An unexpected error. Include the request_id when reporting.

Pagination

List endpoints accept limit and offset query parameters where applicable. Defaults: limit=20 for search, limit=50 for versions. Response is a flat array — total count is not returned.

For incremental sync of large note sets, prefer the structured search endpoint with date filters over paginated /notes calls.

Health & status

GET /api/v1/health

Public health check. No auth required. Returns server version, uptime, and attachment storage diagnostics.

Response

{
  "status": "ok",
  "version": "0.3.16",
  "uptime_seconds": 4827,
  "release_version": "0.3.16",
  "backend_version": "0.3.16",
  "commit_sha": "3a9aa20",
  "build_id": "rw-2026-04-23",
  "attachment_storage": {
    "path": "/data/attachments",
    "writable": true,
    "capacity_known": true,
    "available_bytes": 4294967296,
    "total_bytes": 5368709120,
    "used_bytes": 1073741824,
    "write_failure_count": 0,
    "last_write_error": null,
    "last_write_error_at": null
  }
}

Example

curl https://app.naute.ai/api/v1/health
GET /api/v1/status

Knowledge-base statistics for the authenticated user.

Response

{
  "note_count": 1248,
  "tag_count": 87,
  "link_count": 542,
  "attachment_count": 96
}

Notes

Notes are the primary resource. They have a title, body (markdown), folder (path string with slashes), and tags. Soft-deleted notes can be restored.

Image references in note bodies must point to Naute attachments. Remote http/https Markdown or HTML image URLs are rejected by default; set import_remote_images: true on create, update, append, or prepend writes to download each image, store it as an attachment, and rewrite the body to attachments/<id>.<ext>. The importer follows at most three redirects, requires an image/* response, blocks localhost/private-network hosts, and caps each remote image at 5 MB.

GET /api/v1/notes

List all non-deleted notes for the authenticated user. Results are not paginated; consider filtering by folder for large workspaces.

Query parameters

folder string optional
Exact folder name or glob pattern with * (single segment) or ** (any depth). Examples: projects/*, archive/**.

Response

[
  {
    "id": "note_abc123",
    "title": "Q3 Planning",
    "body": "# Goals\n\n...",
    "folder": "projects/2026",
    "tags": ["work", "priority"],
    "status": null,
    "category": null,
    "created_at": "2026-04-10T17:32:14Z",
    "updated_at": "2026-04-22T09:14:01Z"
  }
]

Example

curl 'https://app.naute.ai/api/v1/notes?folder=projects/*' \
  -H "Authorization: Bearer $NAUTE_TOKEN"
POST /api/v1/notes

Create a new note. Returns the created note with its server-assigned ID and timestamps.

Request body

title string required
Note title. Plain text.
body string optional
Markdown body. Defaults to empty.
folder string optional
Folder path with slashes. Defaults to root. Returns 400 if the path is invalid.
tags string[] optional
Tag names to attach. Tags are auto-created if they don't exist.
import_remote_images boolean optional
When true, imports remote http/https Markdown or HTML image URLs as attachments before saving. Default: false.

Response

Same shape as GET /notes/{id}.

Example

curl -X POST https://app.naute.ai/api/v1/notes \
  -H "Authorization: Bearer $NAUTE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Standup notes",
    "body": "# Today\n- ship docs\n- review PRs",
    "folder": "meetings",
    "tags": ["standup"],
    "import_remote_images": false
  }'
GET /api/v1/notes/{id}

Fetch a single note by ID, including the full body.

Path parameters

id string required
Note UUID.

Errors

404 if the note is missing or has been soft-deleted (use POST /restore to recover).

PUT /api/v1/notes/{id}

Update a note. title and body are required and replace the existing values. Pass folder or tags to change them; omit to leave unchanged.

Request body

title string required
New title. Replaces the existing one.
body string required
New markdown body. Replaces the existing one.
folder string optional
Move the note to a new folder.
tags string[] optional
Replace the tag set. Pass [] to clear all tags.
source_type string optional
Provenance hint. Accepted values: "ai"; anything else is recorded as "editor".
session_id string optional
Client-generated session identifier, used to coalesce versions across rapid edits.
author_device_name string optional
Human-friendly device label for the version history (e.g. "My laptop").
import_remote_images boolean optional
When true, imports remote http/https Markdown or HTML image URLs as attachments before saving. Default: false.
POST /api/v1/notes/{id}/append

Append markdown to the end of a note. Returns the updated note.

Request body

content string required
Markdown to append.
import_remote_images boolean optional
When true, imports remote http/https Markdown or HTML image URLs in content as attachments before appending. Default: false.
POST /api/v1/notes/{id}/prepend

Prepend markdown to the start of a note, after YAML frontmatter when present. Returns the updated note.

Request body

content string required
Markdown to prepend.
import_remote_images boolean optional
When true, imports remote http/https Markdown or HTML image URLs in content as attachments before prepending. Default: false.
DELETE /api/v1/notes/{id}

Soft-delete a note. The note is hidden from list and get endpoints but can be restored.

Response

{ "deleted": true }
POST /api/v1/notes/{id}/restore

Restore a soft-deleted note. Returns the restored note. 404 if the note is not in the trash.

Tags

Tags are simple labels with a name and slug. The system maintains a few built-in tags (e.g. system, hidden) which cannot be deleted or renamed.

GET /api/v1/tags

List all user-defined tags. System tags are excluded.

Response

[
  {
    "id": "tag_xyz",
    "name": "priority",
    "slug": "priority",
    "parent_id": null,
    "system": false,
    "hidden": false,
    "created_at": "2026-01-12T08:00:00Z",
    "updated_at": "2026-04-22T11:21:33Z"
  }
]
POST /api/v1/tags

Create a new tag. Returns 400 if a tag with the same name already exists — use /tags/ensure for idempotent creation.

Request body

name string required
Tag name. Cannot be empty.
POST /api/v1/tags/ensure

Get or create a tag by name. Idempotent — returns the existing tag if one matches, otherwise creates and returns it.

PUT /api/v1/tags/{id}

Update a tag's name. Does not update notes that use this tag — use /rename for that.

POST /api/v1/tags/{id}/rename

Rename a tag and update every note that uses it. Returns the renamed tag plus the IDs of affected notes.

Request body

new_name string required
The new tag name.

Response

{
  "tag": { "id": "tag_xyz", "name": "urgent", ... },
  "affected_note_ids": ["note_a", "note_b"]
}
POST /api/v1/tags/merge

Merge one tag into another. Notes tagged with source_id become tagged with target_id; the source tag is deleted.

Request body

source_id string required
The tag to absorb (will be deleted).
target_id string required
The tag to merge into (kept).
DELETE /api/v1/tags/{id}

Delete the tag definition only. Notes that reference this tag keep their tag references — use /global to remove from notes too.

DELETE /api/v1/tags/{id}/global

Delete the tag everywhere — both the definition and every note reference. Returns the IDs of affected notes.

Attachments

Files attached to notes — typically images and PDFs. Uploaded via multipart, downloaded with the same Bearer token (or a query-string token for embedding).

To render an attachment image in a note body, reference it with Markdown such as ![alt](attachments/<attachment-id>.<ext>). Programmatic note writes reject remote image URLs unless the write explicitly imports them with import_remote_images.

Max file size: 50 MB.

GET /api/v1/notes/{note_id}/attachments

List attachments on a note.

Response

[
  {
    "id": "att_xyz",
    "note_id": "note_abc",
    "filename": "diagram.png",
    "mime_type": "image/png",
    "file_size_bytes": 184320,
    "stored_path": "attachments/att_xyz.png",
    "origin_id": null,
    "created_at": "2026-04-15T12:14:09Z"
  }
]
POST /api/v1/notes/{note_id}/attachments

Upload a file attachment. multipart/form-data with a file part. Returns the created attachment.

Form fields

file file required
The file to upload. Max 50 MB.
origin_id string optional
External identifier for idempotent uploads (e.g. a hash of the source).

Example

curl -X POST https://app.naute.ai/api/v1/notes/note_abc/attachments \
  -H "Authorization: Bearer $NAUTE_TOKEN" \
  -F file=@./diagram.png
GET /api/v1/attachments/{id}

Download an attachment. Returns the raw file with Content-Disposition: inline. Auth via header or a ?token= query parameter (handy for embedding signed image URLs).

DELETE /api/v1/attachments/{id}

Delete an attachment. The file is removed from storage and the database row is dropped.

Versions

Every save creates a version. Version history is kept indefinitely and labels each version with its source_type — useful for distinguishing AI edits from manual ones.

GET /api/v1/notes/{id}/versions

List version metadata for a note. Returns lightweight summaries; use the version-detail endpoint to fetch the actual content.

Query parameters

limit integer optional
Max versions to return. Default 50.
offset integer optional
Skip the first N. Default 0.

Response

[
  {
    "version": 12,
    "source_type": "ai",
    "edit_source": "claude-sonnet-4-6",
    "created_at": "2026-04-22T14:11:02Z",
    "byte_size": 2148,
    "session_id": "sess_abc",
    "name": null,
    "author_device_id": null,
    "author_device_name": "Claude Desktop"
  }
]
GET /api/v1/notes/{id}/versions/{version}

Fetch a specific version, including the full body and the attachment IDs that were part of it.

Response

{
  "note_id": "note_abc",
  "version": 12,
  "title": "Q3 Planning",
  "body": "# Goals\n\n...",
  "content_hash": "sha256:...",
  "source_type": "ai",
  "edit_source": "claude-sonnet-4-6",
  "created_at": "2026-04-22T14:11:02Z",
  "session_id": "sess_abc",
  "name": null,
  "author_device_id": null,
  "author_device_name": "Claude Desktop",
  "attachment_ids": ["att_xyz"]
}