Plugins API
Manage plugins, execute actions, and monitor jobs through the REST API.
Plugin Management
List Plugins
GET /v1/plugins/manage
Returns all discovered plugins with their current state (enabled/disabled), metadata, and settings.
curl http://localhost:8181/v1/plugins/manage
[
{
"name": "image-processor",
"version": "1.0.0",
"description": "Processes images using external APIs",
"enabled": true,
"settings": [
{ "name": "api_key", "type": "password", "label": "API Key", "required": true }
]
}
]
Enable Plugin
POST /v1/plugin/enable
Content-Type: application/x-www-form-urlencoded
| Parameter | Type | Description |
|---|---|---|
name | string | Plugin name to enable |
curl -X POST http://localhost:8181/v1/plugin/enable \
-d "name=image-processor"
Required settings must be saved before enabling. Returns an error if required settings are missing.
Disable Plugin
POST /v1/plugin/disable
Content-Type: application/x-www-form-urlencoded
| Parameter | Type | Description |
|---|---|---|
name | string | Plugin name to disable |
curl -X POST http://localhost:8181/v1/plugin/disable \
-d "name=image-processor"
Disabling removes all hooks, injections, pages, menus, and actions. In-flight async actions are awaited before the Lua VM is closed.
Save Plugin Settings
POST /v1/plugin/settings?name={pluginName}
Content-Type: application/json
| Parameter | Location | Type | Description |
|---|---|---|---|
name | query or form | string | Plugin name |
| (body) | JSON body | object | Setting key-value pairs |
curl -X POST "http://localhost:8181/v1/plugin/settings?name=image-processor" \
-H "Content-Type: application/json" \
-d '{
"api_key": "sk-abc123",
"model": "quality",
"max_size": 2048
}'
Settings are validated against the plugin's declared setting definitions. Unknown keys are ignored. Boolean settings must be native JSON booleans (true/false, not strings). Number settings must be native JSON numbers (2048, not "2048").
Purge Plugin Data
Delete all key-value store data for a plugin. The plugin must be disabled before purging.
POST /v1/plugin/purge-data
Content-Type: application/x-www-form-urlencoded
| Parameter | Type | Description |
|---|---|---|
name | string | Plugin name to purge data for |
curl -X POST http://localhost:8181/v1/plugin/purge-data \
-d "name=image-processor"
Response:
{
"ok": true,
"name": "image-processor"
}
Purging deletes all KV store entries for the plugin. This action is irreversible. The plugin must be disabled first; attempting to purge an enabled plugin returns an error.
Plugin Actions
List Available Actions
GET /v1/plugin/actions
| Parameter | Type | Required | Description |
|---|---|---|---|
entity | string | Yes | "resource", "note", or "group" |
content_type | string | No | Filter by Resource content type |
category_id | uint | No | Filter by Group Category ID |
note_type_id | uint | No | Filter by Note Type ID |
curl "http://localhost:8181/v1/plugin/actions?entity=resource&content_type=image/jpeg"
[
{
"plugin_name": "image-processor",
"id": "colorize",
"label": "Colorize Image",
"entity": "resource",
"placement": ["detail", "card"],
"async": true,
"params": [
{ "name": "style", "type": "select", "label": "Style", "options": ["realistic", "artistic"] }
]
}
]
Run an Action
POST /v1/jobs/action/run
Content-Type: application/json
{
"plugin": "image-processor",
"action": "colorize",
"entity_ids": [42],
"params": {
"style": "realistic"
}
}
Sync actions return 200 OK:
{
"success": true,
"message": "Image colorized",
"redirect": "/resource?id=42"
}
Async actions return 202 Accepted:
{
"job_id": "a1b2c3d4e5f6g7h8"
}
Bulk execution (multiple entity_ids) returns wrapped results:
- Sync actions:
{ "results": [...] } - Async actions:
{ "job_ids": [...] }
The bulk_max limit on the action registration is enforced.
Get Action Job Status
GET /v1/jobs/action/job
| Parameter | Type | Description |
|---|---|---|
id | string | Job ID |
curl "http://localhost:8181/v1/jobs/action/job?id=a1b2c3d4e5f6g7h8"
{
"id": "a1b2c3d4e5f6g7h8",
"source": "plugin",
"pluginName": "image-processor",
"actionId": "colorize",
"label": "Colorize Image",
"entityId": 42,
"entityType": "resource",
"status": "running",
"progress": 65,
"message": "Applying color model...",
"createdAt": "2025-03-01T10:30:00Z"
}
Plugin Block Rendering
GET /v1/plugins/{pluginName}/block/render
Renders a plugin-defined block type as an HTML fragment. The block editor's frontend calls this endpoint to display plugin blocks.
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
pluginName | path | string | Yes | The plugin that registered the block type |
blockId | query | integer | Yes | The block to render |
mode | query | string | Yes | "view" or "edit" |
curl "http://localhost:8181/v1/plugins/my-plugin/block/render?blockId=42&mode=view"
Returns text/html content. The block's type must start with plugin:<pluginName>:, otherwise a 400 error is returned.
See Custom Block Types for details on how plugin block rendering works.
Plugin Pages
GET|POST /plugins/{pluginName}/{path}
Plugin-registered pages are served at this path. The response is HTML generated by the plugin's page handler.
curl http://localhost:8181/plugins/image-processor/dashboard
Plugin JSON API Endpoints
GET|POST|PUT|DELETE /v1/plugins/{pluginName}/{path}
Plugin-registered JSON API endpoints. Unlike plugin pages (which return HTML), these return application/json responses.
# GET endpoint
curl http://localhost:8181/v1/plugins/my-plugin/stats
# POST with JSON body
curl -X POST http://localhost:8181/v1/plugins/my-plugin/webhook \
-H "Content-Type: application/json" \
-d '{"event": "test"}'
Success Response:
{
"total_notes": 42,
"query": { "page": "1" }
}
Error Responses:
| Status | Condition | Body |
|---|---|---|
| 400 | Handler called mah.abort() | {"error": "reason"} |
| 404 | Plugin not found or path not registered | {"error": "plugin not found"} or {"error": "endpoint not found"} |
| 405 | Path exists but method not registered | {"error": "method not allowed"} |
| 500 | Handler runtime error | {"error": "internal plugin error"} |
| 504 | Handler exceeded timeout | {"error": "handler timed out"} |
See Plugin Lua API Reference for the mah.api() registration function.
Unified Job Endpoints
The queue endpoint returns download jobs only. Plugin action jobs appear in the SSE event stream alongside download events.
List Download Jobs
GET /v1/jobs/queue
curl http://localhost:8181/v1/jobs/queue
Returns the retained download jobs currently held in the queue manager, including completed, failed, cancelled, or paused jobs until their retention window expires. Plugin action jobs are not included here; they are available only via the SSE event stream below.
SSE Event Stream
GET /v1/jobs/events
Server-Sent Events stream for all job types. The stream uses SSE event names to distinguish job types.
Download events use event names added, updated, removed:
event: updated
data: {"type":"updated","job":{"id":"abcd1234","status":"downloading","progress":45}}
Plugin action events use event names action_added, action_updated, action_removed:
event: action_updated
data: {"job":{"id":"a1b2c3d4e5f6g7h8","source":"plugin","status":"running","progress":65}}
Initialization: On connect, an init event is sent with all current jobs:
event: init
data: {"jobs":[...],"actionJobs":[...]}