Description
n8n-nodes-emdash
Consume and manage content, media, menus, schemas, taxonomies, search, URL redirects, comments, settings, sections, and widget areas from EmDash CMS in n8n workflows.
> This is an independent Black Swamp AI community integration. It is not affiliated with, endorsed by, sponsored by, or maintained by EmDash or Cloudflare Inc. Product names and marks belong to their respective owners and are used only to identify compatibility.
Installation · Compatibility · Credentials · Operations · Migration · Usage · Troubleshooting · Resources · Black Swamp AI
Installation
On self-hosted n8n instances, install this community node through the n8n web interface:
1. Open Settings → Community Nodes in your n8n workspace.
2. Select Install a community node.
3. Enter @blackswampai/n8n-nodes-emdash in the npm package name field.
4. Agree to the risks of installing third-party code and select Install.
For additional guidance on managing community nodes, see the n8n Community Nodes installation documentation.
Compatibility
| Surface | Tested baseline | Notes |
| ——————- | —————— | ——————————————————— |
| n8n | 2.30.6 | Runtime, picker-source, and user-verified picker baseline |
| EmDash CMS | v1 (emdash@1.0.1+) | Cloudflare Workers REST API endpoint |
| Node.js development | 22.22.0 and 24 | CI and package checks run on both lanes. |
Credentials
To authenticate with your EmDash instance:
EmDash API Credential
1. In n8n, create an EmDash API credential.
2. Site URL: Enter the root URL of your EmDash installation (for example, https://cms.example.com). The node automatically normalizes trailing slashes and routes requests through the /_emdash/api endpoint prefix.
3. API Token: Enter a Personal Access Token (PAT) generated in your EmDash administrative panel.
#### Personal Access Token Scopes and RBAC
EmDash 1.0.1 defines the following valid PAT scopes: content:read, content:write, media:read, media:write, schema:read, schema:write, taxonomies:manage, menus:manage, settings:read, settings:manage, mcp:tools, transfer:export, transfer:analyze, transfer:execute, and admin.
Effective authorization requires both the PAT scope and the user’s underlying RBAC role. Scopes required by resource:
- Content operations:
- Media operations: Read queries (
GET) generally requiremedia:read, except Get Usage which requires Personal Access Token scopeadmin(notmedia:read) alongside RBAC capabilitiesmedia:read+content:readdrafts. For Get and Get Many withincludeUsage=1, an inline coverage-aware usage summary is returned, butusage.countis only readable when the caller holds both the RBACcontent:readdraftscapability and, when authenticated by a PAT/OAuth token, theadmintoken scope (amedia:readPAT alone cannot expose draft-derived usage counts). Mutations (binary uploads, staged upload target generation, raw chunk uploads, confirmation, image replacement, metadata updates, folder creation, folder rename, and file/folder deletion) requiremedia:write. - Menu operations:
- Taxonomy operations: Read queries (
GET) requirecontent:read. Bulk tagging requirescontent:write. Schema mutations and term management requiretaxonomies:manage(implicitly granted bycontent:writeoradmin). (EmDash does not definetaxonomy:readortaxonomy:writescopes). - Search operations: Queries and prefix suggestions require
content:read. Administrative operations (rebuilding an index or enabling search on a collection) requireadmin. (EmDash does not definesearch:readorsearch:adminscopes). - Redirect operations: Neither
redirects:readnorredirects:writeexists as a PAT scope. All redirect rules and 404 access log operations requireadmindue to fail-closed middleware scope enforcement. - Schema operations:
- Comment moderation operations: EmDash does not define granular
comments:*PAT scopes (such ascomments:readorcomments:moderate). All comment moderation endpoints live under/_emdash/api/admin/commentsand strictly require a Personal Access Token with theadminscope in combination with administrative RBAC permissions. - Settings operations:
- Section operations:
- Widget Area operations:
- Get Many (
getAll): Retrieve comments with cursor pagination and status, collection, and search filters. - Get Counts (
getCounts): Retrieve comment counts grouped by moderation status (pending,approved,spam,trash). - Get (
get): Retrieve a single comment by ID including author metadata, IP hash, and status. - Update Status (
updateStatus): Update the moderation status of a comment (approved,pending,spam,trash). - Bulk Action (
bulkAction): Apply moderation action (approve,spam,trash) or permanently delete up to 100 comments in a single request. - Delete (
delete): Permanently delete a comment by ID (irreversible). - Get Many (
getAll): Retrieve entries in a collection with cursor pagination, publication status filtering, and date ranges. - Get (
get): Retrieve a single content item by ID or URL slug. - Create (
create): Create a draft content entry with JSON data, SEO metadata, locale, and taxonomy terms. - Update (
update): Mutate existing content with optimistic concurrency control (_rev). - Delete (
delete): Soft delete an entry to trash. - Publish (
publish): Promote draft changes to live version. - Unpublish (
unpublish): Revert published live entry to draft. - Schedule (
schedule): Set a future publication timestamp. - Unschedule (
unschedule): Cancel scheduled publication. - Duplicate (
duplicate): Clone an existing entry into a new draft. - Restore (
restore): Restore a trashed entry. - Permanently Delete (
permanentDelete): Hard delete a trashed entry. - Compare Draft and Live (
compare): Diff draft changes against the live version. - Discard Draft (
discardDraft): Discard pending draft edits and revert to live version. - Get Content Terms (
getContentTerms): Retrieve taxonomy terms assigned to an entry. - Set Content Terms (
setContentTerms): Replace taxonomy term assignments on an entry. - Get Translations (
getTranslations): Retrieve translation variants linked to the same translation group. - Get Authors (
getAuthors): Retrieve distinct authors of content items within a collection. - Get Trashed (
getTrashed): Retrieve soft-deleted content items in a collection with cursor pagination and locale filtering. - Get Edit Lock (
getLock): Check current edit lock status and holder information for a content item. - Acquire Edit Lock (
acquireLock): Acquire or refresh an edit lock lease on a content item. - Release Edit Lock (
releaseLock): Release the caller’s edit lock lease on a content item. - Get Many (
getAll): List media files with cursor pagination, MIME type, folder filtering, and case-insensitive filename substring search (q). Note:includeUsageprovides a coverage-aware usage summary;usage.countisnullunless the caller holds both the RBACcontent:read_draftspermission andadmintoken scope (use Get Usage for complete usage references). - Get (
get): Get metadata for a media file by ID. Note:includeUsageprovides a coverage-aware usage summary (usage.countisnullunless caller holds both the RBACcontent:read_draftspermission andadmintoken scope). - Upload (
upload): Upload binary files directly via multipart form data, with optionalfieldIdallowlist targeting, pixel dimensions (width,height), and LQIP placeholder thumbnail (thumbnailBinaryPropertyName). - Replace Image (
replaceImage): Replace the binary file of an existing image (image/jpeg,image/png, orimage/webp) while preserving its ID, filename, and storage identity. Updates bytes, size, dimensions, and content hash, while invalidating and explicitly resettingblurhash,dominantColor, andfocalX/focalYtonull(does not regenerate derived metadata). Requires positive integerwidthandheight. - Get Upload Target (
getUploadTarget): Initiate a staged upload workflow by requesting a pre-signed or direct upload destination for a pending file (filename,contentType,size). When deduplication (deduplicate: true) is enabled and a matching checksum is found, the endpoint short-circuits the upload and immediately returns{ existing: true, mediaId, storageKey, url }. - Upload Pending File (
uploadPending): Upload raw binary data directly to the staged upload URL / pending media endpoint (PUT /media/{id}/upload) using raw binary streaming (Content-Type,Content-Length) rather than multipart form data. - Confirm Upload (
confirmUpload): Finalize a staged media upload (POST /media/{id}/confirm) after binary data has been written, optionally recording validatedsize,width, andheight. - Update Metadata (
update): Update media title, alt text, caption, focal points (focalXandfocalYmust be provided together between 0.0 and 1.0, or cleared viaclearFocalPoint/null), positive integer dimensions, or folder (use “unfiled” or empty string to unfile). - Delete (
delete): Delete a media record and associated storage file. - Get Usage (
getUsage): Retrieve content entries and site settings referencing a media file with cursor pagination (cursor,limit). Requires PAT scopeadminand RBACmedia:read+content:read_drafts. - Get Many Folders (
getAllFolders): List media folders. - Get Folder (
getFolder): Get single media folder metadata by ID. - Create Folder (
createFolder): Create a new folder to organize media assets. - Update Folder (
updateFolder): Update media folder name. - Delete Folder (
deleteFolder): Delete a media folder (unfiles referencing media items by settingfolder_idto null; does not require the folder to be empty). - Get Many (
getAll): Retrieve all navigation menus with optional locale filtering. - Get (
get): Retrieve a single menu and its navigation item hierarchy by menu name with optional locale filtering. - Create (
create): Create a new navigation menu with name and label; optionally configure target locale or translate an existing menu (translationOf). - Update (
update): Update a menu label with optional locale filtering. - Delete (
delete): Permanently delete a menu and all its navigation items for the targeted menu and locale (does not delete referenced content). - Create Item (
createItem): Add a navigation item to a menu (custom,page,post,taxonomy, orcollection) with optional parent, ordering, target, and styling. - Update Item (
updateItem): Update navigation item label, URL, target, attributes, parent, or sort order (supports explicit null to move items to root). - Delete Item (
deleteItem): Remove a navigation item from a menu (does not delete referenced content). - Reorder Items (
reorderItems): Atomically update menu hierarchy and sibling ordering via an array of item IDs, parent references, and sort positions. - Get Many (
getAllRedirects): List URL redirect rules with cursor pagination and search, group, enabled, auto filters. - Get (
getRedirect): Retrieve redirect rule by ID. - Create (
createRedirect): Create a redirect rule (301,302,307,308,410,451). - Update (
updateRedirect): Update redirect rule source, destination, status code, enabled state, or group. - Delete (
deleteRedirect): Delete a redirect rule by ID. - Get 404 Entries (
get404Entries): Retrieve recorded 404 Not Found error entries with cursor pagination and search filter. - Get 404 Summary (
get404Summary): Retrieve aggregation summary of top 404 error paths. - Prune 404 Log (
prune404Log): Delete 404 error log entries older than an ISO 8601 datetime threshold. - Clear All 404 Entries (
clear404Log): Destructively delete all recorded 404 log entries. - Get Many Collections (
getCollections): Retrieve all collections defined in the schema. - Get Collection (
getCollection): Retrieve a single collection schema by slug, optionally including its field definitions (includeFields). - Create Collection (
createCollection): Register a new collection schema with slug, label, and optional metadata (supports,admin,source,urlPattern,routable,hasSeo,hidden,sortOrder,editLocking,group). Server defaults forsupportsare preserved when omitted. - Update Collection (
updateCollection): Update collection schema label, metadata, comments moderation, or title/date field bindings (rejects empty updates). UsesortOrder(integer) to update sidebar position, or enableclearSortOrder: true(or passsortOrder: null) to clear explicit sidebar position and revert to default alphabetical ordering (note thatsortOrderandclearSortOrderare mutually exclusive). - Delete Collection (
deleteCollection): Permanently deletes the collection schema and drops its underlying content table. Relations involving the collection are also removed, which cascades to bound reference fields on other collections. When content exists, deletion fails unlessforce=trueis explicitly provided. - Reorder Collections (
reorderCollections): Update admin sidebar display order of collections via an array of collection slugs. Listed collections receive explicit positions 0..N; omitted collections have explicit order cleared and sort alphabetically. Rejects unknown or duplicate slugs. - Get Many Fields (
getFields): Retrieve all field definitions for a collection schema. - Get Field (
getField): Retrieve a single field schema by slug within a collection. - Create Field (
createField): Add a new field definition to a collection schema across 17 supported field types (string,text,url,number,integer,boolean,datetime,select,multiSelect,portableText,image,file,reference,json,slug,repeater,blocks). Field constraints (validation) and widget rendering options (options) are passed as flexible JSON objects. For new reference fields, specifytargetCollectionin the validation JSON (e.g.{ "targetCollection": "authors" }). Referenced block types must already exist in EmDash. - Update Field (
updateField): Update an existing field schema’s label, type, options, widget, or validation rules (rejects empty updates). Passing empty string""clears the widget (JSONnullis rejected upstream by the EmDash schema withVALIDATIONERROR). Note that target collection on an active reference field is immutable. Upstream enforces strict migration restrictions: mutatingrequired,unique, or settingtranslatable: falserequires manual content migration and is rejected upstream withFIELDUPDATEREQUIRESMIGRATION; type changes across SQL column affinities are rejected withFIELDTYPECOLUMN_CHANGE(compatible text-alias transitions such astexttostringor no-op reassertions succeed). - Delete Field (
deleteField): Permanently deletes the field and drops its column from the content table. WhendeleteRelation=trueis enabled on a reference field, it also cascades to delete the underlying relationship, all relation edges, and the field bound to the opposite side of the relation on the other collection. - Reorder Fields (
reorderFields): Update field display ordering within a collection via an array of field slugs. Upstream updates each supplied field slug sequentially; partial field lists update only listed fields while omitted fields retain existing sort orders (which may cause position collisions); unmatched or unknown field slugs silently update 0 rows without error (returns 200, unlikereorderCollectionswhich returns 404); duplicate slugs are rejected locally; provide the complete field list for deterministic ordering. - Search (
search): Full-text search across indexed content with cursor pagination, collections filter, locale, status, and scope (allortitle). - Suggest (
suggest): Autocompletion prefix suggestions with collection and locale filters. - Get Stats (
getStats): Retrieve search index statistics and document counts. - Rebuild Index (
rebuildIndex): Trigger a search index rebuild for a specific collection. - Enable / Configure Search (
enableSearch): Configure SQLite FTS5 search indexing for a collection, including tokenizer strategies (porter unicode61,unicode61,trigram) and column weight mapping. - Get Many (
getAll): Retrieve sections with cursor pagination and optional source (theme,user,import) or search filters. - Get (
get): Retrieve a single section by slug. - Create (
create): Create a new section with slug, title, structured JSON content, and optional description, keywords, preview media ID, source (userorimport), or theme ID. - Update (
update): Update section slug, title, description, keywords, structured JSON content, or preview media ID (pass null or empty string to clear preview media). - Delete (
delete): Delete a custom or imported section (theme-defined sections are protected and cannot be deleted). - Get (
get): Retrieve current site settings object directly from the CMS without static schema constraints. - Update (
update): Update site settings with a validated JSON object or expression viaPOST /settings(merges updates with existing settings; unspecified settings remain unchanged). - Get Many (
getAllTaxonomies): List all registered taxonomies. - Get (
getTaxonomy): Retrieve taxonomy schema and metadata. - Update (
updateTaxonomy): Update taxonomy schema (label,labelSingular,hierarchical,collections). - Delete (
deleteTaxonomy): Delete taxonomy definition and its terms. - Get Many Terms (
getAllTerms): List terms within a taxonomy. - Get Term (
getTerm): Retrieve single taxonomy term by slug. - Create Term (
createTerm): Create a new term with label, slug, description, parent, and locale. - Update Term (
updateTerm): Update an existing term by slug. - Delete Term (
deleteTerm): Delete a term from a taxonomy. - Reorder Terms (
reorderTerms): Update display ordering of taxonomy terms (POST /taxonomies/{name}/reorder). - Get Many (
getAll): Retrieve all registered widget areas with their widgets. - Get (
get): Retrieve a widget area by name including its ordered widgets. - Create (
create): Register a new custom widget area with name, label, and optional description. - Delete (
delete): Delete a widget area (cascades deletion to all contained widgets). - Create Widget (
createWidget): Add a widget (contentwith structured content blocks,menuwith menu name, orcomponentwith component ID and JSON properties) to a widget area. - Update Widget (
updateWidget): Update widget type, title, content blocks, menu name, component ID, or component properties. - Delete Widget (
deleteWidget): Remove a widget from a widget area (does not delete referenced content, menus, or components). - Reorder Widgets (
reorderWidgets): Update display ordering of widgets in an area using an ordered array of widget IDs. - Direct Upload (
upload): - Staged Upload Workflow (
getUploadTarget→uploadPending→confirmUpload):
– Read queries (GET) require content:read. Write and mutation operations (including creation, updates, publish, unpublish, schedule, unschedule, duplicate, restore, and permanent delete) require content:write. (EmDash does not use a separate content:publish scope).
– Editorial and collaboration operations:
– Get Translations: PAT content:read, RBAC content:read (non-published variants filtered without content:read_drafts).
– Get Authors: PAT content:read, RBAC content:read_drafts (editorial draft visibility due to author PII and email).
– Get Trashed: PAT content:read, RBAC content:read_drafts.
– Get Edit Lock: PAT content:read, RBAC content:editown / content:editany.
– Acquire Edit Lock: PAT content:write, RBAC content:editown / content:editany.
– Release Edit Lock: PAT content:write, RBAC content:editown / content:editany.
– Important note on token scopes: There is NO Personal Access Token scope named content:read_drafts. Draft visibility is enforced via internal user RBAC role capabilities under the content:read PAT scope.
– PAT scopes: Read queries (GET) require content:read. Write and mutation operations (POST, PUT, DELETE) require menus:manage (which is also implicitly granted by content:write or admin). EmDash does NOT define menus:read, menu:read, or menu:write as Personal Access Token scopes.
– RBAC permissions: The authenticated user must separately possess the menus:read capability for reads, and menus:manage capability (Editor or Administrator role) for mutations.
– PAT scopes: Read queries (GET) require schema:read (or admin). Write and mutation operations (POST, PUT, DELETE) require schema:write (or admin).
– RBAC permissions: Reads require the schema:read capability. Schema modifications require schema:manage (Administrator or Developer role).
– Write-only token discovery fallback: Tokens possessing only schema:write can execute mutations but cannot access read endpoints used by editor listSearch selectors. Every collection and field resource locator provides a manual “By Slug” mode to allow workflow execution with write-only credentials.
– PAT scopes: Read queries (GET) require settings:read (or admin). Update operations (POST) require settings:manage (or admin).
– RBAC permissions: The authenticated user must separately possess the settings:read capability for reads, and settings:manage capability (Administrator role) for updates.
– PAT scopes: Read queries (GET) require content:read. Write and mutation operations (POST, PUT, DELETE) require content:write (or admin). EmDash does not define separate sections:* PAT scopes.
– RBAC permissions: The authenticated user must separately possess the sections:read capability for reads, and sections:manage capability (Editor or Administrator role) for mutations.
– PAT scopes: Read queries (GET) require content:read. Write and mutation operations (POST, PUT, DELETE) require content:write (or admin). EmDash does not define separate widgets:* PAT scopes.
– RBAC permissions: The authenticated user must separately possess the widgets:read capability for reads, and widgets:manage capability (Editor or Administrator role) for mutations.
Operations
The EmDash community node provides 103 operations across 11 core resources:
Comment (6 operations)
Content (22 operations)
Media (15 operations)
Menu (9 operations)
Redirect (9 operations)
Schema (12 operations)
> Caution on Schema Mutations:
>
> – Collection Deletion: Dropping a collection is irreversible and removes the backing SQLite table and all content entries. Always test with disposable collections.
> – Reference Field Cascade: Deleting a reference field with deleteRelation=true cascades across collection boundaries, modifying the schema of the related collection by removing the reciprocal field.
Search (5 operations)
Section (5 operations)
Settings (2 operations)
Taxonomy (10 operations)
Widget Area (8 operations)
Existing trigger workflows
Version 0.1.4 removes the EmDash webhook trigger because the EmDash webhook notifier plugin is currently broken and its event delivery cannot be verified. After upgrading, existing workflows that contain emdashTrigger will have a missing node and must be migrated before they can run. Replace it with Schedule Trigger and EmDash actions to poll for changes, or use another independently supported event source.
Usage
Declarative architecture
This integration relies on declarative routing throughout the node definition. Binary uploads use preSend hooks to construct multipart form payloads directly in memory, and response envelopes use postReceive hooks to unwrap API payloads. Any irregular or nested API structures (such as generic “weird JSON” payloads) are addressed declaratively with JMESPath or parameter expressions rather than requiring programmatic execution.
Dynamic collection discovery
Collection, folder, and taxonomy fields use n8n resource locators. You can select items interactively from a live EmDash instance or toggle to manual mode to provide dynamic expressions or IDs from upstream workflow nodes.
Cursor pagination
List operations support EmDash opaque cursor pagination. Set Return All to true to fetch all available records automatically, or disable it and specify a custom Limit.
Staged and Direct Media Upload Workflows
EmDash CMS supports both single-step direct uploads and multi-step staged uploads:
– Upload binary assets directly in one request via multipart form data (POST /media).
– Supports optional folder placement (folderId), duplicate checksum matching (deduplicate: true), automatic filename collision avoidance (ensureUniqueFilename: true), field allowlist enforcement (fieldId), explicit image dimensions (width, height), and downscaled thumbnail binary attachments (thumbnailBinaryPropertyName) for low-quality image placeholder (LQIP) generation.
– Recommended for large files, streaming pipelines, or decoupled architectures.
– Step 1: Get Upload Target (POST /media/upload-url):
– Registers a pending upload with filename, MIME contentType, and file size in bytes (must be an integer $ge 0$).
– Optional fields include contentHash, fieldId, deduplicate, ensureUniqueFilename, and folderId (passing 'unfiled' or empty string places the item at root).
– Deduplication short-circuit: When deduplicate: true is enabled and a matching checksum is detected, the EmDash API short-circuits the upload flow and immediately returns the existing media asset:
{
"existing": true,
"mediaId": "...",
"storageKey": "...",
"url": "..."
}
In this case, downstream Upload Pending File and Confirm Upload steps must be skipped.
– Step 2: Upload Pending File (PUT /media/{id}/upload):
– Writes the raw file binary buffer directly to the pending media endpoint using raw binary streaming (Content-Type and Content-Length headers). Unlike direct upload, this does not wrap data in multipart form boundaries, maximizing throughput and minimizing memory overhead.
– Step 3: Confirm Upload (POST /media/{id}/confirm):
– Finalizes the pending upload and transitions the asset to ready state.
– Optionally supplies verified size ($ge 0$), width ($> 0$), and height ($> 0$) dimensions. Unconfigured dimensions are not defaulted to 0.
replaceImage): – The PUT /media/{id}/replace endpoint replaces the binary file of an existing image asset (image/jpeg, image/png, or image/webp).
– Preserves the existing media record’s ID, filename, creation timestamp, and storage key / URL identity while updating file size, width, height, and content hash.
– Image replacement does NOT regenerate derived image metadata: upstream explicitly invalidates and resets blurhash to null, dominantColor to null, focalX to null, and focalY to null.
– Requires positive integer width and height parameters. Replacement MIME type must exactly match the original item.
getUsage): – Querying referencing content entries and site settings requires Personal Access Token scope admin (not media:read) alongside RBAC capabilities media:read and content:read_drafts.
– Supports cursor pagination via cursor and limit (1–100, default 50).
– Preserves the complete response payload (items, nextCursor, siteSettings, coverage) without auto-flattening or stripping.
– In Get Many (getAll) and Get (get), the includeUsage toggle attaches an inline usage summary; however, usage.count remains null unless the caller possesses both the RBAC content:readdrafts permission and the admin token scope (a media:read PAT alone cannot expose draft-derived usage counts). Dedicated media reference inspection via Get Usage (GET /media/{id}/usage) separately requires PAT scope admin, RBAC media:read, and RBAC content:readdrafts.
Collaborative edit locks and concurrency control
EmDash provides dual-layer write protection to prevent conflicting edits in multi-user editorial environments:
– Edit locks coordinate active editing sessions between users and automated workflows to prevent accidental overwrites during active authoring.
– Locks currently use a 7-minute lease in EmDash 1.0.1 and expire automatically unless refreshed. Calling Content → Acquire Edit Lock on an item already locked by the caller refreshes this lease duration.
– Session tokens (token): Specify an optional caller session token (up to 128 characters) when acquiring an edit lock. When releasing the lock via Content → Release Edit Lock, supplying the same token ensures that one workflow session does not inadvertently release a lock another session still relies on.
– Takeover risk (takeover: true): Callers must already be authorized to edit the entry (owned content may be authorized through content:editown, while other content requires content:editany). Once authorized, enabling takeover: true allows the caller to replace the active lock holder. Use this with caution: breaking an active lease will disrupt the current editor’s in-flight work.
_rev: – Edit locks coordinate collaborative presence and in-flight sessions; _rev revision tokens provide optimistic concurrency control at write/commit time.
– Neither replaces the other: holding an edit lock does not eliminate the need for rev checks during updates, and supplying rev does not bypass an edit lock held by another editor unless overrideLock: true is explicitly provided. Workflows should use edit locks to coordinate long-running editorial tasks and pass _rev to guarantee data integrity against stale writes.
Author discovery and privacy
The Content → Get Authors operation returns distinct author records for a collection, including author name, user ID, email address, and avatar URL. Workflows that process or forward author information to notifications, external integrations, or analytics platforms must handle these records responsibly and comply with applicable privacy standards (such as GDPR or internal data handling policies).
Comment moderation and privacy
Comment records returned by moderation endpoints contain commenter personal information, including author email (authorEmail) and cryptographic IP hash (ipHash). Workflows that process or forward comment outputs to notification channels, logs, or external systems should handle and redact these fields appropriately in accordance with organizational privacy standards.
Automated comment moderation workflows
To automate comment moderation workflows (such as AI content analysis, automated spam detection, or alerts), configure an n8n workflow using the Schedule Trigger node to periodically poll Comment → Get Many filtered by status: pending.
Menu management and hierarchy semantics
The Menu resource enables full lifecycle management of EmDash navigation structures, supporting multi-level hierarchies, localized menu variants, and referenced or custom navigation links:
– Personal Access Token (PAT) Scopes:
– Menu reads (GET): requires content:read
– Menu writes (POST, PUT, DELETE): requires menus:manage (or content:write, which implicitly grants menus:manage, or admin)
– Caution: Do NOT configure invented PAT scopes such as menus:read, menu:read, or menu:write — they do not exist in EmDash’s token system.
– Underlying User RBAC Permissions:
– Menu reads: user must have menus:read role capability
– Menu writes: user must have menus:manage role capability (Editor or Administrator)
translationOf with the canonical menu ID and specify the target locale code. The menu name must match the canonical menu name. EmDash clones existing navigation items into the new menu and joins it to the canonical translation group.type: custom validate URLs through EmDash’s upstream safeHref sanitizer. Permitted URL schemes include http, https, mailto, tel, relative web paths (/about), and fragment identifiers (#contact). Potentially unsafe protocols (such as javascript: or data:) are rejected.page, post, taxonomy, or collection) require referenceCollection (the target collection slug) and referenceId. In EmDash, referenceId corresponds to the translation-group identifier of the referenced content rather than an individual revision ID, allowing navigation links to resolve to the appropriate language variant automatically.reorderItems operation accepts a JSON or native expression list of { id, parentId, sortOrder } objects. Setting parentId to a sibling item ID creates nested sub-menus, while null positions items at the root level. sortOrder defines a zero-based integer display sequence among siblings. When updating single items via updateItem, passing an empty string or literal "null" moves an item back to the root level, whereas omitting parentId preserves existing hierarchy.Example: Automated campaign navigation update
A common content automation scenario involves publishing a promotional landing page and immediately integrating it into the site navigation menu:
1. Trigger on Publish: A Schedule Trigger with EmDash actions detects a newly published landing page in the pages collection (e.g. translationGroupId: "grpsummersale").
2. Add Navigation Item: An EmDash node executes Menu → Create Item:
– Menu: main-navigation
– Type: Page
– Label: Summer Sale
– Reference Collection: pages
– Reference ID: ={{ $json.translationGroupId }}
– Additional Fields → Target: _self
3. Reorder Menu: A subsequent EmDash node executes Menu → Reorder Items to place the new campaign link prominently at the front of the top-level navigation (sortOrder: 0).
Settings Management
The Settings resource provides direct access to site-wide configuration stored in EmDash CMS:
get): Fetches the full settings object. The response envelope is automatically unwrapped to return the raw settings data.update): Updates site settings by sending a validated JSON payload via POST /settings.settingsUpdateBody) that strips unknown properties; arbitrary custom keys are not persisted by EmDash 1.0.1, though future CMS releases may accept additional fields without requiring node UI changes. – Personal Access Token (PAT) Scopes: Reading settings via Get requires settings:read (or admin). Modifying settings via Update requires settings:manage (or admin).
– RBAC Capabilities: The authenticated user account must possess the corresponding internal RBAC permission (settings:read capability for reads; settings:manage capability, typical of the Administrator role, for updates).
Section Management
The Section resource provides full lifecycle management of reusable template and layout sections within EmDash CMS:
validateStructuredContent before dispatch to ensure a valid JSON object or array structure.user or import. EmDash strictly rejects creating sections with source: "theme" (HTTP 400 Bad Request), as theme sections are defined in codebase templates. Furthermore, theme-defined sections are protected and cannot be deleted via the API (EmDash returns HTTP 403 Forbidden).previewMediaId links a media library asset to the section to provide visual thumbnails in page and layout builders. In Update Section, passing an explicit null, literal "null", or empty string "" clears the existing preview media association. Non-string, non-null values (such as numbers, booleans, arrays, or objects) are strictly rejected with a validation error.getSections listSearch, which queries GET /sections with limit=100 and passes the interactive search term to the upstream search query parameter, with client-side fallback formatting. – PAT Scopes: Section reads (GET) require content:read. Section mutations (POST, PUT, DELETE) require content:write (or admin). EmDash does not define separate sections:* PAT scopes.
– RBAC Capabilities: The authenticated user must separately possess the sections:read role capability for reads, and sections:manage capability (Editor or Administrator) for mutations.
Widget Area and Widget Configuration
The Widget Area resource manages theme-registered and custom widget zones and the widgets placed inside them:
– content: Renders structured content blocks configured via the content JSON array.
– menu: Renders an existing navigation menu specified by menuName.
– component: Renders a site or theme component specified by componentId, with customizable options in componentProps JSON object.
DELETE /widget-areas/{name}) permanently cascades deletion to all contained widgets in the database.DELETE /widget-areas/{name}/widgets/{id}) removes the widget from the area without deleting the parent widget area, and without deleting referenced menus, components, or content items."" clears title, menuName, or componentId (upstream schema accepts strings, and the route handler converts empty strings "" to NULL in the database). Omitted fields are not included in the payload, preserving existing values. For content, an empty array [] is preserved, and for componentProps, an empty object {} is preserved. Changing widget type does not implicitly send or clear fields from the previous type unless explicitly supplied.reorderWidgets operation accepts an array or comma-separated list of widget IDs (widgetIds). EmDash accepts a partial widget ID list, but only supplied widgets receive new zero-based sort positions; for deterministic ordering, provide the complete ordered list of widgets in the area.widgetAreaSchema returns snakecase timestamps (createdat and updated_at), differing from the camelCase conventions used by content and comments.PUT /widget-areas/{name}/widgets/{id}; omitting all update fields returns HTTP 400 (“No fields to update”). The node validates this preSend to avoid unnecessary network roundtrips.GET /widget-areas endpoint returns all registered widget areas in { items: [...] } without cursor pagination. – PAT Scopes: Widget area reads (GET) require content:read. Widget area and widget mutations (POST, PUT, DELETE) require content:write (or admin). EmDash does not define separate widgets:* PAT scopes.
– RBAC Capabilities: The authenticated user must separately possess the widgets:read role capability for reads, and widgets:manage capability (Editor or Administrator) for mutations.
Troubleshooting
For local development, run npm run dev -- --custom-user-folder /tmp/n8n-node-run and open
http://localhost:5690 manually. The pinned CLI browser shortcut can open port 5678 instead. If 5690
is occupied, use
N8N_PORT=5692 npm exec -- n8n-node dev --custom-user-folder /tmp/n8n-node-run and open port 5692.
admin scope.https://cms.example.com). The node automatically normalizes trailing slashes and prefixes paths with /_emdash/api.ENTRYLOCKED or revision mismatch error, fetch the latest content item revision using Get to obtain the current rev token before retrying.