The frontend called checkMajoorVersion() unconditionally on startup, and the backend /mjr/am/releases endpoint made outbound requests to api.github.com to power it. This violates the no-internet-requests policy for core ComfyUI code, even for update checks framed as diagnostic or opt-out. Removes the endpoint, the frontend check, the now-dead version-update badge dot in HeaderSection.vue, and associated tests/docs.
25 KiB
Majoor API Reference
Base Path: /mjr/am
Version: 2.4.9
Last Updated: April 7, 2026
Compatibility
Versioning
- Current API:
/mjr/am/*(unversioned, stable) - Version Alias:
/mjr/am/v1/*→ redirects to/mjr/am/*(308 Permanent Redirect) - Legacy Alias:
/majoor/version→ redirects to/mjr/am/version
Authentication
Most endpoints require authentication when ComfyUI auth is enabled:
- Read operations: May work without auth (depends on configuration)
- Write operations: Require authentication or API token
- CSRF Protection: All state-changing endpoints require
X-Requested-With: XMLHttpRequestorX-CSRF-Token
API Token
For remote access or when MAJOOR_API_TOKEN is configured:
X-MJR-Token: <your-token>
# OR
Authorization: Bearer <your-token>
Table of Contents
- Health & Diagnostics
- Settings & Configuration
- Search & Discovery
- Asset Operations
- Indexing & Scanning
- Collections & Custom Roots
- Viewer & Metadata
- Download & Export
- Database Maintenance
- Utilities
Health & Diagnostics
Health Summary
GET /mjr/am/health
Response: Extension health summary including version, status, and basic metrics.
{
"ok": true,
"data": {
"version": "2.4.9",
"status": "healthy",
"indexed_count": 1234,
"scopes_available": ["output", "input", "custom", "collections"]
}
}
Health Counters
GET /mjr/am/health/counters
Response: Indexed counters for all scopes.
{
"ok": true,
"data": {
"output": { "count": 1000, "last_scan": "2026-02-28T10:00:00Z" },
"input": { "count": 200, "last_scan": "2026-02-28T10:00:00Z" },
"custom": { "count": 34, "last_scan": "2026-02-28T10:00:00Z" },
"collections": { "count": 5 }
}
}
Database Health
GET /mjr/am/health/db
Response: Database diagnostics including schema version, integrity status, and statistics.
{
"ok": true,
"data": {
"schema_version": 7,
"integrity_check": "ok",
"page_count": 1024,
"freelist_count": 128,
"cache_size": 2000
}
}
Runtime Configuration
GET /mjr/am/config
Response: Current runtime configuration snapshot.
{
"ok": true,
"data": {
"output_directory": "/path/to/output",
"index_directory": "/path/to/_mjr_index",
"media_probe_backend": "auto",
"db_timeout": 30.0,
"max_connections": 8,
"safe_mode": true,
"allow_symlinks": false
}
}
Version Information
GET /mjr/am/version
Response: Extension version and build information.
{
"ok": true,
"data": {
"version": "2.4.9",
"branch": "main",
"build_date": "2026-03-29",
"python_version": "3.11.0",
"comfyui_version": "0.13.0"
}
}
Tool Status
GET /mjr/am/tools/status
Response: Availability status of external tools (ExifTool, FFprobe).
{
"ok": true,
"data": {
"exiftool": { "available": true, "version": "12.40" },
"ffprobe": { "available": true, "version": "6.0" },
"backend": "both"
}
}
Settings & Configuration
Probe Backend Settings
GET /mjr/am/settings/probe-backend
POST /mjr/am/settings/probe-backend
GET: Read current probe mode. POST: Set probe mode.
Request Body (POST):
{
"mode": "auto" // "auto", "exiftool", "ffprobe", "both"
}
Response:
{
"ok": true,
"data": {
"mode": "auto",
"available": ["exiftool", "ffprobe"]
}
}
Output Directory Override
GET /mjr/am/settings/output-directory
POST /mjr/am/settings/output-directory
GET: Read output directory override. POST: Set output directory override.
Request Body (POST):
{
"path": "/path/to/custom/output"
}
Response:
{
"ok": true,
"data": {
"path": "/path/to/custom/output",
"exists": true,
"writable": true
}
}
Index Directory Override
GET /mjr/am/settings/index-directory
POST /mjr/am/settings/index-directory
GET: Read the current index directory path.
Response:
{
"ok": true,
"data": {
"index_directory": "/path/to/_mjr_index"
}
}
POST: Set a new index directory path.
Requires write access (loopback or valid
X-MJR-Token).
Request Body (POST):
{
"index_directory": "/path/to/local/mjr_index"
}
Send an empty string to clear the override and revert to the default (<output>/_mjr_index/):
{
"index_directory": ""
}
Response (POST):
{
"ok": true,
"data": {
"index_directory": "/path/to/local/mjr_index",
"requires_restart": true
}
}
The new path is persisted to the .mjr_index_directory_override sidecar file and the in-process environment variables. The change takes effect after ComfyUI is restarted.
Error codes:
| Code | Meaning |
|---|---|
INVALID_INPUT |
Path exists but is a file, not a directory |
INVALID_INPUT |
Path was given as a non-empty string but the parent directory does not exist |
DB_ERROR |
Sidecar file could not be written |
Metadata Fallback Toggles
GET /mjr/am/settings/metadata-fallback
POST /mjr/am/settings/metadata-fallback
GET: Read fallback toggles for metadata extraction. POST: Set fallback toggles.
Request Body (POST):
{
"image": true, // Use internal parser if ExifTool fails
"media": true // Use hachoir if ffprobe unavailable
}
Response:
{
"ok": true,
"data": {
"image": true,
"media": true
}
}
Search & Discovery
Search with Filters
GET /mjr/am/search
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
q |
string | Search query (full-text) |
scope |
string | Scope: output, input, custom, collections |
root_id |
string | Custom root ID (for custom scope) |
collection_id |
string | Collection ID (for collections scope) |
kind |
string | File kind: image, video, audio, model3d, all |
min_rating |
integer | Minimum rating (0-5) |
workflow |
boolean | Filter by workflow presence |
date_from |
string | Start date (ISO 8601) |
date_to |
string | End date (ISO 8601) |
size_from |
integer | Minimum file size (bytes) |
size_to |
integer | Maximum file size (bytes) |
width_from |
integer | Minimum image width |
width_to |
integer | Maximum image width |
height_from |
integer | Minimum image height |
height_to |
integer | Maximum image height |
sort |
string | Sort field: relevance, name, date, size, rating |
order |
string | Sort order: asc, desc |
page |
integer | Page number (1-based) |
page_size |
integer | Items per page (default: 50) |
hide_png_siblings |
boolean | Hide PNGs when video exists |
Example:
GET /mjr/am/search?q=fantasy&scope=output&kind=image&min_rating=4&sort=date&order=desc&page=1&page_size=50
Response:
{
"ok": true,
"data": {
"total": 150,
"page": 1,
"page_size": 50,
"total_pages": 3,
"items": [
{
"id": "asset_123",
"filename": "fantasy_character.png",
"path": "/path/to/output/fantasy_character.png",
"type": "image",
"size": 2048576,
"width": 1024,
"height": 1536,
"rating": 5,
"tags": ["fantasy", "character"],
"created_at": "2026-02-28T10:00:00Z",
"metadata": {
"prompt": "A fantasy character...",
"model": "SDXL",
"steps": 30
}
}
]
}
}
List Assets (Paginated)
GET /mjr/am/list
Query Parameters: Same as search, but without q parameter.
Purpose: List assets without full-text search (faster for browsing).
Asset Details
GET /mjr/am/asset/{asset_id}
Response: Full asset details including metadata.
{
"ok": true,
"data": {
"id": "asset_123",
"filename": "fantasy_character.png",
"path": "/path/to/output/fantasy_character.png",
"type": "image",
"extension": "png",
"size": 2048576,
"width": 1024,
"height": 1536,
"rating": 5,
"tags": ["fantasy", "character"],
"created_at": "2026-02-28T10:00:00Z",
"modified_at": "2026-02-28T10:00:00Z",
"metadata": {
"prompt": "A fantasy character...",
"negative_prompt": "ugly, blurry",
"model": "SDXL",
"sampler": "DPM++ 2M Karras",
"steps": 30,
"cfg_scale": 7.0,
"seed": 123456789,
"workflow": { ... }
},
"thumbnails": {
"small": "/mjr/am/thumbnail/asset_123?size=small",
"medium": "/mjr/am/thumbnail/asset_123?size=medium",
"large": "/mjr/am/thumbnail/asset_123?size=large"
}
}
}
Metadata Lookup
GET /mjr/am/metadata
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
type |
string | Scope type: output, input, custom |
filename |
string | Filename |
subfolder |
string | Subfolder path (optional) |
root_id |
string | Custom root ID (for custom scope) |
Example:
GET /mjr/am/metadata?type=output&filename=image.png&subfolder=2026-02-28
Response:
{
"ok": true,
"data": {
"filename": "image.png",
"path": "/path/to/output/2026-02-28/image.png",
"metadata": { ... }
}
}
Asset Operations
Update Rating
POST /mjr/am/asset/rating
Request Body:
{
"asset_id": "asset_123",
"rating": 5 // 0-5
}
Response:
{
"ok": true,
"data": {
"asset_id": "asset_123",
"rating": 5,
"synced_to_file": true
}
}
Update Tags
POST /mjr/am/asset/tags
Request Body:
{
"asset_id": "asset_123",
"tags": ["fantasy", "character", "sdxl"]
}
Response:
{
"ok": true,
"data": {
"asset_id": "asset_123",
"tags": ["fantasy", "character", "sdxl"],
"synced_to_file": true
}
}
Rename Asset
POST /mjr/am/asset/rename
Request Body:
{
"asset_id": "asset_123",
"new_filename": "new_name.png"
}
Response:
{
"ok": true,
"data": {
"asset_id": "asset_123",
"old_path": "/path/to/old_name.png",
"new_path": "/path/to/new_name.png"
}
}
Note: Requires MAJOOR_ALLOW_RENAME=1 if Safe Mode is enabled.
Delete Single Asset
POST /mjr/am/asset/delete
Request Body:
{
"asset_id": "asset_123"
}
Response:
{
"ok": true,
"data": {
"asset_id": "asset_123",
"deleted": true,
"path": "/path/to/deleted_file.png"
}
}
Note: Requires MAJOOR_ALLOW_DELETE=1 if Safe Mode is enabled.
Bulk Delete Assets
POST /mjr/am/assets/delete
Request Body:
{
"asset_ids": ["asset_123", "asset_124", "asset_125"]
}
Response:
{
"ok": true,
"data": {
"deleted_count": 3,
"deleted_ids": ["asset_123", "asset_124", "asset_125"],
"failed": []
}
}
Note: Requires MAJOOR_ALLOW_DELETE=1 if Safe Mode is enabled.
Open in Folder
POST /mjr/am/open-in-folder
Request Body:
{
"asset_id": "asset_123"
}
or:
{
"filepath": "/absolute/path/to/file.png"
}
Response:
{
"ok": true,
"data": {
"asset_id": "asset_123",
"path": "/path/to/output",
"opened": true
}
}
Note: Requires MAJOOR_ALLOW_OPEN_IN_FOLDER=1 if Safe Mode is enabled. This route only asks the OS file manager to reveal an existing local file; it does not read, write, delete, or download file contents. Because of that, filepath targets are not restricted to indexed or configured asset roots for this action.
Collect Files
POST /mjr/am/collect-files
Bundles an asset, its embedded workflow, the traced prompt text, and all media inputs referenced by the workflow into a ZIP written next to the asset. See COLLECT_FILES.md for the full guide.
Request Body:
{
"filepath": "/absolute/path/to/file.png"
}
Response:
{
"ok": true,
"data": {
"zip_path": "/path/to/output/render_collected.zip",
"zip_name": "render_collected.zip",
"directory": "/path/to/output",
"fallback_used": false,
"copied": 3,
"missing": [],
"inputs": [{ "name": "photo.png", "path": "/path/to/input/photo.png", "status": "ok" }],
"models": [{ "name": "sdxl.safetensors", "path": "/path/to/checkpoints/sdxl.safetensors", "status": "located" }],
"has_workflow": true,
"has_prompt": true,
"has_prompt_text": true
}
}
Notes:
filepathmust resolve inside the ComfyUI output/input directories or a registered custom root.- When the asset folder is not writable, the ZIP falls back to
output/_mjr_collected/andfallback_usedistrue. - Model files are listed in the manifest with resolved paths but never copied into the ZIP.
- Rate limited (10 requests/minute) and requires write access.
Stage to Input
POST /mjr/am/stage-to-input
Request Body:
{
"asset_id": "asset_123"
}
Response:
{
"ok": true,
"data": {
"asset_id": "asset_123",
"staged_path": "/path/to/input/staged_file.png",
"staged": true
}
}
Purpose: Copy/link asset to ComfyUI input directory for workflow use.
Indexing & Scanning
Scan Scope/Root
POST /mjr/am/scan
Request Body:
{
"scope": "output", // "output", "input", "custom"
"root_id": null, // Custom root ID (for custom scope)
"incremental": true, // Incremental scan (default)
"force": false // Force full rescan
}
Response:
{
"ok": true,
"data": {
"scan_id": "scan_123",
"scope": "output",
"status": "started",
"estimated_duration_ms": 5000
}
}
Note: Scan runs in background. Status available via health endpoints.
Index Explicit Files
POST /mjr/am/index-files
Request Body:
{
"files": [
{
"filename": "image.png",
"subfolder": "2026-02-28",
"type": "output"
}
],
"origin": "generation" // "generation", "manual", "import"
}
Response:
{
"ok": true,
"data": {
"indexed_count": 1,
"failed": []
}
}
Purpose: Index specific files (used for real-time generation tracking).
Reset Index
POST /mjr/am/index/reset
Request Body:
{
"scope": "output", // Scope to reset
"clear_assets": true, // Clear asset records
"clear_metadata": true, // Clear metadata cache
"clear_fts": true, // Clear full-text search index
"clear_journal": true // Clear scan journal
}
Response:
{
"ok": true,
"data": {
"scope": "output",
"reset": true,
"rescan_triggered": true
}
}
Collections & Custom Roots
List Collections
GET /mjr/am/collections
Response:
{
"ok": true,
"data": {
"collections": [
{
"id": "collection_123",
"name": "Best Characters",
"item_count": 25,
"created_at": "2026-02-28T10:00:00Z",
"modified_at": "2026-02-28T12:00:00Z"
}
]
}
}
Create/Update Collection
POST /mjr/am/collections/create
POST /mjr/am/collections/update
Request Body (Create):
{
"name": "Best Characters",
"items": [
{
"asset_id": "asset_123",
"scope": "output"
}
]
}
Request Body (Update):
{
"collection_id": "collection_123",
"name": "Updated Name",
"items": [...],
"add_items": [...], // Items to add
"remove_items": [...] // Items to remove
}
Response:
{
"ok": true,
"data": {
"collection_id": "collection_123",
"name": "Updated Name",
"item_count": 30
}
}
Delete Collection
POST /mjr/am/collections/delete
Request Body:
{
"collection_id": "collection_123"
}
Response:
{
"ok": true,
"data": {
"collection_id": "collection_123",
"deleted": true
}
}
Note: Does not delete assets, only the collection definition.
List Custom Roots
GET /mjr/am/custom-roots
Response:
{
"ok": true,
"data": {
"roots": [
{
"id": "root_123",
"path": "/path/to/custom/dir",
"name": "Custom Directory",
"added_at": "2026-02-28T10:00:00Z"
}
]
}
}
Add Custom Root
POST /mjr/am/custom-roots/add
Request Body:
{
"path": "/path/to/custom/dir",
"name": "Custom Directory"
}
Response:
{
"ok": true,
"data": {
"root_id": "root_123",
"path": "/path/to/custom/dir",
"added": true
}
}
Remove Custom Root
POST /mjr/am/custom-roots/remove
Request Body:
{
"root_id": "root_123"
}
Response:
{
"ok": true,
"data": {
"root_id": "root_123",
"removed": true
}
}
Viewer & Metadata
Viewer Info
GET /mjr/am/viewer/info
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
asset_id |
string | Asset ID |
Example:
GET /mjr/am/viewer/info?asset_id=asset_123
Response:
{
"ok": true,
"data": {
"asset_id": "asset_123",
"filename": "fantasy_character.png",
"type": "image",
"width": 1024,
"height": 1536,
"metadata": {
"prompt": "A fantasy character...",
"model": "SDXL",
"workflow_minimap": { ... }
}
}
}
Download & Export
Download Asset
GET /mjr/am/download
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
asset_id |
string | Asset ID |
filename |
string | Filename (for direct download) |
type |
string | Scope type |
subfolder |
string | Subfolder path |
Example:
GET /mjr/am/download?asset_id=asset_123
Response: File stream with appropriate Content-Type and Content-Disposition headers.
Create Batch ZIP
POST /mjr/am/batch-zip
Request Body:
{
"asset_ids": ["asset_123", "asset_124", "asset_125"]
}
Response:
{
"ok": true,
"data": {
"token": "zip_token_abc123",
"expires_at": "2026-02-28T11:00:00Z",
"download_url": "/mjr/am/batch-zip/zip_token_abc123"
}
}
Download Batch ZIP
GET /mjr/am/batch-zip/{token}
Response: ZIP file stream containing all requested assets.
Database Maintenance
Optimize Database
POST /mjr/am/db/optimize
Purpose: Run PRAGMA optimize and ANALYZE for performance.
Response:
{
"ok": true,
"data": {
"optimized": true,
"duration_ms": 150
}
}
Cleanup Case Duplicates
POST /mjr/am/db/cleanup-case-duplicates
Purpose: Remove historical path-case duplicates (Windows-specific).
Response:
{
"ok": true,
"data": {
"duplicates_removed": 5,
"kept_canonical": 100
}
}
Force-Delete Database
POST /mjr/am/db/force-delete
Purpose: Emergency recovery for corrupted databases.
Response:
{
"ok": true,
"data": {
"deleted": true,
"reinitialized": true,
"rescan_triggered": true
}
}
Note: This endpoint bypasses normal DB-dependent security checks for emergency recovery.
Utilities
Date Histogram
GET /mjr/am/date-histogram
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
month |
string | Month in YYYY-MM format |
scope |
string | Scope type |
Example:
GET /mjr/am/date-histogram?month=2026-02&scope=output
Response:
{
"ok": true,
"data": {
"month": "2026-02",
"days": [
{ "date": "2026-02-01", "count": 50 },
{ "date": "2026-02-02", "count": 75 },
...
]
}
}
Purpose: Calendar histogram for date-based filtering UI.
Duplicate Alerts
GET /mjr/am/duplicates/alerts
Response:
{
"ok": true,
"data": {
"duplicate_groups": [
{
"filename": "image.png",
"paths": [
"/path/to/output/image.png",
"/path/to/output/subfolder/image.png"
],
"count": 2
}
],
"total_groups": 5,
"total_duplicates": 10
}
}
Workflow Library
The Workflow tab uses the standard list endpoint with scope=workflow plus dedicated workflow routes for JSON content, organization, metadata, and thumbnails.
GET /mjr/am/list?scope=workflow&q=*&limit=100&offset=0&sort=workflow_default
Purpose: List saved workflow JSON files as grid cards.
Response fields include:
assets: workflow cardstotal: total matched workflowsroots: scanned workflow rootsscope:workflow
GET /mjr/am/workflows/content?filepath=C%3A%5Cpath%5Cworkflow.json
Purpose: Read workflow JSON and prompt metadata for loading or Graph Map inspection.
POST /mjr/am/workflows/save
POST /mjr/am/workflows/duplicate
POST /mjr/am/workflows/move
POST /mjr/am/workflows/delete
POST /mjr/am/workflows/mark-loaded
POST /mjr/am/workflows/favorite
POST /mjr/am/workflows/tags
POST /mjr/am/workflows/info
Purpose: Manage workflow files and workflow library metadata. State-changing workflow routes require the normal Majoor write guards, CSRF/auth checks, audit logging, and workflow write rate limiting.
GET /mjr/am/workflows/thumbnail-candidates?filepath=...&limit=12
POST /mjr/am/workflows/thumbnail/set
GET /mjr/am/workflows/thumbnail?filepath=...
GET /mjr/am/workflows/graph-map-thumbnail?filepath=...
GET /mjr/am/workflows/model-families
POST /mjr/am/workflows/open-root
Purpose: Support workflow thumbnails, generated Graph Map previews, workflow model-family filtering, and opening the saved workflow root in the OS file manager.
GET /mjr/am/settings/workflow-roots
POST /mjr/am/settings/workflow-roots
Purpose: Read and save the Workflow tab root folders. The POST body accepts workflow_roots as a string or list of strings.
See WORKFLOWS.md for the user-facing Workflow tab behavior.
Security Notes
CSRF Protection
All state-changing endpoints (POST, PUT, PATCH, DELETE) require:
X-Requested-With: XMLHttpRequestheader, ORX-CSRF-Tokenheader with valid token
Authentication
When ComfyUI auth is enabled:
- Write operations require authenticated user
- API token can be used for remote access
- Token sent via
X-MJR-TokenorAuthorization: Bearer
Safe Mode
When Safe Mode is enabled (default):
- Delete operations require
MAJOOR_ALLOW_DELETE=1 - Rename operations require
MAJOOR_ALLOW_RENAME=1 - Open in folder requires
MAJOOR_ALLOW_OPEN_IN_FOLDER=1; it may reveal any existing local path supplied to the route, but it does not grant file read/write access
Rate Limiting
Expensive endpoints are rate-limited:
- Search: 10 requests/minute per client
- Scan: 5 requests/minute per client
- Batch ZIP: 3 requests/minute per client
- Metadata: 20 requests/minute per client
Client identity based on IP address (or X-Forwarded-For from trusted proxies).
Error Responses
Standard Error Format
{
"ok": false,
"error": {
"code": "?_CODE",
"message": "Human-readable error message",
"details": { ... } // Optional additional context
}
}
Common Error Codes
| Code | HTTP Status | Description |
|---|---|---|
AUTH_REQUIRED |
401 | Authentication required |
FORBIDDEN |
403 | Operation not allowed (Safe Mode) |
NOT_FOUND |
404 | Resource not found |
INVALID_REQUEST |
400 | Invalid request body/parameters |
RATE_LIMITED |
429 | Too many requests |
DB_ERROR |
500 | Database error |
FILE_SYSTEM_ERROR |
500 | File system error |
TOOL_UNAVAILABLE |
503 | External tool not available |
WebSocket Events
Real-Time Updates
The extension emits ComfyUI API events for real-time updates:
mjr-asset-added: New asset indexedmjr-asset-updated: Asset metadata updatedmjr-scan-complete: Scan operation completedmjr-enrichment-status: Metadata enrichment statusmjr-db-restore-status: Database restore status
Example (Frontend):
api.addEventListener("mjr-asset-added", (event) => {
const asset = event.detail;
// Update UI with new asset
});
API Reference Version: 2.0 Last Updated: April 5, 2026 Compatible with Majoor Assets Manager v2.4.4+