REST API Reference
EmDash exposes a REST API at /_emdash/api/ for content management, media uploads, and schema operations.
Authentication
Section titled “Authentication”API requests require authentication via Bearer token:
Authorization: Bearer <token>Generate tokens through the admin interface or programmatically.
Response Format
Section titled “Response Format”All responses follow a consistent format:
// Success{ "success": true, "data": { ... }}
// Error{ "success": false, "error": { "code": "ERROR_CODE", "message": "Human-readable message", "details": { ... } }}Content Endpoints
Section titled “Content Endpoints”List Content
Section titled “List Content”GET /_emdash/api/content/:collectionParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
collection | string | Collection slug (path) |
cursor | string | Pagination cursor (query) |
limit | number | Items per page (query, default: 50) |
status | string | Filter by status (query) |
orderBy | string | Field to sort by (query) |
order | string | Sort direction: asc or desc (query) |
Response
Section titled “Response”{ "success": true, "data": { "items": [ { "id": "01HXK5MZSN...", "type": "posts", "slug": "hello-world", "data": { "title": "Hello World", ... }, "status": "published", "createdAt": "2025-01-24T12:00:00Z", "updatedAt": "2025-01-24T12:00:00Z" } ], "nextCursor": "eyJpZCI6..." }}Get Content
Section titled “Get Content”GET /_emdash/api/content/:collection/:idResponse
Section titled “Response”{ "success": true, "data": { "item": { "id": "01HXK5MZSN...", "type": "posts", "slug": "hello-world", "data": { "title": "Hello World", ... }, "status": "published", "createdAt": "2025-01-24T12:00:00Z", "updatedAt": "2025-01-24T12:00:00Z" } }}Create Content
Section titled “Create Content”POST /_emdash/api/content/:collectionContent-Type: application/jsonRequest Body
Section titled “Request Body”{ "data": { "title": "New Post", "content": [...] }, "slug": "new-post", "status": "draft"}Response
Section titled “Response”{ "success": true, "data": { "item": { ... } }}Update Content
Section titled “Update Content”PATCH /_emdash/api/content/:collection/:idContent-Type: application/jsonRequest Body
Section titled “Request Body”{ "data": { "title": "Updated Title" }, "status": "published"}Delete Content
Section titled “Delete Content”DELETE /_emdash/api/content/:collection/:idResponse
Section titled “Response”{ "success": true, "data": { "success": true }}Media Endpoints
Section titled “Media Endpoints”List Media
Section titled “List Media”GET /_emdash/api/mediaParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
cursor | string | Pagination cursor |
limit | number | Items per page (default: 20) |
mimeType | string | Filter by MIME type prefix |
Response
Section titled “Response”{ "success": true, "data": { "items": [ { "id": "01HXK5MZSN...", "filename": "photo.jpg", "mimeType": "image/jpeg", "size": 102400, "width": 1920, "height": 1080, "url": "https://cdn.example.com/photo.jpg", "createdAt": "2025-01-24T12:00:00Z" } ], "nextCursor": "eyJpZCI6..." }}Get Media
Section titled “Get Media”GET /_emdash/api/media/:idCreate Media
Section titled “Create Media”POST /_emdash/api/mediaContent-Type: application/jsonRequest Body
Section titled “Request Body”{ "filename": "photo.jpg", "mimeType": "image/jpeg", "size": 102400, "width": 1920, "height": 1080, "storageKey": "uploads/photo.jpg"}Update Media
Section titled “Update Media”PATCH /_emdash/api/media/:idContent-Type: application/jsonRequest Body
Section titled “Request Body”{ "alt": "Photo description", "caption": "Photo caption"}Delete Media
Section titled “Delete Media”DELETE /_emdash/api/media/:idGet Media File
Section titled “Get Media File”GET /_emdash/api/media/file/:keyServes the actual file content. For local storage only.
Revision Endpoints
Section titled “Revision Endpoints”List Revisions
Section titled “List Revisions”GET /_emdash/api/content/:collection/:entryId/revisionsParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
limit | number | Max revisions to return (default: 50) |
Response
Section titled “Response”{ "success": true, "data": { "items": [ { "id": "01HXK5MZSN...", "collection": "posts", "entryId": "01HXK5MZSN...", "data": { ... }, "createdAt": "2025-01-24T12:00:00Z" } ], "total": 5 }}Get Revision
Section titled “Get Revision”GET /_emdash/api/revisions/:revisionIdRestore Revision
Section titled “Restore Revision”POST /_emdash/api/revisions/:revisionId/restoreRestores content to this revision’s state and creates a new revision.
Schema Endpoints
Section titled “Schema Endpoints”List Collections
Section titled “List Collections”GET /_emdash/api/schema/collectionsResponse
Section titled “Response”{ "success": true, "data": { "items": [ { "id": "01HXK5MZSN...", "slug": "posts", "label": "Posts", "labelSingular": "Post", "supports": ["drafts", "revisions", "preview"] } ] }}Get Collection
Section titled “Get Collection”GET /_emdash/api/schema/collections/:slugParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
includeFields | boolean | Include field definitions (query) |
Create Collection
Section titled “Create Collection”POST /_emdash/api/schema/collectionsContent-Type: application/jsonRequest Body
Section titled “Request Body”{ "slug": "products", "label": "Products", "labelSingular": "Product", "description": "Product catalog", "supports": ["drafts", "revisions"]}Update Collection
Section titled “Update Collection”PATCH /_emdash/api/schema/collections/:slugContent-Type: application/jsonDelete Collection
Section titled “Delete Collection”DELETE /_emdash/api/schema/collections/:slugParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
force | boolean | Delete even if collection has content (query) |
List Fields
Section titled “List Fields”GET /_emdash/api/schema/collections/:slug/fieldsCreate Field
Section titled “Create Field”POST /_emdash/api/schema/collections/:slug/fieldsContent-Type: application/jsonRequest Body
Section titled “Request Body”{ "slug": "price", "label": "Price", "type": "number", "required": true, "validation": { "min": 0 }}Update Field
Section titled “Update Field”PATCH /_emdash/api/schema/collections/:collectionSlug/fields/:fieldSlugContent-Type: application/jsonDelete Field
Section titled “Delete Field”DELETE /_emdash/api/schema/collections/:collectionSlug/fields/:fieldSlugReorder Fields
Section titled “Reorder Fields”POST /_emdash/api/schema/collections/:slug/fields/reorderContent-Type: application/jsonRequest Body
Section titled “Request Body”{ "fieldSlugs": ["title", "content", "author", "publishedAt"]}Schema Export
Section titled “Schema Export”Export Schema (JSON)
Section titled “Export Schema (JSON)”GET /_emdash/api/schemaAccept: application/jsonExport Schema (TypeScript)
Section titled “Export Schema (TypeScript)”GET /_emdash/api/schema?format=typescriptAccept: text/typescriptReturns TypeScript interfaces for all collections.
Plugin Endpoints
Section titled “Plugin Endpoints”List Plugins
Section titled “List Plugins”GET /_emdash/api/pluginsGet Plugin
Section titled “Get Plugin”GET /_emdash/api/plugins/:pluginIdEnable Plugin
Section titled “Enable Plugin”POST /_emdash/api/plugins/:pluginId/enableDisable Plugin
Section titled “Disable Plugin”POST /_emdash/api/plugins/:pluginId/disableError Codes
Section titled “Error Codes”| Code | HTTP Status | Description |
|---|---|---|
NOT_FOUND | 404 | Resource not found |
VALIDATION_ERROR | 400 | Invalid input data |
UNAUTHORIZED | 401 | Missing or invalid token |
FORBIDDEN | 403 | Insufficient permissions |
CONTENT_LIST_ERROR | 500 | Failed to list content |
CONTENT_CREATE_ERROR | 500 | Failed to create content |
CONTENT_UPDATE_ERROR | 500 | Failed to update content |
CONTENT_DELETE_ERROR | 500 | Failed to delete content |
MEDIA_LIST_ERROR | 500 | Failed to list media |
MEDIA_CREATE_ERROR | 500 | Failed to create media |
SCHEMA_ERROR | 400 | Schema operation failed |
DUPLICATE_SLUG | 409 | Slug already exists |
RESERVED_SLUG | 400 | Slug is reserved |
Search Endpoints
Section titled “Search Endpoints”Global Search
Section titled “Global Search”GET /_emdash/api/search?q=hello+worldParameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
q | string | Search query (required) |
collections | string | Comma-separated collection slugs |
status | string | Filter by status (default: published) |
limit | number | Max results (default: 20) |
cursor | string | Pagination cursor |
Response
Section titled “Response”{ "results": [ { "collection": "posts", "id": "01HXK5MZSN...", "slug": "hello-world", "title": "Hello World", "snippet": "...this is a <mark>hello</mark> <mark>world</mark> example...", "score": 0.95 } ], "nextCursor": "eyJvZmZzZXQiOjIwfQ"}Search Suggestions
Section titled “Search Suggestions”GET /_emdash/api/search/suggest?q=hel&limit=5Returns prefix-matched titles for autocomplete.
Rebuild Search Index
Section titled “Rebuild Search Index”POST /_emdash/api/search/rebuildRebuild FTS index for all or specific collections.
Search Stats
Section titled “Search Stats”GET /_emdash/api/search/statsReturns indexed document counts per collection.
Section Endpoints
Section titled “Section Endpoints”List Sections
Section titled “List Sections”GET /_emdash/api/sectionsGET /_emdash/api/sections?source=themeGET /_emdash/api/sections?search=newsletterGet Section
Section titled “Get Section”GET /_emdash/api/sections/:slugCreate Section
Section titled “Create Section”POST /_emdash/api/sectionsContent-Type: application/json
{ "slug": "my-section", "title": "My Section", "keywords": ["keyword1"], "content": [...]}Update Section
Section titled “Update Section”PUT /_emdash/api/sections/:slugDelete Section
Section titled “Delete Section”DELETE /_emdash/api/sections/:slugSettings Endpoints
Section titled “Settings Endpoints”Get All Settings
Section titled “Get All Settings”GET /_emdash/api/settingsUpdate Settings
Section titled “Update Settings”PUT /_emdash/api/settingsContent-Type: application/json
{ "siteTitle": "My Site", "tagline": "A great site", "postsPerPage": 10}Menu Endpoints
Section titled “Menu Endpoints”List Menus
Section titled “List Menus”GET /_emdash/api/menusGet Menu
Section titled “Get Menu”GET /_emdash/api/menus/:nameCreate Menu
Section titled “Create Menu”POST /_emdash/api/menusContent-Type: application/json
{ "name": "footer", "label": "Footer Navigation"}Update Menu
Section titled “Update Menu”PUT /_emdash/api/menus/:nameDelete Menu
Section titled “Delete Menu”DELETE /_emdash/api/menus/:nameAdd Menu Item
Section titled “Add Menu Item”POST /_emdash/api/menus/:name/itemsContent-Type: application/json
{ "type": "page", "referenceCollection": "pages", "referenceId": "page_about", "label": "About Us"}Reorder Menu Items
Section titled “Reorder Menu Items”POST /_emdash/api/menus/:name/reorderContent-Type: application/json
{ "items": [ { "id": "item_1", "parentId": null, "sortOrder": 0 }, { "id": "item_2", "parentId": null, "sortOrder": 1 }, { "id": "item_3", "parentId": "item_2", "sortOrder": 0 } ]}Taxonomy Endpoints
Section titled “Taxonomy Endpoints”List Taxonomy Definitions
Section titled “List Taxonomy Definitions”GET /_emdash/api/taxonomiesCreate Taxonomy
Section titled “Create Taxonomy”POST /_emdash/api/taxonomiesContent-Type: application/json
{ "name": "genre", "label": "Genres", "labelSingular": "Genre", "hierarchical": true, "collections": ["books", "movies"]}List Terms
Section titled “List Terms”GET /_emdash/api/taxonomies/:name/termsCreate Term
Section titled “Create Term”POST /_emdash/api/taxonomies/:name/termsContent-Type: application/json
{ "slug": "tutorials", "label": "Tutorials", "parentId": "term_abc", "description": "How-to guides"}Update Term
Section titled “Update Term”PUT /_emdash/api/taxonomies/:name/terms/:slugDelete Term
Section titled “Delete Term”DELETE /_emdash/api/taxonomies/:name/terms/:slugSet Entry Terms
Section titled “Set Entry Terms”POST /_emdash/api/content/:collection/:id/terms/:taxonomyContent-Type: application/json
{ "termIds": ["term_news", "term_featured"]}Widget Area Endpoints
Section titled “Widget Area Endpoints”List Widget Areas
Section titled “List Widget Areas”GET /_emdash/api/widget-areasGet Widget Area
Section titled “Get Widget Area”GET /_emdash/api/widget-areas/:nameCreate Widget Area
Section titled “Create Widget Area”POST /_emdash/api/widget-areasContent-Type: application/json
{ "name": "sidebar", "label": "Main Sidebar", "description": "Appears on posts"}Delete Widget Area
Section titled “Delete Widget Area”DELETE /_emdash/api/widget-areas/:nameAdd Widget
Section titled “Add Widget”POST /_emdash/api/widget-areas/:name/widgetsContent-Type: application/json
{ "type": "content", "title": "About", "content": [...]}Update Widget
Section titled “Update Widget”PUT /_emdash/api/widget-areas/:name/widgets/:idDelete Widget
Section titled “Delete Widget”DELETE /_emdash/api/widget-areas/:name/widgets/:idReorder Widgets
Section titled “Reorder Widgets”POST /_emdash/api/widget-areas/:name/reorderContent-Type: application/json
{ "widgetIds": ["widget_1", "widget_2", "widget_3"]}User Management Endpoints
Section titled “User Management Endpoints”List Users
Section titled “List Users”GET /_emdash/api/admin/usersGET /_emdash/api/admin/users?role=40GET /_emdash/api/admin/users?search=johnGet User
Section titled “Get User”GET /_emdash/api/admin/users/:idUpdate User
Section titled “Update User”PATCH /_emdash/api/admin/users/:idContent-Type: application/json
{ "name": "John Doe", "role": 40}Enable User
Section titled “Enable User”POST /_emdash/api/admin/users/:id/enableDisable User
Section titled “Disable User”POST /_emdash/api/admin/users/:id/disableAuthentication Endpoints
Section titled “Authentication Endpoints”Setup Status
Section titled “Setup Status”GET /_emdash/api/setup/statusReturns whether setup is complete and if users exist.
Passkey Login
Section titled “Passkey Login”POST /_emdash/api/auth/passkey/optionsGet WebAuthn authentication options.
POST /_emdash/api/auth/passkey/verifyContent-Type: application/json
{ "id": "credential-id", "rawId": "...", "response": {...}, "type": "public-key"}Verify passkey and create session.
Magic Link
Section titled “Magic Link”POST /_emdash/api/auth/magic-link/sendContent-Type: application/json
{ "email": "user@example.com"}GET /_emdash/api/auth/magic-link/verify?token=xxxLogout
Section titled “Logout”POST /_emdash/api/auth/logoutCurrent User
Section titled “Current User”GET /_emdash/api/auth/meInvite User
Section titled “Invite User”POST /_emdash/api/auth/inviteContent-Type: application/json
{ "email": "newuser@example.com", "role": 30}Passkey Management
Section titled “Passkey Management”GET /_emdash/api/auth/passkeyList user’s passkeys.
POST /_emdash/api/auth/passkey/register/optionsPOST /_emdash/api/auth/passkey/register/verifyRegister new passkey.
PATCH /_emdash/api/auth/passkey/:idContent-Type: application/json
{ "name": "MacBook Pro"}Rename passkey.
DELETE /_emdash/api/auth/passkey/:idDelete passkey.
Import Endpoints
Section titled “Import Endpoints”Analyze WordPress Export
Section titled “Analyze WordPress Export”POST /_emdash/api/import/wordpress/analyzeContent-Type: multipart/form-data
file: <WXR file>Execute WordPress Import
Section titled “Execute WordPress Import”POST /_emdash/api/import/wordpress/executeContent-Type: application/json
{ "analysisId": "...", "options": { "includeMedia": true, "includeTaxonomies": true, "includeMenus": true }}Rate Limiting
Section titled “Rate Limiting”API endpoints may be rate-limited based on deployment configuration. When rate-limited, responses include:
HTTP/1.1 429 Too Many RequestsRetry-After: 60The API supports CORS for browser requests. Configure allowed origins in your deployment.