Grimoire API Documentation

August 3, 2026 ยท View on GitHub

Auto-generated from daemon/src/api/contract.ts. Do not edit by hand.

Contract

  • Base URL: http://127.0.0.1:3210
  • Machine-readable contract: docs/api-contract.json
  • OpenAPI output: docs/openapi.json
  • Regenerate: npm run docs:api
  • Drift check: npm run docs:api:check
  • OpenAPI-only commands: npm run docs:openapi and npm run docs:openapi:check

Authentication

The daemon is intended to bind to localhost. The first-party loopback browser app uses the local origin boundary and does not need to send an API token.

Local integration surfaces such as /mcp and /capture require a managed bearer token. Create one with POST /integration-tokens, store the returned token immediately, and send it as Authorization: Bearer <token>. Regular REST routes remain tokenless for the first-party app, but if a client presents an Authorization header it must be a valid integration token. List responses only include redacted token prefixes. Missing required tokens, invalid tokens, rotated tokens, or revoked tokens return 401 with application/problem+json and a WWW-Authenticate bearer challenge.

Browser Origin And CORS

Grimoire keeps browser access loopback-only. The daemon trusts the first-party app from http://127.0.0.1:3210, http://localhost:3210, and configured loopback development origins. Requests without an Origin header are treated as non-browser local client traffic and do not receive CORS headers.

Configure additional local browser clients with CORS_ORIGINS as a comma-separated list of loopback origins:

CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173,http://localhost:4321 littleimpd

Only full http or https origins are accepted, including scheme, host, and any port used by the client. Non-loopback origins are ignored even when configured, unsafe browser writes from rejected origins return 403, and rejected preflight requests return 403 without reflecting Access-Control-Allow-Origin. Protected local capture clients must use loopback origins and a managed integration bearer token.

Response Conventions

  • Most JSON endpoints return { "data": ... } envelopes.
  • Paginated endpoints include a pagination object with total, limit, offset, and has_more.
  • Newer route validation errors use application/problem+json; some backup/export routes still return { "error": string }.

OpenAPI Output

docs/openapi.json is generated from the same daemon-owned contract for local client tooling that expects an OpenAPI 3.0 document.

Limitations:

  • Hono ALL routes are represented by the primary client method POST with x-grimoire-source-method: "ALL".
  • Mixed content responses such as JSON/CSV exports share the closest generated schema; CSV, media, and SSE clients should still use the documented content type.
  • First-party REST routes remain local-origin routes. The OpenAPI bearer scheme documents managed local integration tokens, and MCP marks that scheme as required.

Endpoints

System

GET /health

Return daemon health, version, uptime, and queue size.

Responses:

StatusContent typeSchemaDescription
200application/jsonHealthResponseDaemon health

GET /diagnostics

Return a redacted local diagnostics bundle for support.

Diagnostics are generated locally and omit API keys, URL credentials, query strings, PIN hashes, S3 credentials, and backup passwords.

Responses:

StatusContent typeSchemaDescription
200application/jsonDiagnosticsResponseRedacted diagnostics

Examples:

Generate diagnostics

Request:

curl http://127.0.0.1:3210/diagnostics

Updates

GET /updates/check

Check a GitHub Releases-compatible source for a newer Grimoire release.

Query parameters:

FieldTypeRequiredDescription
channel"stable" | "beta"noUpdate channel to check; defaults from the current package version
sourcestringnoPublic GitHub Releases-compatible JSON endpoint; private and loopback hosts are rejected

Responses:

StatusContent typeSchemaDescription
200application/jsonUpdateCheckResponseUpdate check result
422application/problem+jsonProblemDetailsInvalid channel or source URL
502application/problem+jsonProblemDetailsUpdate source could not be read or returned an invalid response

Examples:

Check for updates

Request:

curl 'http://127.0.0.1:3210/updates/check?channel=stable'

Bookmarks

POST /bookmarks

Save a URL and enqueue the ingestion pipeline.

Request body:

  • Content type: application/json
  • Schema: BookmarkCreateRequest
FieldTypeRequiredDescription
urlstringyesHTTP or HTTPS URL to save
titlestringnoOptional title override

Responses:

StatusContent typeSchemaDescription
200application/jsonBookmarkResponseExisting active bookmark returned idempotently
201application/jsonBookmarkResponseBookmark created
400application/problem+jsonProblemDetailsMalformed JSON
409application/problem+jsonProblemDetailsURL already exists in trash or archive
422application/problem+jsonProblemDetailsInvalid URL or missing url field

Examples:

Save a bookmark

Request:

curl -X POST http://127.0.0.1:3210/bookmarks \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/rag-vector-search","title":"RAG Vector Search Notes"}'

Response:

HTTP/1.1 201 Created
Content-Type: application/json

{
  "data": {
    "id": "bm_123",
    "url": "https://example.com/rag-vector-search",
    "domain": "example.com",
    "title": "RAG Vector Search Notes",
    "description": null,
    "status": "saved",
    "category_id": null,
    "favicon_url": null,
    "screenshot_url": null,
    "is_pinned": 0,
    "is_archived": 0,
    "is_trashed": 0,
    "trashed_at": null,
    "read_later": 0,
    "read_at": null,
    "opened_count": 0,
    "last_opened_at": null,
    "notes": null,
    "created_at": "2026-06-01T09:30:00.000Z",
    "updated_at": "2026-06-01T09:30:00.000Z",
    "tags": []
  }
}

Reject an invalid bookmark URL

Request:

curl -X POST http://127.0.0.1:3210/bookmarks \
  -H "Content-Type: application/json" \
  -d '{"url":"http://127.0.0.1/private"}'

Response:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json

{
  "type": "https://littleimp.app/problems/unprocessable-entity",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "Invalid URL - must be http or https"
}

GET /bookmarks

List active or archived bookmarks with filters and pagination.

Query parameters:

FieldTypeRequiredDescription
tagstringnoFilter by tag name
domainstringnoFilter by exact domain
category_idstringnoFilter by exact category ID; takes precedence over category
categorystringnoFilter by category name
date_fromstringnoInclusive ISO date or date-time lower bound
date_tostringnoInclusive ISO date or date-time upper bound
read_later"true" | "false" | "1" | "0"noFilter by read-later state; accepts boolean strings or numeric flags
read_state"read" | "unread"noFilter by read state
is_pinned"true" | "false" | "1" | "0"noFilter by pinned/starred state; accepts boolean strings or numeric flags
opened_count_minintegernoFilter to bookmarks opened at least this many times
opened_count_maxintegernoFilter to bookmarks opened no more than this many times
last_opened_fromstringnoInclusive ISO date or date-time lower bound for last opened time
last_opened_tostringnoInclusive ISO date or date-time upper bound for last opened time
sort"created_at" | "updated_at" | "title" | "domain" | "opened_count" | "last_opened_at"noSort key applied before pagination
direction"asc" | "desc"noSort direction; requires sort and defaults to desc when omitted
limitintegernoMaximum number of results to return
offsetintegernoNumber of results to skip
archived"true" | "false"noWhen true, return archived bookmarks

Responses:

StatusContent typeSchemaDescription
200application/jsonBookmarkListResponseBookmark page

Examples:

List filtered bookmarks

Request:

curl "http://127.0.0.1:3210/bookmarks?tag=rag&read_state=unread&is_pinned=true&opened_count_min=1&sort=opened_count&direction=desc&limit=10&offset=0"

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": [
    {
      "id": "bm_123",
      "url": "https://example.com/rag-vector-search",
      "domain": "example.com",
      "title": "RAG Vector Search Notes",
      "description": "Practical notes about vector search for retrieval augmented generation.",
      "status": "indexed",
      "category_id": "cat_ai",
      "favicon_url": "/media/bookmarks/bm_123/favicon",
      "screenshot_url": "/media/bookmarks/bm_123/screenshot",
      "is_pinned": 0,
      "is_archived": 0,
      "is_trashed": 0,
      "trashed_at": null,
      "read_later": 1,
      "read_at": null,
      "opened_count": 2,
      "last_opened_at": "2026-06-01T08:45:00.000Z",
      "notes": "Compare chunking guidance with local notes.",
      "created_at": "2026-06-01T09:30:00.000Z",
      "updated_at": "2026-06-01T09:30:00.000Z",
      "tags": [
        "rag",
        "search"
      ]
    }
  ],
  "pagination": {
    "total": 1,
    "limit": 10,
    "offset": 0,
    "has_more": false
  }
}

GET /bookmarks/aggregates

Return page-independent active-library aggregate counts.

Counts categories, tags, domains, read state, pinned/starred state, and read-later state for active bookmarks under the same approved library filter context as bookmark listing. Pagination and sorting are intentionally ignored.

Query parameters:

FieldTypeRequiredDescription
tagstringnoFilter by tag name
domainstringnoFilter by exact domain
category_idstringnoFilter by exact category ID; takes precedence over category
categorystringnoFilter by category name
date_fromstringnoInclusive ISO date or date-time lower bound
date_tostringnoInclusive ISO date or date-time upper bound
read_later"true" | "false" | "1" | "0"noFilter by read-later state; accepts boolean strings or numeric flags
read_state"read" | "unread"noFilter by read state
is_pinned"true" | "false" | "1" | "0"noFilter by pinned/starred state; accepts boolean strings or numeric flags
opened_count_minintegernoFilter to bookmarks opened at least this many times
opened_count_maxintegernoFilter to bookmarks opened no more than this many times
last_opened_fromstringnoInclusive ISO date or date-time lower bound for last opened time
last_opened_tostringnoInclusive ISO date or date-time upper bound for last opened time

Responses:

StatusContent typeSchemaDescription
200application/jsonBookmarkAggregatesResponseBookmark aggregate counts
422application/problem+jsonProblemDetailsInvalid aggregate filter

Examples:

Read library aggregate counts

Request:

curl "http://127.0.0.1:3210/bookmarks/aggregates?read_later=true&is_pinned=false"

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {
    "total": 12,
    "categories": [
      {
        "id": "cat_ai",
        "name": "AI Research",
        "count": 7
      },
      {
        "id": "cat_docs",
        "name": "Documentation",
        "count": 5
      }
    ],
    "tags": [
      {
        "name": "rag",
        "count": 6
      },
      {
        "name": "typescript",
        "count": 4
      }
    ],
    "domains": [
      {
        "domain": "example.com",
        "count": 8
      },
      {
        "domain": "docs.example.com",
        "count": 4
      }
    ],
    "read": {
      "read": 3,
      "unread": 9
    },
    "pinned": {
      "pinned": 2,
      "unpinned": 10
    },
    "read_later": {
      "yes": 5,
      "no": 7
    }
  }
}

GET /bookmarks/:id

Get one bookmark with extracted content.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Responses:

StatusContent typeSchemaDescription
200application/jsonBookmarkDetailResponseBookmark detail
404application/problem+jsonProblemDetailsBookmark not found

Examples:

Read bookmark detail

Request:

curl http://127.0.0.1:3210/bookmarks/bm_123

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {
    "id": "bm_123",
    "url": "https://example.com/rag-vector-search",
    "domain": "example.com",
    "title": "RAG Vector Search Notes",
    "description": "Practical notes about vector search for retrieval augmented generation.",
    "status": "indexed",
    "category_id": "cat_ai",
    "favicon_url": "/media/bookmarks/bm_123/favicon",
    "screenshot_url": "/media/bookmarks/bm_123/screenshot",
    "is_pinned": 0,
    "is_archived": 0,
    "is_trashed": 0,
    "trashed_at": null,
    "read_later": 1,
    "read_at": null,
    "opened_count": 2,
    "last_opened_at": "2026-06-01T08:45:00.000Z",
    "notes": "Compare chunking guidance with local notes.",
    "created_at": "2026-06-01T09:30:00.000Z",
    "updated_at": "2026-06-01T09:30:00.000Z",
    "tags": [
      "rag",
      "search"
    ],
    "content": {
      "bookmark_id": "bm_123",
      "raw_html": null,
      "markdown": "## RAG Vector Search\n\nUse hybrid retrieval when exact terms matter.",
      "summary": "A practical walkthrough of hybrid retrieval for RAG systems.",
      "author": "Example Author",
      "published_at": "2026-05-28T12:00:00.000Z",
      "word_count": 1240,
      "language": "en",
      "extracted_at": "2026-06-01T09:30:00.000Z"
    },
    "media": {
      "favicon": null,
      "screenshot": null,
      "images": []
    }
  }
}

GET /media/bookmarks/:bookmarkId/:mediaId

Serve one cached local bookmark media file.

Media files are served from the local cache only. Missing files, trashed bookmarks, and unknown media IDs return 404.

Path parameters:

FieldTypeRequiredDescription
bookmarkIdstringyesBookmark ID
mediaIdstringyesMedia cache record ID

Responses:

StatusContent typeSchemaDescription
200image/*-Cached non-SVG image media file
404application/problem+jsonProblemDetailsMedia not found

PUT /bookmarks/:id

Patch bookmark fields, tags, archive state, read state, and notes.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Request body:

  • Content type: application/json
  • Schema: BookmarkUpdateRequest
FieldTypeRequiredDescription
titlestring | nullnoNew title, or null to clear
category_idstring | nullnoCategory ID, or null to clear
tagsarraynoReplacement tag names
is_pinnedintegernoPinned flag, 0 or 1; maps Grimoire starred/favorite state
read_laterintegernoRead-later flag, 0 or 1
is_archivedintegernoArchived flag, 0 or 1
read_atstring | nullnoISO 8601 date-time, or null to mark unread
notesstring | nullnoPersonal notes, or null to clear

Responses:

StatusContent typeSchemaDescription
200application/jsonBookmarkResponseUpdated bookmark
400application/problem+jsonProblemDetailsMalformed JSON
404application/problem+jsonProblemDetailsBookmark not found
422application/problem+jsonProblemDetailsInvalid patch field

Examples:

Update bookmark metadata

Request:

curl -X PUT http://127.0.0.1:3210/bookmarks/bm_123 \
  -H "Content-Type: application/json" \
  -d '{"tags":["rag","retrieval"],"read_later":1,"notes":"Compare with local chunking notes."}'

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {
    "id": "bm_123",
    "url": "https://example.com/rag-vector-search",
    "domain": "example.com",
    "title": "RAG Vector Search Notes",
    "description": "Practical notes about vector search for retrieval augmented generation.",
    "status": "indexed",
    "category_id": "cat_ai",
    "favicon_url": "/media/bookmarks/bm_123/favicon",
    "screenshot_url": "/media/bookmarks/bm_123/screenshot",
    "is_pinned": 0,
    "is_archived": 0,
    "is_trashed": 0,
    "trashed_at": null,
    "read_later": 1,
    "read_at": null,
    "opened_count": 2,
    "last_opened_at": "2026-06-01T08:45:00.000Z",
    "notes": "Compare with local chunking notes.",
    "created_at": "2026-06-01T09:30:00.000Z",
    "updated_at": "2026-06-01T09:30:00.000Z",
    "tags": [
      "rag",
      "retrieval"
    ]
  }
}

POST /bookmarks/:id/open

Record a user-triggered external open for a bookmark.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Responses:

StatusContent typeSchemaDescription
200application/jsonBookmarkResponseUpdated bookmark open metrics
404application/problem+jsonProblemDetailsBookmark not found

DELETE /bookmarks/:id

Soft-delete a bookmark by moving it to trash.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Responses:

StatusContent typeSchemaDescription
204--Bookmark moved to trash
404application/problem+jsonProblemDetailsBookmark not found

POST /bookmarks/:id/restore

Restore a trashed bookmark.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Responses:

StatusContent typeSchemaDescription
200application/jsonBookmarkResponseRestored bookmark
404application/problem+jsonProblemDetailsBookmark not found or not in trash
500application/problem+jsonProblemDetailsRestore succeeded but bookmark could not be fetched

DELETE /bookmarks/:id/permanent

Permanently delete a trashed bookmark.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Responses:

StatusContent typeSchemaDescription
204--Bookmark permanently deleted
404application/problem+jsonProblemDetailsBookmark not found or not in trash

GET /trash

List trashed bookmarks.

Responses:

StatusContent typeSchemaDescription
200application/jsonBookmarkArrayResponseTrashed bookmarks

GET /bookmarks/:id/related

List semantically related bookmarks.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Query parameters:

FieldTypeRequiredDescription
limitintegernoMaximum related bookmarks

Responses:

StatusContent typeSchemaDescription
200application/jsonRelatedBookmarksResponseRelated bookmarks
404application/problem+jsonProblemDetailsBookmark not found
422application/problem+jsonProblemDetailsEmbedding provider is not configured

Examples:

List related bookmarks

Request:

curl "http://127.0.0.1:3210/bookmarks/bm_123/related?limit=5"

GET /bookmarks/:id/status

Get latest pipeline job and failure status for a bookmark.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Responses:

StatusContent typeSchemaDescription
200application/jsonBookmarkPipelineStatusResponseBookmark pipeline status
404application/problem+jsonProblemDetailsBookmark not found

POST /bookmarks/:id/failure/dismiss

Dismiss the current non-blocking pipeline failure for a bookmark.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Responses:

StatusContent typeSchemaDescription
204--Pipeline failure dismissed
404application/problem+jsonProblemDetailsBookmark not found
409application/problem+jsonProblemDetailsBlocking pipeline failure cannot be dismissed

Reprocess

POST /bookmarks/:id/retry

Retry pipeline work for one bookmark.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Responses:

StatusContent typeSchemaDescription
202application/jsonReprocessBatchResponseSelected bookmark retry accepted
404application/problem+jsonProblemDetailsBookmark not found

POST /bookmarks/reprocess

Enqueue durable reprocess or re-embed jobs for existing bookmarks.

Request body:

  • Content type: application/json
  • Schema: ReprocessRequest
FieldTypeRequiredDescription
mode"selected" | "failed_only" | "all" | "embeddings_only"yesReprocess mode
bookmark_idstringnoBookmark ID required when mode is selected
replace_ai_fieldsbooleannoWhen true, allow reprocessing to update AI-derived title, category, and tags; manual notes are never overwritten

Responses:

StatusContent typeSchemaDescription
202application/jsonReprocessBatchResponseReprocess batch accepted
400application/problem+jsonProblemDetailsMalformed JSON
404application/problem+jsonProblemDetailsSelected bookmark not found
422application/problem+jsonProblemDetailsInvalid reprocess request

Examples:

Retry failed pipeline work

Request:

curl -X POST http://127.0.0.1:3210/bookmarks/reprocess \
  -H "Content-Type: application/json" \
  -d '{"mode":"failed_only"}'

GET /reprocess/:batchId

Return progress counts for a durable reprocess batch.

Path parameters:

FieldTypeRequiredDescription
batchIdstringyesbatchId path parameter

Responses:

StatusContent typeSchemaDescription
200application/jsonReprocessBatchStatusResponseReprocess batch status
404application/problem+jsonProblemDetailsReprocess batch not found

Search bookmarks by keyword, semantic, or hybrid mode.

Query parameters:

FieldTypeRequiredDescription
qstringnoSearch query
mode"keyword" | "semantic" | "hybrid"noSearch mode
tagstringnoFilter by tag name
domainstringnoFilter by exact domain
category_idstringnoFilter by exact category ID; takes precedence over category
categorystringnoFilter by category name
date_fromstringnoInclusive ISO date or date-time lower bound
date_tostringnoInclusive ISO date or date-time upper bound
read_later"true" | "false" | "1" | "0"noFilter by read-later state; accepts boolean strings or numeric flags
read_state"read" | "unread"noFilter by read state
is_pinned"true" | "false" | "1" | "0"noFilter by pinned/starred state; accepts boolean strings or numeric flags
opened_count_minintegernoFilter to bookmarks opened at least this many times
opened_count_maxintegernoFilter to bookmarks opened no more than this many times
last_opened_fromstringnoInclusive ISO date or date-time lower bound for last opened time
last_opened_tostringnoInclusive ISO date or date-time upper bound for last opened time
sort"created_at" | "updated_at" | "title" | "domain" | "opened_count" | "last_opened_at"noSort key applied before pagination
direction"asc" | "desc"noSort direction; requires sort and defaults to desc when omitted
limitintegernoMaximum number of results to return
offsetintegernoNumber of results to skip

Responses:

StatusContent typeSchemaDescription
200application/jsonSearchResponseSearch page
400application/problem+jsonProblemDetailsInvalid FTS query syntax
422application/problem+jsonProblemDetailsInvalid mode or missing embedding configuration

Examples:

Hybrid search with pagination

Request:

curl "http://127.0.0.1:3210/search?q=vector%20search&mode=hybrid&tag=rag&read_state=read&last_opened_from=2026-06-01&limit=10&offset=0"

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": [
    {
      "id": "bm_123",
      "url": "https://example.com/rag-vector-search",
      "domain": "example.com",
      "title": "RAG Vector Search Notes",
      "description": "Practical notes about vector search for retrieval augmented generation.",
      "status": "indexed",
      "category_id": "cat_ai",
      "favicon_url": "/media/bookmarks/bm_123/favicon",
      "screenshot_url": "/media/bookmarks/bm_123/screenshot",
      "is_pinned": 0,
      "is_archived": 0,
      "is_trashed": 0,
      "trashed_at": null,
      "read_later": 1,
      "read_at": null,
      "opened_count": 2,
      "last_opened_at": "2026-06-01T08:45:00.000Z",
      "notes": "Compare chunking guidance with local notes.",
      "created_at": "2026-06-01T09:30:00.000Z",
      "updated_at": "2026-06-01T09:30:00.000Z",
      "tags": [
        "rag",
        "search"
      ],
      "snippet": "Use hybrid retrieval when exact vector search terms matter.",
      "rank": 0.93
    }
  ],
  "pagination": {
    "total": 1,
    "limit": 10,
    "offset": 0,
    "has_more": false
  },
  "meta": {
    "mode": "hybrid"
  }
}

Categories

GET /categories

List categories as a tree with bookmark counts.

Responses:

StatusContent typeSchemaDescription
200application/jsonCategoryTreeResponseCategory tree

Examples:

List category tree

Request:

curl http://127.0.0.1:3210/categories

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": [
    {
      "id": "cat_ai",
      "name": "AI Research",
      "parent_id": null,
      "color": "#2563eb",
      "icon": "brain",
      "description": "Papers, implementation notes, and reference material for AI work.",
      "slug": "ai-research",
      "is_archived": 0,
      "is_public": 0,
      "created_at": "2026-06-01T09:30:00.000Z",
      "updated_at": "2026-06-01T09:30:00.000Z",
      "bookmark_count": 1,
      "children": []
    }
  ]
}

POST /categories

Create a category.

Request body:

  • Content type: application/json
  • Schema: CategoryRequest
FieldTypeRequiredDescription
namestringyesCategory name
parent_idstring | nullnoParent category ID
colorstring | nullnoOptional category hex color
iconstring | nullnoOptional lowercase icon token
descriptionstring | nullnoOptional category description
slugstring | nullnoOptional category slug
is_archived0 | 1noArchived metadata flag, 0 or 1
is_public0 | 1noPublic visibility metadata flag, 0 or 1; local metadata only and does not expose data

Responses:

StatusContent typeSchemaDescription
201application/jsonCategoryResponseCreated category
400application/problem+jsonProblemDetailsMalformed JSON
409application/problem+jsonProblemDetailsDuplicate category under parent
422application/problem+jsonProblemDetailsInvalid name or parent

Examples:

Create a category with metadata

Request:

curl -X POST http://127.0.0.1:3210/categories \
  -H "Content-Type: application/json" \
  -d '{"name":"AI Research","color":"#2563eb","icon":"brain","slug":"ai-research","description":"Papers, implementation notes, and reference material for AI work.","is_public":0}'

Response:

HTTP/1.1 201 Created
Content-Type: application/json

{
  "data": {
    "id": "cat_ai",
    "name": "AI Research",
    "parent_id": null,
    "color": "#2563eb",
    "icon": "brain",
    "description": "Papers, implementation notes, and reference material for AI work.",
    "slug": "ai-research",
    "is_archived": 0,
    "is_public": 0,
    "created_at": "2026-06-01T09:30:00.000Z",
    "updated_at": "2026-06-01T09:30:00.000Z"
  }
}

PUT /categories/:id

Rename or reparent a category.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Request body:

  • Content type: application/json
  • Schema: CategoryPatchRequest
FieldTypeRequiredDescription
namestringnoCategory name
parent_idstring | nullnoParent category ID
colorstring | nullnoOptional category hex color
iconstring | nullnoOptional lowercase icon token
descriptionstring | nullnoOptional category description
slugstring | nullnoOptional category slug
is_archived0 | 1noArchived metadata flag, 0 or 1
is_public0 | 1noPublic visibility metadata flag, 0 or 1; local metadata only and does not expose data

Responses:

StatusContent typeSchemaDescription
200application/jsonCategoryResponseUpdated category
400application/problem+jsonProblemDetailsMalformed JSON
404application/problem+jsonProblemDetailsCategory not found
409application/problem+jsonProblemDetailsDuplicate category under parent
422application/problem+jsonProblemDetailsInvalid patch or parent

DELETE /categories/:id

Delete a category.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Responses:

StatusContent typeSchemaDescription
204--Category deleted
404application/problem+jsonProblemDetailsCategory not found

Tags

GET /tags

List tags with bookmark counts.

Responses:

StatusContent typeSchemaDescription
200application/jsonTagListResponseTags

Examples:

List tags

Request:

curl http://127.0.0.1:3210/tags

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": [
    {
      "id": "tag_rag",
      "name": "rag",
      "created_at": "2026-06-01T09:30:00.000Z",
      "bookmark_count": 1
    }
  ]
}

POST /tags

Create a tag, idempotently returning an existing tag when present.

Request body:

  • Content type: application/json
  • Schema: TagRequest
FieldTypeRequiredDescription
namestringyesTag name, normalized to lowercase

Responses:

StatusContent typeSchemaDescription
200application/jsonTagResponseExisting tag
201application/jsonTagResponseCreated tag
400application/problem+jsonProblemDetailsMalformed JSON
422application/problem+jsonProblemDetailsInvalid tag name

Examples:

Create a tag

Request:

curl -X POST http://127.0.0.1:3210/tags \
  -H "Content-Type: application/json" \
  -d '{"name":"rag"}'

Response:

HTTP/1.1 201 Created
Content-Type: application/json

{
  "data": {
    "id": "tag_rag",
    "name": "rag",
    "created_at": "2026-06-01T09:30:00.000Z"
  }
}

PUT /tags/:id

Rename a tag without changing bookmark associations.

Duplicate target tag names are rejected with 409 rather than merged implicitly.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Request body:

  • Content type: application/json
  • Schema: TagRequest
FieldTypeRequiredDescription
namestringyesTag name, normalized to lowercase

Responses:

StatusContent typeSchemaDescription
200application/jsonTagResponseRenamed tag
400application/problem+jsonProblemDetailsMalformed JSON
404application/problem+jsonProblemDetailsTag not found
409application/problem+jsonProblemDetailsDuplicate tag name
422application/problem+jsonProblemDetailsInvalid tag name

DELETE /tags/:id

Delete a tag and detach it from bookmarks.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Responses:

StatusContent typeSchemaDescription
204--Tag deleted
404application/problem+jsonProblemDetailsTag not found

POST /bookmarks/:id/tags

Attach a tag to a bookmark.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Request body:

  • Content type: application/json
  • Schema: TagRequest
FieldTypeRequiredDescription
namestringyesTag name, normalized to lowercase

Responses:

StatusContent typeSchemaDescription
201application/jsonBookmarkResponseBookmark with attached tag
400application/problem+jsonProblemDetailsMalformed JSON
404application/problem+jsonProblemDetailsBookmark not found
422application/problem+jsonProblemDetailsInvalid tag name

DELETE /bookmarks/:id/tags/:tagId

Detach a tag from a bookmark.

Path parameters:

FieldTypeRequiredDescription
idstringyesBookmark ID
tagIdstringyesTag ID

Responses:

StatusContent typeSchemaDescription
204--Tag detached
404application/problem+jsonProblemDetailsBookmark, tag, or attachment not found

Domains

GET /domains

List domains with active bookmark counts.

Responses:

StatusContent typeSchemaDescription
200application/jsonDomainListResponseDomains
500application/problem+jsonProblemDetailsQuery failed

Import

POST /import/preview

Preview a Netscape HTML bookmark export without mutating library data.

Request body:

  • Content type: multipart/form-data
  • Multipart body with a file field plus optional duplicatePolicy JSON and remapping JSON fields.
  • Schema: object
FieldTypeRequiredDescription
filestringyesHTML bookmark export file
duplicatePolicystringnoOptional JSON duplicate policy
remappingstringnoOptional JSON ImportRemappingInput. Folder create mappings use sourcePath and targetPath; folder existing mappings use sourcePath and categoryId. Tag existing mappings use sourceTag and tagId; new/renamed mappings use sourceTag and targetName; skipped mappings use only sourceTag.

Responses:

StatusContent typeSchemaDescription
200application/jsonImportPreviewResponseImport preview
400application/problem+jsonProblemDetailsMultipart parsing failed
413application/problem+jsonProblemDetailsFile exceeds 10 MB
415application/problem+jsonProblemDetailsRequest is not multipart/form-data
422application/problem+jsonProblemDetailsMissing file, invalid bookmark export, or invalid duplicate policy

Examples:

Preview Netscape bookmarks

Request:

curl -X POST http://127.0.0.1:3210/import/preview \
  -F file=@bookmarks.html \
  -F 'duplicatePolicy={"active":"merge","archived":"restore_merge","trashed":"skip"}' \
  -F 'remapping={"folders":[{"sourcePath":["Research"],"action":"existing","categoryId":"cat_research"}],"tags":[{"sourceTag":"sqlite","action":"renamed","targetName":"database"}]}'

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {
    "duplicatePolicy": {
      "active": "merge",
      "archived": "restore_merge",
      "trashed": "skip"
    },
    "remapping": {
      "folders": [
        {
          "sourcePath": [
            "Research"
          ],
          "action": "existing",
          "targetCategoryId": "cat_research",
          "targetPath": [
            "Research"
          ],
          "status": "existing"
        }
      ],
      "tags": [
        {
          "sourceTag": "database",
          "action": "existing",
          "targetTagId": "tag_database",
          "targetName": "database",
          "status": "existing"
        },
        {
          "sourceTag": "sqlite",
          "action": "renamed",
          "targetTagId": "tag_database",
          "targetName": "database",
          "status": "existing"
        }
      ]
    },
    "summary": {
      "totalRows": 12,
      "importableRows": 10,
      "new": 7,
      "activeDuplicates": 1,
      "archivedDuplicates": 1,
      "trashedDuplicates": 1,
      "invalidUrls": 1,
      "privateUrls": 1,
      "created": 7,
      "merged": 1,
      "restored": 1,
      "skipped": 3
    },
    "folders": [
      [
        "Research"
      ],
      [
        "Research",
        "Databases"
      ]
    ],
    "tags": [
      "database",
      "sqlite"
    ],
    "warnings": [
      "Skipped private/internal URL: http://127.0.0.1/admin"
    ],
    "rows": [
      {
        "classification": "active_duplicate",
        "action": "merge",
        "url": "https://example.com/rag-vector-search",
        "title": "RAG Vector Search Notes",
        "notes": null,
        "tags": [
          "database"
        ],
        "targetTags": [
          "database"
        ],
        "folders": [
          "Research"
        ],
        "targetCategoryId": "cat_research",
        "targetCategoryPath": [
          "Research"
        ],
        "existingBookmarkId": "bm_123",
        "existingState": "active",
        "skipReason": null
      }
    ]
  }
}

POST /import

Import a Netscape HTML bookmark export.

Request body:

  • Content type: multipart/form-data
  • Multipart body with a file field plus optional duplicatePolicy JSON and remapping JSON fields.
  • Schema: object
FieldTypeRequiredDescription
filestringyesHTML bookmark export file
duplicatePolicystringnoOptional JSON duplicate policy
remappingstringnoOptional JSON ImportRemappingInput. Folder create mappings use sourcePath and targetPath; folder existing mappings use sourcePath and categoryId. Tag existing mappings use sourceTag and tagId; new/renamed mappings use sourceTag and targetName; skipped mappings use only sourceTag.

Responses:

StatusContent typeSchemaDescription
200application/jsonImportSummaryResponseImport accepted
400application/problem+jsonProblemDetailsMultipart parsing failed
413application/problem+jsonProblemDetailsFile exceeds 10 MB
415application/problem+jsonProblemDetailsRequest is not multipart/form-data
422application/problem+jsonProblemDetailsMissing file or invalid bookmark export

Examples:

Import Netscape bookmarks

Request:

curl -X POST http://127.0.0.1:3210/import \
  -F file=@bookmarks.html \
  -F 'remapping={"folders":[{"sourcePath":["Research"],"action":"existing","categoryId":"cat_research"}],"tags":[{"sourceTag":"sqlite","action":"renamed","targetName":"database"}]}'

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {
    "importId": "import_123",
    "total": 12,
    "folders": 4,
    "warnings": 1,
    "duplicatePolicy": {
      "active": "skip",
      "archived": "skip",
      "trashed": "skip"
    },
    "remapping": {
      "folders": [
        {
          "sourcePath": [
            "Research"
          ],
          "action": "existing",
          "targetCategoryId": "cat_research",
          "targetPath": [
            "Research"
          ],
          "status": "existing"
        }
      ],
      "tags": [
        {
          "sourceTag": "sqlite",
          "action": "renamed",
          "targetTagId": null,
          "targetName": "database",
          "status": "new"
        }
      ]
    },
    "progressUrl": "/import/import_123/progress"
  }
}

GET /import/:importId/progress

Stream import progress over Server-Sent Events.

Path parameters:

FieldTypeRequiredDescription
importIdstringyesimportId path parameter

Responses:

StatusContent typeSchemaDescription
200text/event-streamImportProgressEventSSE stream of progress events
404application/problem+jsonProblemDetailsImport ID not found

Settings

GET /settings

Read current settings with secrets redacted and runtime capabilities.

Responses:

StatusContent typeSchemaDescription
200application/jsonSettingsResponseSettings

PUT /settings

Deep-merge a settings patch into persisted settings.

Request body:

  • Content type: application/json
  • Schema: SettingsPatch
FieldTypeRequiredDescription
aiobjectno
ai.provider"openai" | "ollama" | "anthropic" | "openrouter" | "openai_compatible" | "deepseek" | "none"noLLM provider
ai.openaiobjectno
ai.openai.api_keystringnoOpenAI API key, empty string clears it
ai.openai.modelstringnoOpenAI chat model
ai.ollamaobjectno
ai.ollama.base_urlstringnoOllama base URL
ai.ollama.modelstringnoOllama model
ai.anthropicobjectno
ai.anthropic.api_keystringnoAnthropic API key, empty string clears it
ai.anthropic.base_urlstringnoAnthropic API base URL
ai.anthropic.modelstringnoAnthropic Messages API model
ai.openrouterobjectno
ai.openrouter.api_keystringnoOpenRouter API key, empty string clears it
ai.openrouter.base_urlstringnoOpenRouter OpenAI-compatible base URL
ai.openrouter.modelstringnoOpenRouter model slug
ai.openai_compatibleobjectno
ai.openai_compatible.api_keystringnoCustom OpenAI-compatible API key, empty string clears it
ai.openai_compatible.base_urlstringnoCustom OpenAI-compatible chat base URL
ai.openai_compatible.modelstringnoCustom OpenAI-compatible chat model
ai.deepseekobjectno
ai.deepseek.api_keystringnoDeepSeek API key, empty string clears it
ai.deepseek.base_urlstringnoDeepSeek OpenAI-compatible base URL
ai.deepseek.modelstringnoDeepSeek chat model
ai.embeddingsobjectno
ai.embeddings.provider"openai" | "ollama" | "openai_compatible"noEmbedding provider
ai.embeddings.modelstringnoEmbedding model
ai.embeddings.openai_compatibleobjectno
ai.embeddings.openai_compatible.api_keystringnoCustom OpenAI-compatible embedding API key, empty string clears it
ai.embeddings.openai_compatible.base_urlstringnoCustom OpenAI-compatible embeddings base URL
ai.embeddings.openai_compatible.modelstringnoCustom OpenAI-compatible embedding model
appobjectno
app.autostartbooleannoStart daemon automatically
app.theme"light" | "dark" | "system"noUI theme
app.lockobjectno
app.lock.enabledbooleannoWhether app lock is enabled
app.lock.pin_hashstringnoPIN hash, empty string clears it
backupobjectno
backup.localobjectno
backup.local.destination_pathstringnoAbsolute custom backup destination, or empty string for default
backup.scheduleobjectno
backup.schedule.enabledbooleannoEnable scheduled snapshots
backup.schedule.cronstringnoFive-part cron expression
backup.schedule.retention_countintegernoNumber of local snapshots to retain
backup.s3objectno
backup.s3.endpointstringnoS3-compatible endpoint URL, or empty string for AWS
backup.s3.bucketstringnoS3 bucket
backup.s3.access_keystringnoS3 access key
backup.s3.secret_keystringnoS3 secret key
backup.s3.regionstringnoS3 region
backup.s3.prefixstringnoObject key prefix

Responses:

StatusContent typeSchemaDescription
200application/jsonSettingsResponseUpdated settings
400application/problem+jsonProblemDetailsMalformed JSON
422application/problem+jsonProblemDetailsInvalid settings patch
500application/problem+jsonProblemDetailsSettings could not be persisted

POST /settings/test-ai

Test connectivity to the configured LLM provider.

Responses:

StatusContent typeSchemaDescription
200application/jsonConnectivityTestResponseConnectivity result

Backup

POST /backup

Create a local backup snapshot and optionally upload it to S3.

Request body:

  • Content type: application/json
  • Schema: BackupCreateRequest
FieldTypeRequiredDescription
skip_remotebooleannoWhen true, create only the local snapshot and skip S3 upload

Responses:

StatusContent typeSchemaDescription
201application/jsonBackupResultBackup created
400application/jsonLegacyErrorMalformed or non-object JSON body
409application/jsonLegacyErrorBackup or restore already in progress
422application/jsonLegacyErrorInvalid backup create request
500application/jsonLegacyErrorBackup creation failed

Examples:

Create a local backup

Request:

curl -X POST http://127.0.0.1:3210/backup \
  -H "Content-Type: application/json" \
  -d '{"skip_remote":true}'

Response:

HTTP/1.1 201 Created
Content-Type: application/json

{
  "path": "/Users/me/.local/share/littleimp/backups/2026-06-01T09-30-00-000Z",
  "size_bytes": 98304,
  "bookmark_count": 42,
  "created_at": "2026-06-01T09:30:00.000Z"
}

GET /backup/list

List local backups and optionally merge remote S3 backups.

Query parameters:

FieldTypeRequiredDescription
include_remote"true" | "false"noWhen true, include S3 backups

Responses:

StatusContent typeSchemaDescription
200application/jsonBackupListResponseBackups
422application/jsonLegacyErrorS3 is not configured
500application/jsonLegacyErrorRemote backup listing failed

GET /backup/schedule

Read backup schedule settings and the computed next run time.

Responses:

StatusContent typeSchemaDescription
200application/jsonBackupScheduleResponseBackup schedule

PUT /backup/schedule

Patch backup schedule settings.

Request body:

  • Content type: application/json
  • Schema: BackupSchedulePatch
FieldTypeRequiredDescription
enabledbooleannoEnable scheduled snapshots
cronstringnoFive-part cron expression
retention_countintegernoNumber of local snapshots to retain

Responses:

StatusContent typeSchemaDescription
200application/jsonBackupScheduleResponseUpdated backup schedule
400application/jsonLegacyErrorMalformed or non-object JSON body
422application/jsonLegacyErrorInvalid schedule patch
500application/jsonLegacyErrorSchedule settings could not be saved

Examples:

Update backup schedule

Request:

curl -X PUT http://127.0.0.1:3210/backup/schedule \
  -H "Content-Type: application/json" \
  -d '{"enabled":true,"cron":"0 3 * * *","retention_count":10}'

GET /backup/destination

Read the effective backup directory and writability.

Responses:

StatusContent typeSchemaDescription
200application/jsonBackupDestinationResponseBackup destination

PUT /backup/destination

Set or clear the custom local backup directory.

Request body:

  • Content type: application/json
  • Schema: BackupDestinationPatch
FieldTypeRequiredDescription
pathstringyesAbsolute custom backup path, or empty string to reset

Responses:

StatusContent typeSchemaDescription
200application/jsonBackupDestinationResponseUpdated backup destination
400application/jsonLegacyErrorMalformed or non-object JSON body
422application/jsonLegacyErrorInvalid or unwritable path
500application/jsonLegacyErrorDestination settings could not be saved

Examples:

Set a custom backup destination

Request:

curl -X PUT http://127.0.0.1:3210/backup/destination \
  -H "Content-Type: application/json" \
  -d '{"path":"/Users/me/Backups/Grimoire"}'

POST /backup/verify

Verify a local backup snapshot without restoring it.

Request body:

  • Content type: application/json
  • Schema: BackupVerifyRequest
FieldTypeRequiredDescription
namestringyesLocal backup directory name

Responses:

StatusContent typeSchemaDescription
200application/jsonBackupVerificationResultBackup verification result
400application/jsonLegacyErrorMalformed JSON or non-object request body
409application/jsonLegacyErrorBackup or restore already in progress
422application/jsonLegacyErrorInvalid verify request or backup validation failed
500application/jsonLegacyErrorBackup verification failed

Examples:

Verify a local backup

Request:

curl -X POST http://127.0.0.1:3210/backup/verify \
  -H "Content-Type: application/json" \
  -d '{"name":"2026-05-13T09-30-00-000Z"}'

POST /backup/package

Create an encrypted package file from a local backup snapshot.

Request body:

  • Content type: application/json
  • Schema: BackupPackageRequest
FieldTypeRequiredDescription
namestringyesLocal backup directory name
passwordstringyesPassword used to encrypt the package

Responses:

StatusContent typeSchemaDescription
201application/jsonEncryptedBackupPackageResultEncrypted backup package created
400application/jsonLegacyErrorMalformed JSON or non-object request body
409application/jsonLegacyErrorBackup or restore already in progress
422application/jsonLegacyErrorInvalid package request or backup validation failed
500application/jsonLegacyErrorEncrypted backup package creation failed

Examples:

Create an encrypted package

Request:

curl -X POST http://127.0.0.1:3210/backup/package \
  -H "Content-Type: application/json" \
  -d '{"name":"2026-05-13T09-30-00-000Z","password":"correct horse battery staple"}'

POST /backup/package/verify

Verify an encrypted package file without restoring it.

Request body:

  • Content type: application/json
  • Schema: EncryptedBackupPackageRequest
FieldTypeRequiredDescription
pathstringyesAbsolute path to an encrypted backup package file accessible by the daemon
passwordstringyesPassword used to decrypt the package

Responses:

StatusContent typeSchemaDescription
200application/jsonEncryptedBackupPackageVerificationResultEncrypted backup package verification result
400application/jsonLegacyErrorMalformed JSON or non-object request body
409application/jsonLegacyErrorBackup or restore already in progress
422application/jsonLegacyErrorInvalid package request, wrong password, or package validation failed
500application/jsonLegacyErrorEncrypted backup package verification failed

Examples:

Verify an encrypted package

Request:

curl -X POST http://127.0.0.1:3210/backup/package/verify \
  -H "Content-Type: application/json" \
  -d '{"path":"/Users/me/Library/Application Support/littleimp/backups/2026-05-13T09-30-00-000Z.littleimp-backup.enc","password":"correct horse battery staple"}'

POST /restore

Restore from a local backup directory, remote S3 snapshot, or encrypted package.

Request body:

  • Content type: application/json
  • Schema: RestoreRequest
FieldTypeRequiredDescription
namestringnoLocal backup directory name
source"remote" | "encrypted_package"noRestore source
keystringnoRemote S3 snapshot.db key
pathstringnoAbsolute path to an encrypted backup package file accessible by the daemon
passwordstringnoPassword used to decrypt the encrypted package
allow_unsafe_no_checksumbooleannoAllow restoring a backup with no checksum file

Responses:

StatusContent typeSchemaDescription
200application/jsonRestoreResultRestore completed
400application/jsonLegacyErrorMalformed JSON
409application/jsonLegacyErrorBackup or restore already in progress
422application/jsonLegacyErrorInvalid restore request or backup validation failed
500application/jsonLegacyErrorRestore failed

Examples:

Restore a local backup

Request:

curl -X POST http://127.0.0.1:3210/restore \
  -H "Content-Type: application/json" \
  -d '{"name":"2026-05-13T09-30-00-000Z"}'

Restore a remote backup

Request:

curl -X POST http://127.0.0.1:3210/restore \
  -H "Content-Type: application/json" \
  -d '{"source":"remote","key":"little-imp/2026-05-13T09-30-00-000Z/snapshot.db"}'

Restore an encrypted package

Request:

curl -X POST http://127.0.0.1:3210/restore \
  -H "Content-Type: application/json" \
  -d '{"source":"encrypted_package","path":"/Users/me/Library/Application Support/littleimp/backups/2026-05-13T09-30-00-000Z.littleimp-backup.enc","password":"correct horse battery staple"}'

POST /settings/test-s3

Test connectivity to the configured S3 backup destination.

Responses:

StatusContent typeSchemaDescription
200application/jsonConnectivityTestResponseS3 connectivity succeeded
422application/jsonLegacyErrorS3 is not configured or connection failed

Examples:

Test S3 connectivity

Request:

curl -X POST http://127.0.0.1:3210/settings/test-s3

Timeline

GET /timeline

List timeline events with pagination.

Query parameters:

FieldTypeRequiredDescription
limitintegernoMaximum number of results to return
offsetintegernoNumber of results to skip

Responses:

StatusContent typeSchemaDescription
200application/jsonTimelinePageTimeline page
400application/problem+jsonProblemDetailsInvalid limit or offset

Suggestions

GET /suggestions

List pending organization-agent suggestions.

Responses:

StatusContent typeSchemaDescription
200application/jsonSuggestionsResponsePending suggestions

POST /suggestions/:id/accept

Accept a suggestion and apply its action.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Responses:

StatusContent typeSchemaDescription
200application/jsonobjectAccepted suggestion
404application/problem+jsonProblemDetailsSuggestion not found
422application/problem+jsonProblemDetailsSuggestion is no longer pending or action is invalid
500application/problem+jsonProblemDetailsSuggestion action failed

POST /suggestions/:id/reject

Reject a pending suggestion.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Responses:

StatusContent typeSchemaDescription
200application/jsonobjectRejected suggestion
404application/problem+jsonProblemDetailsSuggestion not found
422application/problem+jsonProblemDetailsSuggestion is no longer pending
500application/problem+jsonProblemDetailsSuggestion could not be resolved

Export

GET /export

Export active bookmarks as JSON or CSV.

Query parameters:

FieldTypeRequiredDescription
format"json" | "csv"noExport format
tagstringnoFilter by tag name
domainstringnoFilter by exact domain
category_idstringnoFilter by exact category ID; takes precedence over category
categorystringnoFilter by category name
date_fromstringnoInclusive ISO date or date-time lower bound
date_tostringnoInclusive ISO date or date-time upper bound
read_later"true" | "false" | "1" | "0"noFilter by read-later state; accepts boolean strings or numeric flags
read_state"read" | "unread"noFilter by read state
is_pinned"true" | "false" | "1" | "0"noFilter by pinned/starred state; accepts boolean strings or numeric flags
opened_count_minintegernoFilter to bookmarks opened at least this many times
opened_count_maxintegernoFilter to bookmarks opened no more than this many times
last_opened_fromstringnoInclusive ISO date or date-time lower bound for last opened time
last_opened_tostringnoInclusive ISO date or date-time upper bound for last opened time

Responses:

StatusContent typeSchemaDescription
200application/json or text/csvarray<ExportBookmark>Downloadable JSON or CSV export
400application/jsonLegacyErrorInvalid format
422application/jsonLegacyErrorInvalid export filter

Examples:

Export read-later bookmarks as JSON

Request:

curl "http://127.0.0.1:3210/export?format=json&read_later=true"

Response:

HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "bm_123",
    "url": "https://example.com/rag-vector-search",
    "title": "RAG Vector Search Notes",
    "summary": "A practical walkthrough of hybrid retrieval for RAG systems.",
    "tags": [
      "rag",
      "search"
    ],
    "category": "AI Research",
    "domain": "example.com",
    "is_pinned": 0,
    "read_later": 1,
    "opened_count": 2,
    "last_opened_at": "2026-06-01T08:45:00.000Z",
    "created_at": "2026-06-01T09:30:00.000Z",
    "is_archived": 0,
    "read_at": null,
    "notes": "Compare chunking guidance with local notes."
  }
]

Export read pinned bookmarks opened this month

Request:

curl "http://127.0.0.1:3210/export?format=csv&read_state=read&is_pinned=true&opened_count_min=1&last_opened_from=2026-06-01"

Reject an invalid export filter

Request:

curl "http://127.0.0.1:3210/export?format=json&read_state=maybe"

Response:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json

{
  "error": "`read_state` must be read or unread"
}

Integrations

POST /capture

Capture a bookmark from an explicit local integration.

This protected local integration endpoint requires Authorization: Bearer <integration-token>. It creates a normal bookmark, optionally applies tags, notes, category assignment, and capture metadata, then enqueues the standard ingestion pipeline. Existing active URLs are returned idempotently without merging metadata or queueing duplicate work.

Request body:

  • Content type: application/json
  • Schema: CaptureRequest
FieldTypeRequiredDescription
urlstringyesHTTP or HTTPS URL to save
titlestringnoOptional title override
tagsarraynoOptional replacement tag names
category_idstring | nullnoExisting category ID to assign
categorystringnoRoot category name to resolve or create when category_id is omitted
notesstring | nullnoPersonal notes, or null to leave empty
sourceCaptureSourceno
source.clientstring | nullnoOptional local integration client label
source.source_urlstring | nullnoOptional public HTTP or HTTPS page/context URL
source.referrer_urlstring | nullnoOptional public HTTP or HTTPS referrer URL
source.selected_textstring | nullnoOptional selected text or short capture context

Responses:

StatusContent typeSchemaDescription
200application/jsonCaptureResponseExisting active bookmark returned idempotently
201application/jsonCaptureResponseBookmark captured and ingest queued
400application/problem+jsonProblemDetailsMalformed JSON
401application/problem+jsonProblemDetailsMissing, invalid, rotated, or revoked integration token
409application/problem+jsonProblemDetailsURL already exists in trash or archive
413application/jsonLegacyErrorRequest body exceeds local JSON limit
422application/problem+jsonProblemDetailsInvalid capture request

Examples:

Capture a bookmark from a local integration

Request:

curl -X POST http://127.0.0.1:3210/capture \
  -H "Authorization: Bearer limp_it_example" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/rag-vector-search","title":"RAG Vector Search Notes","tags":["rag","search"],"category":"AI Research","notes":"Compare chunking guidance with local notes.","source":{"client":"local-capture","source_url":"https://example.com/rag-vector-search","referrer_url":"https://example.com/","selected_text":"Hybrid retrieval combines exact and semantic matching."}}'

Response:

HTTP/1.1 201 Created
Content-Type: application/json

{
  "data": {
    "bookmark": {
      "id": "bm_123",
      "url": "https://example.com/rag-vector-search",
      "domain": "example.com",
      "title": "RAG Vector Search Notes",
      "description": null,
      "status": "saved",
      "category_id": "cat_ai",
      "favicon_url": null,
      "screenshot_url": null,
      "is_pinned": 0,
      "is_archived": 0,
      "is_trashed": 0,
      "trashed_at": null,
      "read_later": 0,
      "read_at": null,
      "opened_count": 0,
      "last_opened_at": null,
      "notes": "Compare chunking guidance with local notes.",
      "created_at": "2026-06-01T09:30:00.000Z",
      "updated_at": "2026-06-01T09:30:00.000Z",
      "tags": [
        "rag",
        "search"
      ]
    },
    "capture": {
      "bookmark_id": "bm_123",
      "source_client": "local-capture",
      "source_url": "https://example.com/rag-vector-search",
      "referrer_url": "https://example.com/",
      "selected_text": "Hybrid retrieval combines exact and semantic matching.",
      "captured_at": "2026-06-01T09:30:00.000Z",
      "updated_at": "2026-06-01T09:30:00.000Z"
    },
    "created": true,
    "job_id": "job_123"
  }
}

GET /capture/bookmarklet

Bookmarklet capture page (hidden iframe target, no auth header).

The browser bookmarklet uses a hidden iframe pointed at this endpoint to avoid CORS. Authentication is via a query-parameter token. The endpoint returns an HTML page (not JSON) that the iframe renders silently. Designed for the Settings โ†’ Browser Integration bookmarklet flow; not intended for direct use.

Query parameters:

FieldTypeRequiredDescription
tokenstringyesIntegration bearer token (query-param auth)
urlstringyesThe URL to capture
titlestringnoPage title
selectionstringnoUser-selected text

Responses:

StatusContent typeSchemaDescription
200--Bookmark already exists (not duplicated)
201--Bookmark captured successfully
400application/problem+jsonProblemDetailsMissing token or url
401application/problem+jsonProblemDetailsInvalid or revoked token
409application/problem+jsonProblemDetailsURL exists in trash or archive
422application/problem+jsonProblemDetailsInvalid URL

GET /integration-tokens

List managed local integration tokens with secret values redacted.

Responses:

StatusContent typeSchemaDescription
200application/jsonIntegrationTokenListResponseIntegration tokens

Examples:

List integration tokens

Request:

curl http://127.0.0.1:3210/integration-tokens

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": [
    {
      "id": "itok_123",
      "name": "Raycast MCP",
      "token_prefix": "limp_it_7fd9",
      "created_at": "2026-06-01T09:30:00.000Z",
      "last_used_at": null,
      "revoked_at": null
    }
  ]
}

POST /integration-tokens

Create a managed bearer token for an explicit local integration client.

The full token is returned only once. Store it in the client and use it as an Authorization bearer token. The JSON body is optional; omit it to create a token named Local integration.

Request body:

  • Content type: application/json
  • Schema: IntegrationTokenCreateRequest
FieldTypeRequiredDescription
namestringnoUser-visible integration client name

Responses:

StatusContent typeSchemaDescription
201application/jsonIntegrationTokenCreateResponseIntegration token created
400application/problem+jsonProblemDetailsMalformed JSON
415application/problem+jsonProblemDetailsRequest body is not application/json
422application/problem+jsonProblemDetailsInvalid token name

Examples:

Create an integration token

Request:

curl -X POST http://127.0.0.1:3210/integration-tokens \
  -H "Content-Type: application/json" \
  -d '{"name":"Raycast MCP"}'

Response:

HTTP/1.1 201 Created
Content-Type: application/json

{
  "data": {
    "token": "limp_it_example_secret",
    "record": {
      "id": "itok_123",
      "name": "Raycast MCP",
      "token_prefix": "limp_it_7fd9",
      "created_at": "2026-06-01T09:30:00.000Z",
      "last_used_at": null,
      "revoked_at": null
    }
  }
}

POST /integration-tokens/:id/rotate

Rotate an active integration token and return the new bearer token once.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Responses:

StatusContent typeSchemaDescription
200application/jsonIntegrationTokenCreateResponseIntegration token rotated
404application/problem+jsonProblemDetailsActive integration token not found

DELETE /integration-tokens/:id

Revoke an integration token.

Path parameters:

FieldTypeRequiredDescription
idstringyesid path parameter

Responses:

StatusContent typeSchemaDescription
204--Integration token revoked
404application/problem+jsonProblemDetailsIntegration token not found

MCP

ALL /mcp

Handle MCP Streamable HTTP transport requests.

The daemon creates a fresh MCP server and transport for each request. MCP is a local integration surface and requires Authorization: Bearer <integration-token>.

Responses:

StatusContent typeSchemaDescription
200application/json or text/event-stream-MCP transport response
401application/problem+jsonProblemDetailsMissing, invalid, rotated, or revoked integration token
500application/jsonMcpErrorResponseMCP request failed

Examples:

Call the MCP endpoint

Request:

curl -X POST http://127.0.0.1:3210/mcp \
  -H "Authorization: Bearer limp_it_example" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.1"}}}'

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-03-26",
    "capabilities": {},
    "serverInfo": {
      "name": "grimoire",
      "version": "1.0.1"
    }
  }
}

Reject a missing integration token

Request:

curl -X POST http://127.0.0.1:3210/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Response:

HTTP/1.1 401 Unauthorized
Content-Type: application/problem+json
WWW-Authenticate: Bearer realm="littleimp-local-integrations"

{
  "type": "https://littleimp.app/problems/integration-token-required",
  "title": "Unauthorized",
  "status": 401,
  "detail": "A managed integration bearer token is required for this route"
}

Demo

POST /demo/load

Load demo bookmarks into an empty library for first-run exploration.

Creates a set of 10 demo bookmarks with realistic developer-content URLs, titles, categories, and tags. Only succeeds when the library has no existing bookmarks. Returns the count of created bookmarks and categories.

Responses:

StatusContent typeSchemaDescription
200application/jsonDemoLoadResultDemo data loaded
409application/jsonLegacyErrorLibrary is not empty โ€” demo can only be loaded on a fresh library
500application/jsonLegacyErrorFailed to load demo data

Schemas

ProblemDetails

RFC 7807-style problem response

FieldTypeRequiredDescription
typestringyesStable problem type URI
titlestringyesShort human-readable error title
statusintegeryesHTTP status code
detailstring | nullnoHuman-readable explanation

LegacyError

Legacy JSON error response

FieldTypeRequiredDescription
errorstringyesHuman-readable error message
detailsstring | nullnoOptional additional details

Pagination

FieldTypeRequiredDescription
totalintegeryesTotal matching records
limitintegeryesApplied page size
offsetintegeryesApplied offset
has_morebooleanyesWhether another page exists

Bookmark

FieldTypeRequiredDescription
idstringyesBookmark ID
urlstringyesOriginal bookmark URL
domainstringyesURL hostname
titlestring | nullyesPage title
descriptionstring | nullyesPage description
status"saved" | "fetched" | "extracted" | "ai_enriched" | "indexed"yesPipeline status
category_idstring | nullyesAssigned category ID
favicon_urlstring | nullyesCached favicon media path or URL
screenshot_urlstring | nullyesCached page preview media path or URL
is_pinned0 | 1yesPinned flag, 0 or 1; maps Grimoire starred/favorite state
is_archived0 | 1yesArchived flag, 0 or 1
is_trashed0 | 1yesTrash flag, 0 or 1
trashed_atstring | nullyesTrash timestamp
read_later0 | 1yesRead-later flag, 0 or 1
read_atstring | nullyesRead timestamp
opened_countintegeryesNumber of user-triggered opens
last_opened_atstring | nullyesMost recent user-triggered open timestamp
notesstring | nullyesPersonal notes
created_atstringyesCreation timestamp
updated_atstringyesUpdate timestamp
tagsarrayyesTag names attached to the bookmark

BookmarkContent

FieldTypeRequiredDescription
bookmark_idstringyesBookmark ID
raw_htmlstring | nullyesRaw HTML
markdownstring | nullyesExtracted Markdown
summarystring | nullyesExtracted summary
authorstring | nullyesAuthor
published_atstring | nullyesPublished timestamp
word_countinteger | nullyesEstimated word count
languagestring | nullyesDetected language
extracted_atstringyesExtraction timestamp

BookmarkMedia

Cached local media item

FieldTypeRequiredDescription
idstringyesMedia cache record ID
kind"favicon" | "screenshot" | "image"yesMedia kind
urlstringyesLocal daemon media path
source_urlstringyesOriginal media source URL
media_typestringyesCached non-SVG image MIME type
size_bytesintegeryesCached media byte size
altstring | nullyesImage alt text or preview label

BookmarkMediaSet

Cached local media available for a bookmark

FieldTypeRequiredDescription
faviconBookmarkMedia | nullyes
favicon.idstringyesMedia cache record ID
favicon.kind"favicon" | "screenshot" | "image"yesMedia kind
favicon.urlstringyesLocal daemon media path
favicon.source_urlstringyesOriginal media source URL
favicon.media_typestringyesCached non-SVG image MIME type
favicon.size_bytesintegeryesCached media byte size
favicon.altstring | nullyesImage alt text or preview label
screenshotBookmarkMedia | nullyes
screenshot.idstringyesMedia cache record ID
screenshot.kind"favicon" | "screenshot" | "image"yesMedia kind
screenshot.urlstringyesLocal daemon media path
screenshot.source_urlstringyesOriginal media source URL
screenshot.media_typestringyesCached non-SVG image MIME type
screenshot.size_bytesintegeryesCached media byte size
screenshot.altstring | nullyesImage alt text or preview label
imagesarrayyesCached extracted images

BookmarkDetail

Bookmark with extracted content

FieldTypeRequiredDescription
idstringyesBookmark ID
urlstringyesOriginal bookmark URL
domainstringyesURL hostname
titlestring | nullyesPage title
descriptionstring | nullyesPage description
status"saved" | "fetched" | "extracted" | "ai_enriched" | "indexed"yesPipeline status
category_idstring | nullyesAssigned category ID
favicon_urlstring | nullyesCached favicon media path or URL
screenshot_urlstring | nullyesCached page preview media path or URL
is_pinned0 | 1yesPinned flag, 0 or 1; maps Grimoire starred/favorite state
is_archived0 | 1yesArchived flag, 0 or 1
is_trashed0 | 1yesTrash flag, 0 or 1
trashed_atstring | nullyesTrash timestamp
read_later0 | 1yesRead-later flag, 0 or 1
read_atstring | nullyesRead timestamp
opened_countintegeryesNumber of user-triggered opens
last_opened_atstring | nullyesMost recent user-triggered open timestamp
notesstring | nullyesPersonal notes
created_atstringyesCreation timestamp
updated_atstringyesUpdate timestamp
tagsarrayyesTag names attached to the bookmark
contentBookmarkContent | nullyes
content.bookmark_idstringyesBookmark ID
content.raw_htmlstring | nullyesRaw HTML
content.markdownstring | nullyesExtracted Markdown
content.summarystring | nullyesExtracted summary
content.authorstring | nullyesAuthor
content.published_atstring | nullyesPublished timestamp
content.word_countinteger | nullyesEstimated word count
content.languagestring | nullyesDetected language
content.extracted_atstringyesExtraction timestamp
mediaBookmarkMediaSetyes
media.faviconBookmarkMedia | nullyes
media.favicon.idstringyesMedia cache record ID
media.favicon.kind"favicon" | "screenshot" | "image"yesMedia kind
media.favicon.urlstringyesLocal daemon media path
media.favicon.source_urlstringyesOriginal media source URL
media.favicon.media_typestringyesCached non-SVG image MIME type
media.favicon.size_bytesintegeryesCached media byte size
media.favicon.altstring | nullyesImage alt text or preview label
media.screenshotBookmarkMedia | nullyes
media.screenshot.idstringyesMedia cache record ID
media.screenshot.kind"favicon" | "screenshot" | "image"yesMedia kind
media.screenshot.urlstringyesLocal daemon media path
media.screenshot.source_urlstringyesOriginal media source URL
media.screenshot.media_typestringyesCached non-SVG image MIME type
media.screenshot.size_bytesintegeryesCached media byte size
media.screenshot.altstring | nullyesImage alt text or preview label
media.imagesarrayyesCached extracted images

BookmarkDetailResponse

Single bookmark response

FieldTypeRequiredDescription
dataBookmarkDetailyes
data.idstringyesBookmark ID
data.urlstringyesOriginal bookmark URL
data.domainstringyesURL hostname
data.titlestring | nullyesPage title
data.descriptionstring | nullyesPage description
data.status"saved" | "fetched" | "extracted" | "ai_enriched" | "indexed"yesPipeline status
data.category_idstring | nullyesAssigned category ID
data.favicon_urlstring | nullyesCached favicon media path or URL
data.screenshot_urlstring | nullyesCached page preview media path or URL
data.is_pinned0 | 1yesPinned flag, 0 or 1; maps Grimoire starred/favorite state
data.is_archived0 | 1yesArchived flag, 0 or 1
data.is_trashed0 | 1yesTrash flag, 0 or 1
data.trashed_atstring | nullyesTrash timestamp
data.read_later0 | 1yesRead-later flag, 0 or 1
data.read_atstring | nullyesRead timestamp
data.opened_countintegeryesNumber of user-triggered opens
data.last_opened_atstring | nullyesMost recent user-triggered open timestamp
data.notesstring | nullyesPersonal notes
data.created_atstringyesCreation timestamp
data.updated_atstringyesUpdate timestamp
data.tagsarrayyesTag names attached to the bookmark
data.contentBookmarkContent | nullyes
data.content.bookmark_idstringyesBookmark ID
data.content.raw_htmlstring | nullyesRaw HTML
data.content.markdownstring | nullyesExtracted Markdown
data.content.summarystring | nullyesExtracted summary
data.content.authorstring | nullyesAuthor
data.content.published_atstring | nullyesPublished timestamp
data.content.word_countinteger | nullyesEstimated word count
data.content.languagestring | nullyesDetected language
data.content.extracted_atstringyesExtraction timestamp
data.mediaBookmarkMediaSetyes
data.media.faviconBookmarkMedia | nullyes
data.media.favicon.idstringyesMedia cache record ID
data.media.favicon.kind"favicon" | "screenshot" | "image"yesMedia kind
data.media.favicon.urlstringyesLocal daemon media path
data.media.favicon.source_urlstringyesOriginal media source URL
data.media.favicon.media_typestringyesCached non-SVG image MIME type
data.media.favicon.size_bytesintegeryesCached media byte size
data.media.favicon.altstring | nullyesImage alt text or preview label
data.media.screenshotBookmarkMedia | nullyes
data.media.screenshot.idstringyesMedia cache record ID
data.media.screenshot.kind"favicon" | "screenshot" | "image"yesMedia kind
data.media.screenshot.urlstringyesLocal daemon media path
data.media.screenshot.source_urlstringyesOriginal media source URL
data.media.screenshot.media_typestringyesCached non-SVG image MIME type
data.media.screenshot.size_bytesintegeryesCached media byte size
data.media.screenshot.altstring | nullyesImage alt text or preview label
data.media.imagesarrayyesCached extracted images

BookmarkResponse

Single bookmark response

FieldTypeRequiredDescription
dataBookmarkyes
data.idstringyesBookmark ID
data.urlstringyesOriginal bookmark URL
data.domainstringyesURL hostname
data.titlestring | nullyesPage title
data.descriptionstring | nullyesPage description
data.status"saved" | "fetched" | "extracted" | "ai_enriched" | "indexed"yesPipeline status
data.category_idstring | nullyesAssigned category ID
data.favicon_urlstring | nullyesCached favicon media path or URL
data.screenshot_urlstring | nullyesCached page preview media path or URL
data.is_pinned0 | 1yesPinned flag, 0 or 1; maps Grimoire starred/favorite state
data.is_archived0 | 1yesArchived flag, 0 or 1
data.is_trashed0 | 1yesTrash flag, 0 or 1
data.trashed_atstring | nullyesTrash timestamp
data.read_later0 | 1yesRead-later flag, 0 or 1
data.read_atstring | nullyesRead timestamp
data.opened_countintegeryesNumber of user-triggered opens
data.last_opened_atstring | nullyesMost recent user-triggered open timestamp
data.notesstring | nullyesPersonal notes
data.created_atstringyesCreation timestamp
data.updated_atstringyesUpdate timestamp
data.tagsarrayyesTag names attached to the bookmark

BookmarkListResponse

Paginated bookmark list

FieldTypeRequiredDescription
dataarrayyesPage items
paginationPaginationyes
pagination.totalintegeryesTotal matching records
pagination.limitintegeryesApplied page size
pagination.offsetintegeryesApplied offset
pagination.has_morebooleanyesWhether another page exists

BookmarkArrayResponse

Bookmark array response

FieldTypeRequiredDescription
dataarrayyesBookmarks

BookmarkAggregateCategory

Category aggregate count under the requested library filter context

FieldTypeRequiredDescription
idstringyesCategory ID
namestringyesCategory name
countintegeryesMatching active bookmark count

BookmarkAggregateTag

Tag aggregate count under the requested library filter context

FieldTypeRequiredDescription
namestringyesTag name
countintegeryesMatching active bookmark count

BookmarkAggregateDomain

Domain aggregate count under the requested library filter context

FieldTypeRequiredDescription
domainstringyesDomain
countintegeryesMatching active bookmark count

BookmarkReadAggregate

Read state aggregate counts

FieldTypeRequiredDescription
readintegeryesMatching active bookmarks marked read
unreadintegeryesMatching active bookmarks not marked read

BookmarkPinnedAggregate

Pinned/starred aggregate counts

FieldTypeRequiredDescription
pinnedintegeryesMatching active bookmarks pinned/starred
unpinnedintegeryesMatching active bookmarks not pinned/starred

BookmarkReadLaterAggregate

Read-later aggregate counts

FieldTypeRequiredDescription
yesintegeryesMatching active bookmarks marked read-later
nointegeryesMatching active bookmarks not marked read-later

BookmarkAggregates

Page-independent active-library aggregate counts

FieldTypeRequiredDescription
totalintegeryesTotal active bookmarks matching the requested library filter context
categoriesarrayyesCategory counts
tagsarrayyesTag counts
domainsarrayyesDomain counts
readBookmarkReadAggregateyes
read.readintegeryesMatching active bookmarks marked read
read.unreadintegeryesMatching active bookmarks not marked read
pinnedBookmarkPinnedAggregateyes
pinned.pinnedintegeryesMatching active bookmarks pinned/starred
pinned.unpinnedintegeryesMatching active bookmarks not pinned/starred
read_laterBookmarkReadLaterAggregateyes
read_later.yesintegeryesMatching active bookmarks marked read-later
read_later.nointegeryesMatching active bookmarks not marked read-later

BookmarkAggregatesResponse

Bookmark aggregate counts response

FieldTypeRequiredDescription
dataBookmarkAggregatesyes
data.totalintegeryesTotal active bookmarks matching the requested library filter context
data.categoriesarrayyesCategory counts
data.tagsarrayyesTag counts
data.domainsarrayyesDomain counts
data.readBookmarkReadAggregateyes
data.read.readintegeryesMatching active bookmarks marked read
data.read.unreadintegeryesMatching active bookmarks not marked read
data.pinnedBookmarkPinnedAggregateyes
data.pinned.pinnedintegeryesMatching active bookmarks pinned/starred
data.pinned.unpinnedintegeryesMatching active bookmarks not pinned/starred
data.read_laterBookmarkReadLaterAggregateyes
data.read_later.yesintegeryesMatching active bookmarks marked read-later
data.read_later.nointegeryesMatching active bookmarks not marked read-later

BookmarkCreateRequest

FieldTypeRequiredDescription
urlstringyesHTTP or HTTPS URL to save
titlestringnoOptional title override

CaptureSource

Optional metadata recorded for a local integration capture request

FieldTypeRequiredDescription
clientstring | nullnoOptional local integration client label
source_urlstring | nullnoOptional public HTTP or HTTPS page/context URL
referrer_urlstring | nullnoOptional public HTTP or HTTPS referrer URL
selected_textstring | nullnoOptional selected text or short capture context

BookmarkCaptureMetadata

Stored local integration capture metadata

FieldTypeRequiredDescription
bookmark_idstringyesCaptured bookmark ID
source_clientstring | nullyesLocal integration client label
source_urlstring | nullyesStored source/context URL
referrer_urlstring | nullyesStored referrer URL
selected_textstring | nullyesStored selected text or capture context
captured_atstringyesFirst capture timestamp
updated_atstringyesMost recent metadata update timestamp

CaptureRequest

Protected one-click capture request for explicit local integrations

FieldTypeRequiredDescription
urlstringyesHTTP or HTTPS URL to save
titlestringnoOptional title override
tagsarraynoOptional replacement tag names
category_idstring | nullnoExisting category ID to assign
categorystringnoRoot category name to resolve or create when category_id is omitted
notesstring | nullnoPersonal notes, or null to leave empty
sourceCaptureSourceno
source.clientstring | nullnoOptional local integration client label
source.source_urlstring | nullnoOptional public HTTP or HTTPS page/context URL
source.referrer_urlstring | nullnoOptional public HTTP or HTTPS referrer URL
source.selected_textstring | nullnoOptional selected text or short capture context

CaptureResult

One-click capture result

FieldTypeRequiredDescription
bookmarkBookmarkyes
bookmark.idstringyesBookmark ID
bookmark.urlstringyesOriginal bookmark URL
bookmark.domainstringyesURL hostname
bookmark.titlestring | nullyesPage title
bookmark.descriptionstring | nullyesPage description
bookmark.status"saved" | "fetched" | "extracted" | "ai_enriched" | "indexed"yesPipeline status
bookmark.category_idstring | nullyesAssigned category ID
bookmark.favicon_urlstring | nullyesCached favicon media path or URL
bookmark.screenshot_urlstring | nullyesCached page preview media path or URL
bookmark.is_pinned0 | 1yesPinned flag, 0 or 1; maps Grimoire starred/favorite state
bookmark.is_archived0 | 1yesArchived flag, 0 or 1
bookmark.is_trashed0 | 1yesTrash flag, 0 or 1
bookmark.trashed_atstring | nullyesTrash timestamp
bookmark.read_later0 | 1yesRead-later flag, 0 or 1
bookmark.read_atstring | nullyesRead timestamp
bookmark.opened_countintegeryesNumber of user-triggered opens
bookmark.last_opened_atstring | nullyesMost recent user-triggered open timestamp
bookmark.notesstring | nullyesPersonal notes
bookmark.created_atstringyesCreation timestamp
bookmark.updated_atstringyesUpdate timestamp
bookmark.tagsarrayyesTag names attached to the bookmark
captureBookmarkCaptureMetadata | nullyes
capture.bookmark_idstringyesCaptured bookmark ID
capture.source_clientstring | nullyesLocal integration client label
capture.source_urlstring | nullyesStored source/context URL
capture.referrer_urlstring | nullyesStored referrer URL
capture.selected_textstring | nullyesStored selected text or capture context
capture.captured_atstringyesFirst capture timestamp
capture.updated_atstringyesMost recent metadata update timestamp
createdbooleanyesWhether a new bookmark was created
job_idstring | nullyesQueued ingest job ID for new bookmarks

CaptureResponse

One-click capture response

FieldTypeRequiredDescription
dataCaptureResultyes
data.bookmarkBookmarkyes
data.bookmark.idstringyesBookmark ID
data.bookmark.urlstringyesOriginal bookmark URL
data.bookmark.domainstringyesURL hostname
data.bookmark.titlestring | nullyesPage title
data.bookmark.descriptionstring | nullyesPage description
data.bookmark.status"saved" | "fetched" | "extracted" | "ai_enriched" | "indexed"yesPipeline status
data.bookmark.category_idstring | nullyesAssigned category ID
data.bookmark.favicon_urlstring | nullyesCached favicon media path or URL
data.bookmark.screenshot_urlstring | nullyesCached page preview media path or URL
data.bookmark.is_pinned0 | 1yesPinned flag, 0 or 1; maps Grimoire starred/favorite state
data.bookmark.is_archived0 | 1yesArchived flag, 0 or 1
data.bookmark.is_trashed0 | 1yesTrash flag, 0 or 1
data.bookmark.trashed_atstring | nullyesTrash timestamp
data.bookmark.read_later0 | 1yesRead-later flag, 0 or 1
data.bookmark.read_atstring | nullyesRead timestamp
data.bookmark.opened_countintegeryesNumber of user-triggered opens
data.bookmark.last_opened_atstring | nullyesMost recent user-triggered open timestamp
data.bookmark.notesstring | nullyesPersonal notes
data.bookmark.created_atstringyesCreation timestamp
data.bookmark.updated_atstringyesUpdate timestamp
data.bookmark.tagsarrayyesTag names attached to the bookmark
data.captureBookmarkCaptureMetadata | nullyes
data.capture.bookmark_idstringyesCaptured bookmark ID
data.capture.source_clientstring | nullyesLocal integration client label
data.capture.source_urlstring | nullyesStored source/context URL
data.capture.referrer_urlstring | nullyesStored referrer URL
data.capture.selected_textstring | nullyesStored selected text or capture context
data.capture.captured_atstringyesFirst capture timestamp
data.capture.updated_atstringyesMost recent metadata update timestamp
data.createdbooleanyesWhether a new bookmark was created
data.job_idstring | nullyesQueued ingest job ID for new bookmarks

BookmarkUpdateRequest

FieldTypeRequiredDescription
titlestring | nullnoNew title, or null to clear
category_idstring | nullnoCategory ID, or null to clear
tagsarraynoReplacement tag names
is_pinnedintegernoPinned flag, 0 or 1; maps Grimoire starred/favorite state
read_laterintegernoRead-later flag, 0 or 1
is_archivedintegernoArchived flag, 0 or 1
read_atstring | nullnoISO 8601 date-time, or null to mark unread
notesstring | nullnoPersonal notes, or null to clear

RelatedBookmarksResponse

Response data

FieldTypeRequiredDescription
dataarrayyesRelated bookmarks

PipelineFailure

Latest actionable pipeline failure for a bookmark

FieldTypeRequiredDescription
stage"fetch" | "extract" | "ai_enrich" | "embed" | "index"yesPipeline stage that last reported an actionable failure
messagestringyesFailure message safe to show in the local UI
configuration_relatedbooleanyesWhether the failure likely requires provider settings
retryablebooleanyesWhether retrying the bookmark pipeline is supported
failed_atstringyesFailure timestamp
dismissed_atstring | nullyesDismissal timestamp

BookmarkPipelineStatus

FieldTypeRequiredDescription
bookmarkIdstringyesBookmark ID
bookmarkStatus"saved" | "fetched" | "extracted" | "ai_enriched" | "indexed"yesCurrent bookmark pipeline status
last_failurePipelineFailure | nullyes
last_failure.stage"fetch" | "extract" | "ai_enrich" | "embed" | "index"yesPipeline stage that last reported an actionable failure
last_failure.messagestringyesFailure message safe to show in the local UI
last_failure.configuration_relatedbooleanyesWhether the failure likely requires provider settings
last_failure.retryablebooleanyesWhether retrying the bookmark pipeline is supported
last_failure.failed_atstringyesFailure timestamp
last_failure.dismissed_atstring | nullyesDismissal timestamp
jobobject | nullyes
job.idstringyesJob ID
job.typestringyesJob type
job.status"pending" | "running" | "done" | "failed"yesJob status
job.errorstring | nullyesJob error
job.created_atstringyesJob creation timestamp
job.started_atstring | nullyesJob start timestamp
job.finished_atstring | nullyesJob finish timestamp

BookmarkPipelineStatusResponse

Response data

FieldTypeRequiredDescription
dataBookmarkPipelineStatusyes
data.bookmarkIdstringyesBookmark ID
data.bookmarkStatus"saved" | "fetched" | "extracted" | "ai_enriched" | "indexed"yesCurrent bookmark pipeline status
data.last_failurePipelineFailure | nullyes
data.last_failure.stage"fetch" | "extract" | "ai_enrich" | "embed" | "index"yesPipeline stage that last reported an actionable failure
data.last_failure.messagestringyesFailure message safe to show in the local UI
data.last_failure.configuration_relatedbooleanyesWhether the failure likely requires provider settings
data.last_failure.retryablebooleanyesWhether retrying the bookmark pipeline is supported
data.last_failure.failed_atstringyesFailure timestamp
data.last_failure.dismissed_atstring | nullyesDismissal timestamp
data.jobobject | nullyes
data.job.idstringyesJob ID
data.job.typestringyesJob type
data.job.status"pending" | "running" | "done" | "failed"yesJob status
data.job.errorstring | nullyesJob error
data.job.created_atstringyesJob creation timestamp
data.job.started_atstring | nullyesJob start timestamp
data.job.finished_atstring | nullyesJob finish timestamp

ReprocessRequest

FieldTypeRequiredDescription
mode"selected" | "failed_only" | "all" | "embeddings_only"yesReprocess mode
bookmark_idstringnoBookmark ID required when mode is selected
replace_ai_fieldsbooleannoWhen true, allow reprocessing to update AI-derived title, category, and tags; manual notes are never overwritten

ReprocessBatch

FieldTypeRequiredDescription
batch_idstringyesReprocess batch ID
mode"selected" | "failed_only" | "all" | "embeddings_only"yesAccepted reprocess mode
requestedintegeryesTarget bookmarks considered
enqueuedintegeryesJobs enqueued
skippedintegeryesBookmarks skipped because work is already queued or running
job_idsarrayyesQueued job IDs
status_urlstring | nullyesBatch status URL when jobs were enqueued

ReprocessBatchResponse

Response data

FieldTypeRequiredDescription
dataReprocessBatchyes
data.batch_idstringyesReprocess batch ID
data.mode"selected" | "failed_only" | "all" | "embeddings_only"yesAccepted reprocess mode
data.requestedintegeryesTarget bookmarks considered
data.enqueuedintegeryesJobs enqueued
data.skippedintegeryesBookmarks skipped because work is already queued or running
data.job_idsarrayyesQueued job IDs
data.status_urlstring | nullyesBatch status URL when jobs were enqueued

ReprocessBatchStatus

FieldTypeRequiredDescription
batch_idstringyesReprocess batch ID
totalintegeryesTotal jobs in the batch
pendingintegeryesPending jobs
runningintegeryesRunning jobs
doneintegeryesCompleted jobs
failedintegeryesFailed jobs

ReprocessBatchStatusResponse

Response data

FieldTypeRequiredDescription
dataReprocessBatchStatusyes
data.batch_idstringyesReprocess batch ID
data.totalintegeryesTotal jobs in the batch
data.pendingintegeryesPending jobs
data.runningintegeryesRunning jobs
data.doneintegeryesCompleted jobs
data.failedintegeryesFailed jobs

SearchResultItem

Bookmark search hit

FieldTypeRequiredDescription
idstringyesBookmark ID
urlstringyesOriginal bookmark URL
domainstringyesURL hostname
titlestring | nullyesPage title
descriptionstring | nullyesPage description
status"saved" | "fetched" | "extracted" | "ai_enriched" | "indexed"yesPipeline status
category_idstring | nullyesAssigned category ID
favicon_urlstring | nullyesCached favicon media path or URL
screenshot_urlstring | nullyesCached page preview media path or URL
is_pinned0 | 1yesPinned flag, 0 or 1; maps Grimoire starred/favorite state
is_archived0 | 1yesArchived flag, 0 or 1
is_trashed0 | 1yesTrash flag, 0 or 1
trashed_atstring | nullyesTrash timestamp
read_later0 | 1yesRead-later flag, 0 or 1
read_atstring | nullyesRead timestamp
opened_countintegeryesNumber of user-triggered opens
last_opened_atstring | nullyesMost recent user-triggered open timestamp
notesstring | nullyesPersonal notes
created_atstringyesCreation timestamp
updated_atstringyesUpdate timestamp
tagsarrayyesTag names attached to the bookmark
snippetstring | nullyesHighlighted search excerpt
ranknumber | nullyesSearch rank or hybrid score

SearchResponse

FieldTypeRequiredDescription
dataarrayyesSearch hits
paginationPaginationyes
pagination.totalintegeryesTotal matching records
pagination.limitintegeryesApplied page size
pagination.offsetintegeryesApplied offset
pagination.has_morebooleanyesWhether another page exists
metaobjectyes
meta.mode"keyword" | "semantic" | "hybrid"yesApplied search mode

CategoryRecord

Category row returned by create and update endpoints

FieldTypeRequiredDescription
idstringyesCategory ID
namestringyesCategory name
parent_idstring | nullyesParent category ID
colorstring | nullyesOptional category hex color
iconstring | nullyesOptional lowercase icon token
descriptionstring | nullyesOptional category description
slugstring | nullyesOptional category slug
is_archived0 | 1yesArchived metadata flag, 0 or 1
is_public0 | 1yesPublic visibility metadata flag, 0 or 1; local metadata only and does not expose data
created_atstringyesCreation timestamp
updated_atstringyesUpdate timestamp

CategoryWithCount

Category row with active bookmark count returned by category listings

FieldTypeRequiredDescription
idstringyesCategory ID
namestringyesCategory name
parent_idstring | nullyesParent category ID
colorstring | nullyesOptional category hex color
iconstring | nullyesOptional lowercase icon token
descriptionstring | nullyesOptional category description
slugstring | nullyesOptional category slug
is_archived0 | 1yesArchived metadata flag, 0 or 1
is_public0 | 1yesPublic visibility metadata flag, 0 or 1; local metadata only and does not expose data
created_atstringyesCreation timestamp
updated_atstringyesUpdate timestamp
bookmark_countintegeryesActive bookmark count

CategoryNode

FieldTypeRequiredDescription
idstringyesCategory ID
namestringyesCategory name
parent_idstring | nullyesParent category ID
colorstring | nullyesOptional category hex color
iconstring | nullyesOptional lowercase icon token
descriptionstring | nullyesOptional category description
slugstring | nullyesOptional category slug
is_archived0 | 1yesArchived metadata flag, 0 or 1
is_public0 | 1yesPublic visibility metadata flag, 0 or 1; local metadata only and does not expose data
created_atstringyesCreation timestamp
updated_atstringyesUpdate timestamp
bookmark_countintegeryesActive bookmark count
childrenarrayyesChild categories

CategoryRequest

FieldTypeRequiredDescription
namestringyesCategory name
parent_idstring | nullnoParent category ID
colorstring | nullnoOptional category hex color
iconstring | nullnoOptional lowercase icon token
descriptionstring | nullnoOptional category description
slugstring | nullnoOptional category slug
is_archived0 | 1noArchived metadata flag, 0 or 1
is_public0 | 1noPublic visibility metadata flag, 0 or 1; local metadata only and does not expose data

CategoryPatchRequest

FieldTypeRequiredDescription
namestringnoCategory name
parent_idstring | nullnoParent category ID
colorstring | nullnoOptional category hex color
iconstring | nullnoOptional lowercase icon token
descriptionstring | nullnoOptional category description
slugstring | nullnoOptional category slug
is_archived0 | 1noArchived metadata flag, 0 or 1
is_public0 | 1noPublic visibility metadata flag, 0 or 1; local metadata only and does not expose data

CategoryTreeResponse

Response data

FieldTypeRequiredDescription
dataarrayyesCategory tree

CategoryResponse

Response data

FieldTypeRequiredDescription
dataCategoryRecordyes
data.idstringyesCategory ID
data.namestringyesCategory name
data.parent_idstring | nullyesParent category ID
data.colorstring | nullyesOptional category hex color
data.iconstring | nullyesOptional lowercase icon token
data.descriptionstring | nullyesOptional category description
data.slugstring | nullyesOptional category slug
data.is_archived0 | 1yesArchived metadata flag, 0 or 1
data.is_public0 | 1yesPublic visibility metadata flag, 0 or 1; local metadata only and does not expose data
data.created_atstringyesCreation timestamp
data.updated_atstringyesUpdate timestamp

TagRecord

Tag row returned by create and attach endpoints

FieldTypeRequiredDescription
idstringyesTag ID
namestringyesTag name
created_atstringyesCreation timestamp

TagWithCount

Tag row with active bookmark count returned by tag listings

FieldTypeRequiredDescription
idstringyesTag ID
namestringyesTag name
created_atstringyesCreation timestamp
bookmark_countintegeryesActive bookmark count

TagRequest

FieldTypeRequiredDescription
namestringyesTag name, normalized to lowercase

TagListResponse

Response data

FieldTypeRequiredDescription
dataarrayyesTags

TagResponse

Response data

FieldTypeRequiredDescription
dataTagRecordyes
data.idstringyesTag ID
data.namestringyesTag name
data.created_atstringyesCreation timestamp

Domain

FieldTypeRequiredDescription
domainstringyesDomain
countintegeryesActive bookmark count

DomainListResponse

Response data

FieldTypeRequiredDescription
dataarrayyesDomains

ImportDuplicatePolicy

Duplicate handling policy applied to an import preview or commit

FieldTypeRequiredDescription
active"skip" | "merge"yesPolicy for active duplicate URLs
archived"skip" | "restore_merge"yesPolicy for archived duplicate URLs
trashed"skip" | "restore_merge"yesPolicy for trashed duplicate URLs

ImportFolderRemappingInput

Import folder remapping request entry

FieldTypeRequiredDescription
sourcePatharrayyesFolder path from the imported file
action"create" | "existing"yesFolder remapping action. Use create with targetPath or existing with categoryId.
categoryIdstringnoExisting category ID; required when action is existing
targetPatharraynoTarget path for create/reuse mappings. Child folders inherit remapped ancestor paths unless explicitly mapped.

ImportTagRemappingInput

Import tag remapping request entry

FieldTypeRequiredDescription
sourceTagstringyesSource tag name from the imported file
action"new" | "existing" | "renamed" | "skipped"yesTag remapping action. Use tagId for existing, targetName for new or renamed.
tagIdstringnoExisting tag ID; required when action is existing
targetNamestringnoTarget tag name for new or renamed mappings; lowercase hyphen format, max 50 characters

ImportRemappingInput

Optional import remapping request JSON. Omitted folders and tags use the daemon's default create/reuse decisions.

FieldTypeRequiredDescription
foldersarraynoFolder remapping overrides
tagsarraynoTag remapping overrides

ImportFolderMapping

Resolved import folder remapping decision

FieldTypeRequiredDescription
sourcePatharrayyesFolder path from the imported file
action"create" | "existing"yesFolder remapping action
targetCategoryIdstring | nullyesExisting target category ID when mapped to an existing category
targetPatharrayyesResolved target category path
status"new" | "existing"yesWhether the target category path already exists or will be created

ImportTagMapping

Resolved import tag remapping decision

FieldTypeRequiredDescription
sourceTagstringyesSource tag name from the imported file
action"new" | "existing" | "renamed" | "skipped"yesTag remapping action
targetTagIdstring | nullyesExisting target tag ID when reused
targetNamestring | nullyesResolved target tag name; null when skipped
status"new" | "existing" | "skipped"yesWhether the target tag exists, will be created, or is skipped

ImportRemapping

Resolved category and tag remapping decisions applied to an import preview or commit

FieldTypeRequiredDescription
foldersarrayyesResolved folder remapping decisions
tagsarrayyesResolved tag remapping decisions

ImportPreviewSummary

FieldTypeRequiredDescription
totalRowsintegeryesTotal parsed bookmark rows, including skipped invalid/private rows
importableRowsintegeryesValid public HTTP(S) bookmark rows
newintegeryesRows that would create new bookmarks
activeDuplicatesintegeryesRows matching active bookmarks
archivedDuplicatesintegeryesRows matching archived bookmarks
trashedDuplicatesintegeryesRows matching trashed bookmarks
invalidUrlsintegeryesRows skipped because the URL is malformed or not HTTP(S)
privateUrlsintegeryesRows skipped because the URL targets a private or loopback host
createdintegeryesEstimated rows created under the selected policy
mergedintegeryesEstimated active duplicate rows merged under the selected policy
restoredintegeryesEstimated archived or trashed duplicate rows restored and merged
skippedintegeryesEstimated rows skipped under the selected policy

ImportPreviewRow

FieldTypeRequiredDescription
classification"new" | "active_duplicate" | "archived_duplicate" | "trashed_duplicate" | "invalid_url" | "private_url"yesImport row classification
action"create" | "skip" | "merge" | "restore_merge"yesAction that the selected policy would apply
urlstring | nullyesSource bookmark URL
titlestringyesSource bookmark title
notesstring | nullyesSource note text when the import format provides note-like metadata
tagsarrayyesSource tag names
targetTagsarrayyesTarget tag names after remapping
foldersarrayyesSource folder path
targetCategoryIdstring | nullyesMapped target category ID when it already exists
targetCategoryPatharrayyesTarget category path after remapping
existingBookmarkIdstring | nullyesMatching existing bookmark ID
existingState"active" | "archived" | "trashed" | nullyesMatching existing bookmark state
skipReasonstring | nullyesReason the row would be skipped

ImportPreview

Non-mutating import preview

FieldTypeRequiredDescription
duplicatePolicyImportDuplicatePolicyyes
duplicatePolicy.active"skip" | "merge"yesPolicy for active duplicate URLs
duplicatePolicy.archived"skip" | "restore_merge"yesPolicy for archived duplicate URLs
duplicatePolicy.trashed"skip" | "restore_merge"yesPolicy for trashed duplicate URLs
remappingImportRemappingyes
remapping.foldersarrayyesResolved folder remapping decisions
remapping.tagsarrayyesResolved tag remapping decisions
summaryImportPreviewSummaryyes
summary.totalRowsintegeryesTotal parsed bookmark rows, including skipped invalid/private rows
summary.importableRowsintegeryesValid public HTTP(S) bookmark rows
summary.newintegeryesRows that would create new bookmarks
summary.activeDuplicatesintegeryesRows matching active bookmarks
summary.archivedDuplicatesintegeryesRows matching archived bookmarks
summary.trashedDuplicatesintegeryesRows matching trashed bookmarks
summary.invalidUrlsintegeryesRows skipped because the URL is malformed or not HTTP(S)
summary.privateUrlsintegeryesRows skipped because the URL targets a private or loopback host
summary.createdintegeryesEstimated rows created under the selected policy
summary.mergedintegeryesEstimated active duplicate rows merged under the selected policy
summary.restoredintegeryesEstimated archived or trashed duplicate rows restored and merged
summary.skippedintegeryesEstimated rows skipped under the selected policy
foldersarray<array>yesDetected Netscape folder paths
tagsarrayyesDetected tag names
warningsarrayyesParser warnings
rowsarrayyesPreview rows

ImportPreviewResponse

Response data

FieldTypeRequiredDescription
dataImportPreviewyes
data.duplicatePolicyImportDuplicatePolicyyes
data.duplicatePolicy.active"skip" | "merge"yesPolicy for active duplicate URLs
data.duplicatePolicy.archived"skip" | "restore_merge"yesPolicy for archived duplicate URLs
data.duplicatePolicy.trashed"skip" | "restore_merge"yesPolicy for trashed duplicate URLs
data.remappingImportRemappingyes
data.remapping.foldersarrayyesResolved folder remapping decisions
data.remapping.tagsarrayyesResolved tag remapping decisions
data.summaryImportPreviewSummaryyes
data.summary.totalRowsintegeryesTotal parsed bookmark rows, including skipped invalid/private rows
data.summary.importableRowsintegeryesValid public HTTP(S) bookmark rows
data.summary.newintegeryesRows that would create new bookmarks
data.summary.activeDuplicatesintegeryesRows matching active bookmarks
data.summary.archivedDuplicatesintegeryesRows matching archived bookmarks
data.summary.trashedDuplicatesintegeryesRows matching trashed bookmarks
data.summary.invalidUrlsintegeryesRows skipped because the URL is malformed or not HTTP(S)
data.summary.privateUrlsintegeryesRows skipped because the URL targets a private or loopback host
data.summary.createdintegeryesEstimated rows created under the selected policy
data.summary.mergedintegeryesEstimated active duplicate rows merged under the selected policy
data.summary.restoredintegeryesEstimated archived or trashed duplicate rows restored and merged
data.summary.skippedintegeryesEstimated rows skipped under the selected policy
data.foldersarray<array>yesDetected Netscape folder paths
data.tagsarrayyesDetected tag names
data.warningsarrayyesParser warnings
data.rowsarrayyesPreview rows

ImportResultSummary

Final committed import result counts

FieldTypeRequiredDescription
totalRowsintegeryesTotal parsed bookmark rows, including skipped invalid/private rows
importableRowsintegeryesValid public HTTP(S) bookmark rows
createdintegeryesBookmarks created by the committed import
updatedintegeryesExisting bookmarks updated by merge or restore actions
mergedintegeryesActive duplicate bookmarks merged by the committed import
restoredintegeryesArchived or trashed duplicate bookmarks restored and merged
skippedintegeryesRows skipped by validation or duplicate policy
failedintegeryesRows that failed during commit after import processing started
warningsintegeryesParser and row-level warnings included in the result report
categoriesCreatedintegeryesCategories created from imported folder paths
categoriesReusedintegeryesExisting categories reused for imported folder paths

ImportResultRow

Final committed import row result

FieldTypeRequiredDescription
status"created" | "merged" | "restored" | "skipped" | "failed"yesFinal committed row status
action"create" | "skip" | "merge" | "restore_merge"yesRequested action selected by the duplicate policy
classification"new" | "active_duplicate" | "archived_duplicate" | "trashed_duplicate" | "invalid_url" | "private_url"yesImport row classification
urlstring | nullyesSource bookmark URL
titlestringyesSource bookmark title
notesstring | nullyesSource note text when the import format provides note-like metadata
tagsarrayyesSource tag names
targetTagsarrayyesTarget tag names after remapping
foldersarrayyesSource folder path
targetCategoryIdstring | nullyesMapped target category ID when it already exists
targetCategoryPatharrayyesTarget category path after remapping
existingBookmarkIdstring | nullyesMatching existing bookmark ID from preview analysis
bookmarkIdstring | nullyesBookmark ID created or updated by the committed import row
skipReasonstring | nullyesReason the row was skipped
warningstring | nullyesUser-visible row warning, duplicate note, remapping note, or skipped-row reason
errorstring | nullyesUser-visible row error when commit processing failed for this row

ImportResultReport

Final import result report available when progress is done

FieldTypeRequiredDescription
duplicatePolicyImportDuplicatePolicyyes
duplicatePolicy.active"skip" | "merge"yesPolicy for active duplicate URLs
duplicatePolicy.archived"skip" | "restore_merge"yesPolicy for archived duplicate URLs
duplicatePolicy.trashed"skip" | "restore_merge"yesPolicy for trashed duplicate URLs
remappingImportRemappingyes
remapping.foldersarrayyesResolved folder remapping decisions
remapping.tagsarrayyesResolved tag remapping decisions
summaryImportResultSummaryyes
summary.totalRowsintegeryesTotal parsed bookmark rows, including skipped invalid/private rows
summary.importableRowsintegeryesValid public HTTP(S) bookmark rows
summary.createdintegeryesBookmarks created by the committed import
summary.updatedintegeryesExisting bookmarks updated by merge or restore actions
summary.mergedintegeryesActive duplicate bookmarks merged by the committed import
summary.restoredintegeryesArchived or trashed duplicate bookmarks restored and merged
summary.skippedintegeryesRows skipped by validation or duplicate policy
summary.failedintegeryesRows that failed during commit after import processing started
summary.warningsintegeryesParser and row-level warnings included in the result report
summary.categoriesCreatedintegeryesCategories created from imported folder paths
summary.categoriesReusedintegeryesExisting categories reused for imported folder paths
warningsarrayyesParser warnings
rowsarrayyesCommitted row results

ImportSummary

FieldTypeRequiredDescription
importIdstringyesImport ID for progress stream
totalintegeryesParsed bookmark row count
foldersintegeryesParsed Netscape folder count
warningsintegeryesParser warning count
duplicatePolicyImportDuplicatePolicyyes
duplicatePolicy.active"skip" | "merge"yesPolicy for active duplicate URLs
duplicatePolicy.archived"skip" | "restore_merge"yesPolicy for archived duplicate URLs
duplicatePolicy.trashed"skip" | "restore_merge"yesPolicy for trashed duplicate URLs
remappingImportRemappingyes
remapping.foldersarrayyesResolved folder remapping decisions
remapping.tagsarrayyesResolved tag remapping decisions
progressUrlstringyesSSE progress URL

ImportSummaryResponse

Response data

FieldTypeRequiredDescription
dataImportSummaryyes
data.importIdstringyesImport ID for progress stream
data.totalintegeryesParsed bookmark row count
data.foldersintegeryesParsed Netscape folder count
data.warningsintegeryesParser warning count
data.duplicatePolicyImportDuplicatePolicyyes
data.duplicatePolicy.active"skip" | "merge"yesPolicy for active duplicate URLs
data.duplicatePolicy.archived"skip" | "restore_merge"yesPolicy for archived duplicate URLs
data.duplicatePolicy.trashed"skip" | "restore_merge"yesPolicy for trashed duplicate URLs
data.remappingImportRemappingyes
data.remapping.foldersarrayyesResolved folder remapping decisions
data.remapping.tagsarrayyesResolved tag remapping decisions
data.progressUrlstringyesSSE progress URL

ImportProgressEvent

FieldTypeRequiredDescription
queuedintegeryesQueued bookmarks
skippedintegeryesSkipped bookmarks
mergedintegeryesExisting active bookmarks merged
restoredintegeryesExisting archived or trashed bookmarks restored and merged
failedintegeryesRows that failed during commit after import processing started
totalintegeryesTotal parsed bookmarks
foldersintegeryesTotal parsed Netscape folders
categoriesCreatedintegeryesCategories created from imported folder paths
categoriesReusedintegeryesExisting categories reused for imported folder paths
donebooleanyesWhether import processing is complete
errorstring | nullyesBackground import error
resultImportResultReport | nullyes
result.duplicatePolicyImportDuplicatePolicyyes
result.duplicatePolicy.active"skip" | "merge"yesPolicy for active duplicate URLs
result.duplicatePolicy.archived"skip" | "restore_merge"yesPolicy for archived duplicate URLs
result.duplicatePolicy.trashed"skip" | "restore_merge"yesPolicy for trashed duplicate URLs
result.remappingImportRemappingyes
result.remapping.foldersarrayyesResolved folder remapping decisions
result.remapping.tagsarrayyesResolved tag remapping decisions
result.summaryImportResultSummaryyes
result.summary.totalRowsintegeryesTotal parsed bookmark rows, including skipped invalid/private rows
result.summary.importableRowsintegeryesValid public HTTP(S) bookmark rows
result.summary.createdintegeryesBookmarks created by the committed import
result.summary.updatedintegeryesExisting bookmarks updated by merge or restore actions
result.summary.mergedintegeryesActive duplicate bookmarks merged by the committed import
result.summary.restoredintegeryesArchived or trashed duplicate bookmarks restored and merged
result.summary.skippedintegeryesRows skipped by validation or duplicate policy
result.summary.failedintegeryesRows that failed during commit after import processing started
result.summary.warningsintegeryesParser and row-level warnings included in the result report
result.summary.categoriesCreatedintegeryesCategories created from imported folder paths
result.summary.categoriesReusedintegeryesExisting categories reused for imported folder paths
result.warningsarrayyesParser warnings
result.rowsarrayyesCommitted row results

RuntimeLlmCapability

FieldTypeRequiredDescription
enabledbooleanyesWhether this runtime feature is usable
provider"openai" | "ollama" | "anthropic" | "openrouter" | "openai_compatible" | "deepseek" | "none"yesResolved provider
modelstring | nullyesResolved model
base_urlstring | nullyesResolved base URL

RuntimeEmbeddingCapability

FieldTypeRequiredDescription
enabledbooleanyesWhether this runtime feature is usable
provider"openai" | "ollama" | "openai_compatible" | "none"yesResolved embedding provider
modelstring | nullyesResolved model
base_urlstring | nullyesResolved base URL

RuntimeCapabilities

FieldTypeRequiredDescription
llmRuntimeLlmCapabilityyes
llm.enabledbooleanyesWhether this runtime feature is usable
llm.provider"openai" | "ollama" | "anthropic" | "openrouter" | "openai_compatible" | "deepseek" | "none"yesResolved provider
llm.modelstring | nullyesResolved model
llm.base_urlstring | nullyesResolved base URL
embeddingsRuntimeEmbeddingCapabilityyes
embeddings.enabledbooleanyesWhether this runtime feature is usable
embeddings.provider"openai" | "ollama" | "openai_compatible" | "none"yesResolved embedding provider
embeddings.modelstring | nullyesResolved model
embeddings.base_urlstring | nullyesResolved base URL
capabilitiesobjectyes
capabilities.enrichmentbooleanyesLLM enrichment available
capabilities.semantic_searchbooleanyesSemantic search available
capabilities.related_bookmarksbooleanyesRelated bookmarks available
capabilities.organization_agentbooleanyesOrganization agent available

SettingsBackupSchedule

FieldTypeRequiredDescription
enabledbooleanyesEnable scheduled snapshots
cronstringyesFive-part cron expression
retention_countintegeryesNumber of local snapshots to retain

Settings

FieldTypeRequiredDescription
aiobjectyes
ai.provider"openai" | "ollama" | "anthropic" | "openrouter" | "openai_compatible" | "deepseek" | "none"yesLLM provider
ai.openaiobjectyes
ai.openai.api_keystringyesRedacted OpenAI API key. Empty string means unset
ai.openai.modelstringyesOpenAI chat model
ai.ollamaobjectyes
ai.ollama.base_urlstringyesOllama base URL
ai.ollama.modelstringyesOllama model
ai.anthropicobjectyes
ai.anthropic.api_keystringyesRedacted Anthropic API key. Empty string means unset
ai.anthropic.base_urlstringyesAnthropic API base URL
ai.anthropic.modelstringyesAnthropic Messages API model
ai.openrouterobjectyes
ai.openrouter.api_keystringyesRedacted OpenRouter API key. Empty string means unset
ai.openrouter.base_urlstringyesOpenRouter OpenAI-compatible base URL
ai.openrouter.modelstringyesOpenRouter model slug
ai.openai_compatibleobjectyes
ai.openai_compatible.api_keystringyesRedacted custom OpenAI-compatible API key. Empty string means unset
ai.openai_compatible.base_urlstringyesCustom OpenAI-compatible chat base URL
ai.openai_compatible.modelstringyesCustom OpenAI-compatible chat model
ai.deepseekobjectyes
ai.deepseek.api_keystringyesRedacted DeepSeek API key. Empty string means unset
ai.deepseek.base_urlstringyesDeepSeek OpenAI-compatible base URL
ai.deepseek.modelstringyesDeepSeek chat model
ai.embeddingsobjectyes
ai.embeddings.provider"openai" | "ollama" | "openai_compatible"yesEmbedding provider
ai.embeddings.modelstringyesEmbedding model
ai.embeddings.openai_compatibleobjectyes
ai.embeddings.openai_compatible.api_keystringyesRedacted custom OpenAI-compatible embedding API key. Empty string means unset
ai.embeddings.openai_compatible.base_urlstringyesCustom OpenAI-compatible embeddings base URL
ai.embeddings.openai_compatible.modelstringyesCustom OpenAI-compatible embedding model
appobjectyes
app.autostartbooleanyesStart daemon automatically
app.theme"light" | "dark" | "system"yesUI theme
app.lockobjectyes
app.lock.enabledbooleanyesWhether app lock is enabled
app.lock.pin_hashstringyesRedacted PIN hash. Empty string means unset
backupobjectyes
backup.localobjectyes
backup.local.destination_pathstringyesAbsolute custom backup destination, or empty string for default
backup.scheduleSettingsBackupScheduleyes
backup.schedule.enabledbooleanyesEnable scheduled snapshots
backup.schedule.cronstringyesFive-part cron expression
backup.schedule.retention_countintegeryesNumber of local snapshots to retain
backup.s3objectyes
backup.s3.endpointstringyesS3-compatible endpoint URL, or empty string for AWS
backup.s3.bucketstringyesS3 bucket
backup.s3.access_keystringyesRedacted S3 access key. Empty string means unset
backup.s3.secret_keystringyesRedacted S3 secret key. Empty string means unset
backup.s3.regionstringyesS3 region
backup.s3.prefixstringyesObject key prefix
runtimeRuntimeCapabilitiesyes
runtime.llmRuntimeLlmCapabilityyes
runtime.llm.enabledbooleanyesWhether this runtime feature is usable
runtime.llm.provider"openai" | "ollama" | "anthropic" | "openrouter" | "openai_compatible" | "deepseek" | "none"yesResolved provider
runtime.llm.modelstring | nullyesResolved model
runtime.llm.base_urlstring | nullyesResolved base URL
runtime.embeddingsRuntimeEmbeddingCapabilityyes
runtime.embeddings.enabledbooleanyesWhether this runtime feature is usable
runtime.embeddings.provider"openai" | "ollama" | "openai_compatible" | "none"yesResolved embedding provider
runtime.embeddings.modelstring | nullyesResolved model
runtime.embeddings.base_urlstring | nullyesResolved base URL
runtime.capabilitiesobjectyes
runtime.capabilities.enrichmentbooleanyesLLM enrichment available
runtime.capabilities.semantic_searchbooleanyesSemantic search available
runtime.capabilities.related_bookmarksbooleanyesRelated bookmarks available
runtime.capabilities.organization_agentbooleanyesOrganization agent available

SettingsPatch

FieldTypeRequiredDescription
aiobjectno
ai.provider"openai" | "ollama" | "anthropic" | "openrouter" | "openai_compatible" | "deepseek" | "none"noLLM provider
ai.openaiobjectno
ai.openai.api_keystringnoOpenAI API key, empty string clears it
ai.openai.modelstringnoOpenAI chat model
ai.ollamaobjectno
ai.ollama.base_urlstringnoOllama base URL
ai.ollama.modelstringnoOllama model
ai.anthropicobjectno
ai.anthropic.api_keystringnoAnthropic API key, empty string clears it
ai.anthropic.base_urlstringnoAnthropic API base URL
ai.anthropic.modelstringnoAnthropic Messages API model
ai.openrouterobjectno
ai.openrouter.api_keystringnoOpenRouter API key, empty string clears it
ai.openrouter.base_urlstringnoOpenRouter OpenAI-compatible base URL
ai.openrouter.modelstringnoOpenRouter model slug
ai.openai_compatibleobjectno
ai.openai_compatible.api_keystringnoCustom OpenAI-compatible API key, empty string clears it
ai.openai_compatible.base_urlstringnoCustom OpenAI-compatible chat base URL
ai.openai_compatible.modelstringnoCustom OpenAI-compatible chat model
ai.deepseekobjectno
ai.deepseek.api_keystringnoDeepSeek API key, empty string clears it
ai.deepseek.base_urlstringnoDeepSeek OpenAI-compatible base URL
ai.deepseek.modelstringnoDeepSeek chat model
ai.embeddingsobjectno
ai.embeddings.provider"openai" | "ollama" | "openai_compatible"noEmbedding provider
ai.embeddings.modelstringnoEmbedding model
ai.embeddings.openai_compatibleobjectno
ai.embeddings.openai_compatible.api_keystringnoCustom OpenAI-compatible embedding API key, empty string clears it
ai.embeddings.openai_compatible.base_urlstringnoCustom OpenAI-compatible embeddings base URL
ai.embeddings.openai_compatible.modelstringnoCustom OpenAI-compatible embedding model
appobjectno
app.autostartbooleannoStart daemon automatically
app.theme"light" | "dark" | "system"noUI theme
app.lockobjectno
app.lock.enabledbooleannoWhether app lock is enabled
app.lock.pin_hashstringnoPIN hash, empty string clears it
backupobjectno
backup.localobjectno
backup.local.destination_pathstringnoAbsolute custom backup destination, or empty string for default
backup.scheduleobjectno
backup.schedule.enabledbooleannoEnable scheduled snapshots
backup.schedule.cronstringnoFive-part cron expression
backup.schedule.retention_countintegernoNumber of local snapshots to retain
backup.s3objectno
backup.s3.endpointstringnoS3-compatible endpoint URL, or empty string for AWS
backup.s3.bucketstringnoS3 bucket
backup.s3.access_keystringnoS3 access key
backup.s3.secret_keystringnoS3 secret key
backup.s3.regionstringnoS3 region
backup.s3.prefixstringnoObject key prefix

SettingsResponse

Response data

FieldTypeRequiredDescription
dataSettingsyes
data.aiobjectyes
data.ai.provider"openai" | "ollama" | "anthropic" | "openrouter" | "openai_compatible" | "deepseek" | "none"yesLLM provider
data.ai.openaiobjectyes
data.ai.openai.api_keystringyesRedacted OpenAI API key. Empty string means unset
data.ai.openai.modelstringyesOpenAI chat model
data.ai.ollamaobjectyes
data.ai.ollama.base_urlstringyesOllama base URL
data.ai.ollama.modelstringyesOllama model
data.ai.anthropicobjectyes
data.ai.anthropic.api_keystringyesRedacted Anthropic API key. Empty string means unset
data.ai.anthropic.base_urlstringyesAnthropic API base URL
data.ai.anthropic.modelstringyesAnthropic Messages API model
data.ai.openrouterobjectyes
data.ai.openrouter.api_keystringyesRedacted OpenRouter API key. Empty string means unset
data.ai.openrouter.base_urlstringyesOpenRouter OpenAI-compatible base URL
data.ai.openrouter.modelstringyesOpenRouter model slug
data.ai.openai_compatibleobjectyes
data.ai.openai_compatible.api_keystringyesRedacted custom OpenAI-compatible API key. Empty string means unset
data.ai.openai_compatible.base_urlstringyesCustom OpenAI-compatible chat base URL
data.ai.openai_compatible.modelstringyesCustom OpenAI-compatible chat model
data.ai.deepseekobjectyes
data.ai.deepseek.api_keystringyesRedacted DeepSeek API key. Empty string means unset
data.ai.deepseek.base_urlstringyesDeepSeek OpenAI-compatible base URL
data.ai.deepseek.modelstringyesDeepSeek chat model
data.ai.embeddingsobjectyes
data.ai.embeddings.provider"openai" | "ollama" | "openai_compatible"yesEmbedding provider
data.ai.embeddings.modelstringyesEmbedding model
data.ai.embeddings.openai_compatibleobjectyes
data.ai.embeddings.openai_compatible.api_keystringyesRedacted custom OpenAI-compatible embedding API key. Empty string means unset
data.ai.embeddings.openai_compatible.base_urlstringyesCustom OpenAI-compatible embeddings base URL
data.ai.embeddings.openai_compatible.modelstringyesCustom OpenAI-compatible embedding model
data.appobjectyes
data.app.autostartbooleanyesStart daemon automatically
data.app.theme"light" | "dark" | "system"yesUI theme
data.app.lockobjectyes
data.app.lock.enabledbooleanyesWhether app lock is enabled
data.app.lock.pin_hashstringyesRedacted PIN hash. Empty string means unset
data.backupobjectyes
data.backup.localobjectyes
data.backup.local.destination_pathstringyesAbsolute custom backup destination, or empty string for default
data.backup.scheduleSettingsBackupScheduleyes
data.backup.schedule.enabledbooleanyesEnable scheduled snapshots
data.backup.schedule.cronstringyesFive-part cron expression
data.backup.schedule.retention_countintegeryesNumber of local snapshots to retain
data.backup.s3objectyes
data.backup.s3.endpointstringyesS3-compatible endpoint URL, or empty string for AWS
data.backup.s3.bucketstringyesS3 bucket
data.backup.s3.access_keystringyesRedacted S3 access key. Empty string means unset
data.backup.s3.secret_keystringyesRedacted S3 secret key. Empty string means unset
data.backup.s3.regionstringyesS3 region
data.backup.s3.prefixstringyesObject key prefix
data.runtimeRuntimeCapabilitiesyes
data.runtime.llmRuntimeLlmCapabilityyes
data.runtime.llm.enabledbooleanyesWhether this runtime feature is usable
data.runtime.llm.provider"openai" | "ollama" | "anthropic" | "openrouter" | "openai_compatible" | "deepseek" | "none"yesResolved provider
data.runtime.llm.modelstring | nullyesResolved model
data.runtime.llm.base_urlstring | nullyesResolved base URL
data.runtime.embeddingsRuntimeEmbeddingCapabilityyes
data.runtime.embeddings.enabledbooleanyesWhether this runtime feature is usable
data.runtime.embeddings.provider"openai" | "ollama" | "openai_compatible" | "none"yesResolved embedding provider
data.runtime.embeddings.modelstring | nullyesResolved model
data.runtime.embeddings.base_urlstring | nullyesResolved base URL
data.runtime.capabilitiesobjectyes
data.runtime.capabilities.enrichmentbooleanyesLLM enrichment available
data.runtime.capabilities.semantic_searchbooleanyesSemantic search available
data.runtime.capabilities.related_bookmarksbooleanyesRelated bookmarks available
data.runtime.capabilities.organization_agentbooleanyesOrganization agent available

ConnectivityTestResponse

FieldTypeRequiredDescription
okbooleanyesWhether the connectivity check succeeded
errorstringnoFailure reason
messagestringnoSuccess message

BackupSchedule

FieldTypeRequiredDescription
enabledbooleanyesEnable scheduled snapshots
cronstringyesFive-part cron expression
retention_countintegeryesNumber of local snapshots to retain
next_run_atstring | nullyesNext scheduled run timestamp

BackupSchedulePatch

FieldTypeRequiredDescription
enabledbooleannoEnable scheduled snapshots
cronstringnoFive-part cron expression
retention_countintegernoNumber of local snapshots to retain

BackupScheduleResponse

Response data

FieldTypeRequiredDescription
dataBackupScheduleyes
data.enabledbooleanyesEnable scheduled snapshots
data.cronstringyesFive-part cron expression
data.retention_countintegeryesNumber of local snapshots to retain
data.next_run_atstring | nullyesNext scheduled run timestamp

BackupDestination

FieldTypeRequiredDescription
pathstringyesEffective backup directory
is_custombooleanyesWhether a custom destination is active
writablebooleanyesWhether the daemon can write to this directory

BackupDestinationPatch

FieldTypeRequiredDescription
pathstringyesAbsolute custom backup path, or empty string to reset

BackupDestinationResponse

Response data

FieldTypeRequiredDescription
dataBackupDestinationyes
data.pathstringyesEffective backup directory
data.is_custombooleanyesWhether a custom destination is active
data.writablebooleanyesWhether the daemon can write to this directory

BackupCreateRequest

FieldTypeRequiredDescription
skip_remotebooleannoWhen true, create only the local snapshot and skip S3 upload

BackupResult

FieldTypeRequiredDescription
pathstringyesLocal backup directory
size_bytesintegeryesSnapshot database size
bookmark_countintegeryesBookmarks included
created_atstringyesCreation timestamp
remote_urlstringnoRemote S3 URL when uploaded

BackupEntry

FieldTypeRequiredDescription
namestringyesBackup name or remote key
pathstringyesLocal path or s3:// URI
size_bytesintegeryesSnapshot database size
bookmark_countintegeryesBookmarks included
created_atstringyesCreation timestamp
source"local" | "remote"yesBackup source

BackupListResponse

Response data

FieldTypeRequiredDescription
dataarrayyesBackup entries

BackupVerifyRequest

FieldTypeRequiredDescription
namestringyesLocal backup directory name

BackupPackageRequest

FieldTypeRequiredDescription
namestringyesLocal backup directory name
passwordstringyesPassword used to encrypt the package

EncryptedBackupPackageRequest

FieldTypeRequiredDescription
pathstringyesAbsolute path to an encrypted backup package file accessible by the daemon
passwordstringyesPassword used to decrypt the package

BackupVerificationResult

FieldTypeRequiredDescription
okbooleanyesWhether verification succeeded
namestringyesLocal backup directory name
pathstringyesLocal backup directory
checksum_verifiedbooleanyesWhether checksum verification succeeded
verified_filesarrayyesVerified files
bookmark_countintegeryesBookmarks included
created_atstringyesBackup creation timestamp

EncryptedBackupPackageResult

FieldTypeRequiredDescription
pathstringyesEncrypted package file path
source_pathstringyesSource local backup directory
encryptedbooleanyesWhether the package is encrypted
size_bytesintegeryesEncrypted package size
created_atstringyesPackage creation timestamp

EncryptedBackupPackageVerificationResult

FieldTypeRequiredDescription
okbooleanyesWhether verification succeeded
pathstringyesEncrypted package file path
package_encryptedbooleanyesWhether the verified input was encrypted
checksum_verifiedbooleanyesWhether checksum verification succeeded after decryption
verified_filesarrayyesVerified files
bookmark_countintegeryesBookmarks included
created_atstringyesBackup creation timestamp

RestoreRequest

FieldTypeRequiredDescription
namestringnoLocal backup directory name
source"remote" | "encrypted_package"noRestore source
keystringnoRemote S3 snapshot.db key
pathstringnoAbsolute path to an encrypted backup package file accessible by the daemon
passwordstringnoPassword used to decrypt the encrypted package
allow_unsafe_no_checksumbooleannoAllow restoring a backup with no checksum file

RestoreResult

FieldTypeRequiredDescription
restored_atstringyesRestore timestamp
bookmark_countintegeryesRestored bookmark count
checksum_verifiedbooleanyesWhether checksum verification succeeded
rollback_pathstringyesRollback copy directory
restart_requiredbooleanyesWhether daemon restart is required
restart_commandstringyesPlatform-specific command for restarting littleimpd when detectable
health_urlstringyesLocal health endpoint to poll after restarting the daemon
rollback_instructionsarrayyesManual rollback instructions

TimelineEvent

FieldTypeRequiredDescription
idstringyesTimeline event ID
type"category_created" | "category_merged" | "category_merge_suggested" | "category_renamed" | "category_reparented" | "category_deleted" | "duplicate_removed" | "duplicate_flagged" | "cluster_labeled" | "suggestion_accepted" | "suggestion_rejected"yesTimeline event type
descriptionstringyesHuman-readable event description
metadataobjectyesEvent metadata
source"agent" | "user"yesEvent source
created_atstringyesCreation timestamp

TimelinePage

FieldTypeRequiredDescription
dataarrayyesTimeline events
paginationPaginationyes
pagination.totalintegeryesTotal matching records
pagination.limitintegeryesApplied page size
pagination.offsetintegeryesApplied offset
pagination.has_morebooleanyesWhether another page exists

Suggestion

FieldTypeRequiredDescription
idstringyesSuggestion ID
bookmarkIdstring | nullyesRelated bookmark ID
type"new_subcategory" | "merge_categories" | "duplicate_bookmark"yesSuggestion type
valuestringyesHuman-readable suggestion value
metadataobjectyesSuggestion metadata
confidencenumber | nullyesConfidence score
status"pending" | "accepted" | "rejected"yesSuggestion status
created_atstringyesCreation timestamp
resolved_atstring | nullyesResolution timestamp

SuggestionsResponse

FieldTypeRequiredDescription
dataarrayyesPending suggestions
metaobjectyes
meta.pendingintegeryesPending suggestion count

HealthResponse

FieldTypeRequiredDescription
status"ok"yesHealth status
versionstringyesDaemon package version
uptimeintegeryesProcess uptime in milliseconds
queueSizeintegeryesQueued background jobs

Diagnostics

Redacted local diagnostics payload for user-shared support bundles

FieldTypeRequiredDescription
generated_atstringyesDiagnostics generation timestamp
versionstringyesDaemon package version
platformobjectyes
platform.osstringyesOperating system platform
platform.archstringyesCPU architecture
platform.bun_versionstringyesBun runtime version
platform.node_envstringyesNode environment
platform.hoststringyesConfigured daemon bind host
platform.portintegeryesConfigured daemon port
installobjectyes
install.mode"development" | "native" | "docker"yesDetected install mode
pathsobjectyes
paths.data_dirstringyesConfigured data directory
paths.database_pathstringyesSQLite database path
paths.config_filestringyesRuntime settings file path
paths.backup_dirstringyesEffective local backup directory
paths.frontend_diststring | nullyesStatic frontend directory when served by the daemon
paths.log_filesarrayyesKnown local daemon log files
daemonobjectyes
daemon.status"ok"yesDaemon status
daemon.uptime_msintegeryesProcess uptime in milliseconds
daemon.queue_sizeintegeryesPending background jobs
daemon.queueobjectyes
daemon.queue.pendingintegeryesPending jobs
daemon.queue.runningintegeryesRunning jobs
daemon.queue.doneintegeryesCompleted jobs retained in the queue table
daemon.queue.failedintegeryesFailed jobs retained in the queue table
providersobjectyes
providers.llmobjectyes
providers.llm.providerstringyesSelected LLM provider
providers.llm.configuredbooleanyesWhether LLM enrichment can run with current settings
providers.llm.modelstring | nullyesResolved or selected LLM model
providers.llm.base_urlstring | nullyesResolved or selected LLM base URL with credentials, query strings, and fragments removed
providers.embeddingsobjectyes
providers.embeddings.providerstringyesSelected embedding provider
providers.embeddings.configuredbooleanyesWhether embedding-backed features can run with current settings
providers.embeddings.modelstring | nullyesResolved or selected embedding model
providers.embeddings.base_urlstring | nullyesResolved or selected embedding base URL with credentials, query strings, and fragments removed
backupobjectyes
backup.localobjectyes
backup.local.pathstringyesEffective local backup directory
backup.local.is_custombooleanyesWhether a custom backup destination is active
backup.local.writablebooleanyesWhether the effective local backup directory is writable
backup.scheduleBackupScheduleyes
backup.schedule.enabledbooleanyesEnable scheduled snapshots
backup.schedule.cronstringyesFive-part cron expression
backup.schedule.retention_countintegeryesNumber of local snapshots to retain
backup.schedule.next_run_atstring | nullyesNext scheduled run timestamp
backup.s3objectyes
backup.s3.configuredbooleanyesWhether enough non-secret S3 fields and stored credentials are present
backup.s3.endpointstringyesS3-compatible endpoint URL with credentials, query strings, and fragments removed; empty string for AWS
backup.s3.bucketstringyesS3 bucket
backup.s3.regionstringyesS3 region
backup.s3.prefixstringyesObject key prefix
searchobjectyes
search.keywordbooleanyesWhether keyword search is available
search.semanticbooleanyesWhether semantic search is available
search.hybridbooleanyesWhether hybrid search is available
omitted_secretsarrayyesOmitted secret classes

DiagnosticsResponse

Response data

FieldTypeRequiredDescription
dataDiagnosticsyes
data.generated_atstringyesDiagnostics generation timestamp
data.versionstringyesDaemon package version
data.platformobjectyes
data.platform.osstringyesOperating system platform
data.platform.archstringyesCPU architecture
data.platform.bun_versionstringyesBun runtime version
data.platform.node_envstringyesNode environment
data.platform.hoststringyesConfigured daemon bind host
data.platform.portintegeryesConfigured daemon port
data.installobjectyes
data.install.mode"development" | "native" | "docker"yesDetected install mode
data.pathsobjectyes
data.paths.data_dirstringyesConfigured data directory
data.paths.database_pathstringyesSQLite database path
data.paths.config_filestringyesRuntime settings file path
data.paths.backup_dirstringyesEffective local backup directory
data.paths.frontend_diststring | nullyesStatic frontend directory when served by the daemon
data.paths.log_filesarrayyesKnown local daemon log files
data.daemonobjectyes
data.daemon.status"ok"yesDaemon status
data.daemon.uptime_msintegeryesProcess uptime in milliseconds
data.daemon.queue_sizeintegeryesPending background jobs
data.daemon.queueobjectyes
data.daemon.queue.pendingintegeryesPending jobs
data.daemon.queue.runningintegeryesRunning jobs
data.daemon.queue.doneintegeryesCompleted jobs retained in the queue table
data.daemon.queue.failedintegeryesFailed jobs retained in the queue table
data.providersobjectyes
data.providers.llmobjectyes
data.providers.llm.providerstringyesSelected LLM provider
data.providers.llm.configuredbooleanyesWhether LLM enrichment can run with current settings
data.providers.llm.modelstring | nullyesResolved or selected LLM model
data.providers.llm.base_urlstring | nullyesResolved or selected LLM base URL with credentials, query strings, and fragments removed
data.providers.embeddingsobjectyes
data.providers.embeddings.providerstringyesSelected embedding provider
data.providers.embeddings.configuredbooleanyesWhether embedding-backed features can run with current settings
data.providers.embeddings.modelstring | nullyesResolved or selected embedding model
data.providers.embeddings.base_urlstring | nullyesResolved or selected embedding base URL with credentials, query strings, and fragments removed
data.backupobjectyes
data.backup.localobjectyes
data.backup.local.pathstringyesEffective local backup directory
data.backup.local.is_custombooleanyesWhether a custom backup destination is active
data.backup.local.writablebooleanyesWhether the effective local backup directory is writable
data.backup.scheduleBackupScheduleyes
data.backup.schedule.enabledbooleanyesEnable scheduled snapshots
data.backup.schedule.cronstringyesFive-part cron expression
data.backup.schedule.retention_countintegeryesNumber of local snapshots to retain
data.backup.schedule.next_run_atstring | nullyesNext scheduled run timestamp
data.backup.s3objectyes
data.backup.s3.configuredbooleanyesWhether enough non-secret S3 fields and stored credentials are present
data.backup.s3.endpointstringyesS3-compatible endpoint URL with credentials, query strings, and fragments removed; empty string for AWS
data.backup.s3.bucketstringyesS3 bucket
data.backup.s3.regionstringyesS3 region
data.backup.s3.prefixstringyesObject key prefix
data.searchobjectyes
data.search.keywordbooleanyesWhether keyword search is available
data.search.semanticbooleanyesWhether semantic search is available
data.search.hybridbooleanyesWhether hybrid search is available
data.omitted_secretsarrayyesOmitted secret classes

UpdateRelease

FieldTypeRequiredDescription
versionstringyesNormalized semantic version
tagstringyesRelease tag from the update source
namestringyesRelease display name
prereleasebooleanyesWhether the release is marked as a prerelease
published_atstringyesRelease publication timestamp
urlstringyesHuman-readable release URL

UpdateCheckResult

FieldTypeRequiredDescription
current_versionstringyesCurrent packaged Grimoire version
update_availablebooleanyesWhether a compatible release is newer than the current version
sourcestringyesRelease source URL used for the check
channel"stable" | "beta"yesApplied update channel
latestUpdateRelease | nullyes
latest.versionstringyesNormalized semantic version
latest.tagstringyesRelease tag from the update source
latest.namestringyesRelease display name
latest.prereleasebooleanyesWhether the release is marked as a prerelease
latest.published_atstringyesRelease publication timestamp
latest.urlstringyesHuman-readable release URL

UpdateCheckResponse

Response data

FieldTypeRequiredDescription
dataUpdateCheckResultyes
data.current_versionstringyesCurrent packaged Grimoire version
data.update_availablebooleanyesWhether a compatible release is newer than the current version
data.sourcestringyesRelease source URL used for the check
data.channel"stable" | "beta"yesApplied update channel
data.latestUpdateRelease | nullyes
data.latest.versionstringyesNormalized semantic version
data.latest.tagstringyesRelease tag from the update source
data.latest.namestringyesRelease display name
data.latest.prereleasebooleanyesWhether the release is marked as a prerelease
data.latest.published_atstringyesRelease publication timestamp
data.latest.urlstringyesHuman-readable release URL

ExportBookmark

FieldTypeRequiredDescription
idstringyesBookmark ID
urlstringyesBookmark URL
titlestring | nullyesTitle
summarystring | nullyesSummary
tagsarrayyesTag names
categorystring | nullyesCategory name
domainstringyesDomain
is_pinned0 | 1yesPinned flag, 0 or 1; maps Grimoire starred/favorite state
read_later0 | 1yesRead-later flag, 0 or 1
opened_countintegeryesNumber of user-triggered opens
last_opened_atstring | nullyesMost recent user-triggered open timestamp
created_atstringyesCreation timestamp
is_archived0 | 1yesArchived flag, 0 or 1; /export currently returns active rows, so emitted rows are 0
read_atstring | nullyesRead timestamp; null means unread
notesstring | nullyesPersonal notes; null when empty

IntegrationTokenRecord

Managed local integration token metadata. Full bearer token values are returned only at creation or rotation.

FieldTypeRequiredDescription
idstringyesIntegration token ID
namestringyesUser-visible integration client name
token_prefixstringyesRedacted token prefix for display and support
created_atstringyesToken creation timestamp
last_used_atstring | nullyesMost recent successful token use timestamp
revoked_atstring | nullyesToken revocation timestamp

IntegrationTokenCreateRequest

FieldTypeRequiredDescription
namestringnoUser-visible integration client name

IntegrationTokenCreateResult

One-time integration token creation or rotation result

FieldTypeRequiredDescription
tokenstringyesFull bearer token. Store it now; it is never returned by list endpoints.
recordIntegrationTokenRecordyes
record.idstringyesIntegration token ID
record.namestringyesUser-visible integration client name
record.token_prefixstringyesRedacted token prefix for display and support
record.created_atstringyesToken creation timestamp
record.last_used_atstring | nullyesMost recent successful token use timestamp
record.revoked_atstring | nullyesToken revocation timestamp

IntegrationTokenCreateResponse

Integration token creation response

FieldTypeRequiredDescription
dataIntegrationTokenCreateResultyes
data.tokenstringyesFull bearer token. Store it now; it is never returned by list endpoints.
data.recordIntegrationTokenRecordyes
data.record.idstringyesIntegration token ID
data.record.namestringyesUser-visible integration client name
data.record.token_prefixstringyesRedacted token prefix for display and support
data.record.created_atstringyesToken creation timestamp
data.record.last_used_atstring | nullyesMost recent successful token use timestamp
data.record.revoked_atstring | nullyesToken revocation timestamp

IntegrationTokenListResponse

Response data

FieldTypeRequiredDescription
dataarrayyesIntegration token records

McpErrorResponse

FieldTypeRequiredDescription
errorstringyesMCP failure message

DemoLoadResult

Demo data load result

FieldTypeRequiredDescription
dataobjectyes
data.bookmarks_createdintegeryesNumber of bookmarks created by the demo load
data.categories_createdintegeryesNumber of categories created by the demo load