Skip to main content

Tags, Categories, Queries & More

This page covers Tags, Categories, Resource Categories, Queries, Search, Logs, and Download Queue endpoints.


Tags API

Tags are labels that can be applied to resources, notes, and groups for organization.

List Tags

GET /v1/tags

Query Parameters

ParameterTypeDescription
pageintegerPage number (default: 1)
NamestringFilter by name (partial match)
DescriptionstringFilter by description
CreatedBeforestringFilter by creation date
CreatedAfterstringFilter by creation date
SortBystring[]Sort order

Example

curl http://localhost:8181/v1/tags

# Search for tags
curl "http://localhost:8181/v1/tags?Name=project"

Response

[
{
"ID": 1,
"Name": "important",
"Description": "High priority items",
"CreatedAt": "2024-01-01T00:00:00Z"
}
]

Create or Update Tag

POST /v1/tag

Parameters

ParameterTypeDescription
IDintegerTag ID (include to update)
NamestringTag name
DescriptionstringDescription

Example

# Create
curl -X POST http://localhost:8181/v1/tag \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"Name": "urgent", "Description": "Requires immediate attention"}'

# Update
curl -X POST http://localhost:8181/v1/tag \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"ID": 1, "Name": "critical", "Description": "Updated description"}'

Delete Tag

POST /v1/tag/delete?Id={id}

Bulk Delete Tags

Delete multiple tags at once.

POST /v1/tags/delete

Parameters

ParameterTypeDescription
IDinteger[]Tag IDs to delete

Merge Tags

Merge multiple tags into one, transferring all associations.

POST /v1/tags/merge

Parameters

ParameterTypeDescription
WinnerintegerTag ID to keep
Losersinteger[]Tag IDs to merge and delete

Inline Editing

POST /v1/tag/editName?id={id}
POST /v1/tag/editDescription?id={id}

Categories API

Categories define types for groups with optional display customizations.

List Categories

GET /v1/categories

Query Parameters

ParameterTypeDescription
pageintegerPage number (default: 1)
NamestringFilter by name
DescriptionstringFilter by description

Example

curl http://localhost:8181/v1/categories

Response

[
{
"ID": 1,
"Name": "Person",
"Description": "Individual people",
"CustomHeader": "...",
"CustomSidebar": "...",
"CustomSummary": "...",
"CustomAvatar": "...",
"MetaSchema": "..."
}
]

Create or Update Category

POST /v1/category

Parameters

ParameterTypeDescription
IDintegerCategory ID (include to update)
NamestringCategory name
DescriptionstringDescription
CustomHeaderstringCustom header template
CustomSidebarstringCustom sidebar template
CustomSummarystringCustom summary template
CustomAvatarstringCustom avatar template
MetaSchemastringJSON schema for metadata validation

Example

curl -X POST http://localhost:8181/v1/category \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"Name": "Company",
"Description": "Business organizations"
}'

Delete Category

POST /v1/category/delete?Id={id}

Inline Editing

POST /v1/category/editName?id={id}
POST /v1/category/editDescription?id={id}

Resource Categories API

Resource categories define types for resources with optional display customizations and metadata schemas.

List Resource Categories

GET /v1/resourceCategories

Query Parameters

ParameterTypeDescription
pageintegerPage number (default: 1)
NamestringFilter by name
DescriptionstringFilter by description

Example

curl http://localhost:8181/v1/resourceCategories

Response

[
{
"ID": 1,
"Name": "Photo",
"Description": "Photograph files",
"CustomHeader": "...",
"CustomSidebar": "...",
"CustomSummary": "...",
"CustomAvatar": "...",
"MetaSchema": "..."
}
]

Create or Update Resource Category

POST /v1/resourceCategory

Parameters

ParameterTypeDescription
IDintegerResource category ID (include to update)
NamestringResource category name
DescriptionstringDescription
CustomHeaderstringCustom header template
CustomSidebarstringCustom sidebar template
CustomSummarystringCustom summary template
CustomAvatarstringCustom avatar template
MetaSchemastringJSON schema for metadata validation

Example

curl -X POST http://localhost:8181/v1/resourceCategory \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"Name": "Photo",
"Description": "Photograph files"
}'

Delete Resource Category

POST /v1/resourceCategory/delete?Id={id}

Inline Editing

POST /v1/resourceCategory/editName?id={id}
POST /v1/resourceCategory/editDescription?id={id}

Queries API

Queries are saved SQL queries that can be executed to generate custom reports. For database-level write protection, configure DB_READONLY_DSN as a truly read-only connection; otherwise query execution is not database-enforced read-only.

List Queries

GET /v1/queries

Query Parameters

ParameterTypeDescription
pageintegerPage number (default: 1)
NamestringFilter by name
TextstringFilter by query text

Example

curl http://localhost:8181/v1/queries

Get Single Query

GET /v1/query?id={id}

Create or Update Query

POST /v1/query

Parameters

ParameterTypeDescription
IDintegerQuery ID (include to update)
NamestringQuery name
TextstringSQL query text
TemplatestringDisplay template

Example

curl -X POST http://localhost:8181/v1/query \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"Name": "Recent Resources",
"Text": "SELECT * FROM resources ORDER BY created_at DESC LIMIT 10"
}'

Delete Query

POST /v1/query/delete?Id={id}

Run Query

Execute a saved query and get results.

POST /v1/query/run

Query Parameters

ParameterTypeDescription
idintegerQuery ID to run
namestringQuery name to run (alternative to id)

Example

# Run by ID
curl -X POST "http://localhost:8181/v1/query/run?id=1" \
-H "Accept: application/json"

# Run by name
curl -X POST "http://localhost:8181/v1/query/run?name=Recent%20Resources" \
-H "Accept: application/json"

Get Database Schema

Return the database table and column schema. Useful for writing saved queries.

GET /v1/query/schema

Example

curl http://localhost:8181/v1/query/schema

The response is cached for 5 minutes.

Inline Editing

POST /v1/query/editName?id={id}
POST /v1/query/editDescription?id={id}

Global Search API

Search across entity types: resources, notes, groups, tags, categories, queries, relation types, note types, and resource categories.

GET /v1/search

Query Parameters

ParameterTypeDescription
qstringRequired. Search query
limitintegerMaximum results (default: 20, max: 200)
typesstringEntity types to search (comma-separated: resource, note, group, tag, category, query, relationType, noteType, resourceCategory)

Example

# Search everything
curl "http://localhost:8181/v1/search?q=project"

# Search with limit
curl "http://localhost:8181/v1/search?q=project&limit=50"

# Search specific types
curl "http://localhost:8181/v1/search?q=project&types=resource,note"

Response

{
"query": "project",
"total": 15,
"results": [
{
"id": 1,
"type": "group",
"name": "Project Alpha",
"description": "Main project group",
"score": 100,
"url": "/group?id=1",
"extra": {"category": "Project"}
},
{
"id": 5,
"type": "resource",
"name": "project-plan.pdf",
"description": "Project planning document",
"score": 85,
"url": "/resource?id=5"
}
]
}

Logs API

Query the audit log of system events and entity changes.

List Log Entries

GET /v1/logs

Query Parameters

ParameterTypeDescription
pageintegerPage number (default: 1)
LevelstringFilter by level (info, warning, error)
ActionstringFilter by action (create, update, delete, system)
EntityTypestringFilter by entity type
EntityIDintegerFilter by entity ID
MessagestringSearch in message (partial match)
RequestPathstringSearch in request path
CreatedBeforestringFilter by date
CreatedAfterstringFilter by date
SortBystring[]Sort order

Example

# List recent logs
curl http://localhost:8181/v1/logs

# Filter by action
curl "http://localhost:8181/v1/logs?Action=create"

# Filter by entity type
curl "http://localhost:8181/v1/logs?EntityType=resource"

# Filter errors only
curl "http://localhost:8181/v1/logs?Level=error"

Response

{
"logs": [
{
"id": 100,
"createdAt": "2024-01-15T10:30:00Z",
"level": "info",
"action": "create",
"entityType": "resource",
"entityId": 456,
"entityName": "photo.jpg",
"message": "Resource created: photo.jpg",
"requestPath": "/v1/resource"
}
],
"totalCount": 1500,
"page": 1,
"perPage": 50
}

Get Single Log Entry

GET /v1/log?id={id}

Get Entity History

Get all log entries for a specific entity.

GET /v1/logs/entity

Query Parameters

ParameterTypeDescription
entityTypestringRequired. Entity type (tag, note, resource, group)
entityIdintegerRequired. Entity ID
pageintegerPage number (default: 1)

Example

# Get history for a specific resource
curl "http://localhost:8181/v1/logs/entity?entityType=resource&entityId=123"

Download Queue API

Queue background downloads for remote resources. The queue holds up to 100 jobs and runs up to 3 concurrently. Completed jobs are retained for 1 hour before eviction.

The canonical route family is /v1/jobs/*. Legacy /v1/download/* aliases remain available for compatibility.

Submit Download

Add URLs to the download queue.

POST /v1/jobs/download/submit

Parameters

Same as POST /v1/resource/remote, but always queues for background download.

Submit multiple URLs by separating them with newlines in the URL field. Each URL becomes a separate job.

Example

curl -X POST http://localhost:8181/v1/jobs/download/submit \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"URL": "https://example.com/file1.zip\nhttps://example.com/file2.zip",
"OwnerId": 5
}'

Legacy alias: POST /v1/download/submit

Get Download Queue

Get all download jobs.

GET /v1/jobs/queue

Example

curl http://localhost:8181/v1/jobs/queue

Legacy alias: GET /v1/download/queue

Response

{
"jobs": [
{
"id": "job-123",
"url": "https://example.com/file.zip",
"status": "downloading",
"progress": 45,
"totalSize": 1048576,
"progressPercent": 4.29,
"createdAt": "2024-01-15T10:00:00Z",
"source": "download"
}
]
}

Job Operations

EndpointDescription
POST /v1/jobs/cancel?id={job_id}Cancel a pending or in-progress download
POST /v1/jobs/pause?id={job_id}Pause a download job
POST /v1/jobs/resume?id={job_id}Resume a paused download (restarts from the beginning)
POST /v1/jobs/retry?id={job_id}Retry a failed or cancelled download

Downloads can fail due to network errors, connection timeouts (default 30s), idle timeouts (default 60s), or exceeding the overall timeout (default 30m). Configure these with the -remote-connect-timeout, -remote-idle-timeout, and -remote-overall-timeout flags.

Legacy aliases remain available under /v1/download/cancel, /v1/download/pause, /v1/download/resume, and /v1/download/retry.

Download Events (SSE)

Stream real-time download status updates via Server-Sent Events.

GET /v1/jobs/events

Example

The server emits named events, so you must use addEventListener (not onmessage):

EventDescription
initFull initial state with all current jobs ({ jobs: [...], actionJobs: [...] })
addedA new download job was queued
updatedA download job changed status or progress
removedA download job was removed from the queue
action_addedA plugin action job was created
action_updatedA plugin action job changed status
action_removedA plugin action job was removed
const eventSource = new EventSource('http://localhost:8181/v1/jobs/events');

// Receive full initial state (all current jobs)
eventSource.addEventListener('init', (event) => {
const { jobs, actionJobs } = JSON.parse(event.data);
console.log('Initial download jobs:', jobs);
console.log('Initial action jobs:', actionJobs);
});

// Download job updates
eventSource.addEventListener('added', (event) => {
const { type, job } = JSON.parse(event.data);
console.log('New download job:', job);
});

eventSource.addEventListener('updated', (event) => {
const { type, job } = JSON.parse(event.data);
console.log('Download job updated:', job.id, job.status, job.progressPercent + '%');
});

eventSource.addEventListener('removed', (event) => {
const { type, job } = JSON.parse(event.data);
console.log('Download job removed:', job.id);
});

// Plugin action job updates (prefixed with "action_")
eventSource.addEventListener('action_updated', (event) => {
const { job } = JSON.parse(event.data);
console.log('Action job updated:', job);
});

Legacy alias: GET /v1/download/events


Series API

A series groups related resources into an ordered sequence (e.g., pages of a scanned document, frames of an animation).

List Series

GET /v1/seriesList

Query Parameters

ParameterTypeDescription
pageintegerPage number for pagination
NamestringFilter by name (partial match)
SlugstringFilter by slug
CreatedBeforestringFilter by creation date (ISO 8601)
CreatedAfterstringFilter by creation date (ISO 8601)
SortBystring[]Sort order

Get Single Series

GET /v1/series?id={id}

Create Series

POST /v1/series/create

Parameters

ParameterTypeDescription
NamestringRequired. Series name

Update Series

POST /v1/series

Parameters

ParameterTypeDescription
IDintegerRequired. Series ID
NamestringNew name
MetastringJSON metadata

Delete Series

POST /v1/series/delete?Id={id}

Remove Resource from Series

POST /v1/resource/removeSeries?id={resourceId}

Removes a resource from its series without deleting the series itself.


Meta Keys Endpoints

Get all unique metadata keys used across entities.

EntityEndpoint
ResourcesGET /v1/resources/meta/keys
NotesGET /v1/notes/meta/keys
GroupsGET /v1/groups/meta/keys

Each returns an array of strings representing all metadata keys in use:

["author", "source", "date_created", "location"]