REST API 參考

本頁內容

EmDash 在 /_emdash/api/ 提供 REST API,用於內容管理、媒體上傳和架構操作。

認證

API 請求需要透過 Authorization 標頭中的 Bearer 權杖進行認證:

Authorization: Bearer <token>

透過管理介面或以程式方式產生權杖。

回應格式

所有回應遵循一致的格式。成功回應將結果包裝在 data 中:

{
  "success": true,
  "data": { ... }
}

錯誤回應包含代碼、訊息和選擇性的詳細資訊:

{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable message",
    "details": { ... }
  }
}

內容端點

列出內容

GET /_emdash/api/content/:collection

參數

參數型別描述
collectionstring集合識別碼(路徑)
cursorstring分頁游標(查詢)
limitnumber每頁項目數(查詢,預設:50)
statusstring依狀態篩選(查詢)
orderBystring排序欄位(查詢)
orderstring排序方向:ascdesc(查詢)

回應

{
  "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 /_emdash/api/content/:collection/:id

回應

{
  "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"
    }
  }
}

建立內容

POST /_emdash/api/content/:collection
Content-Type: application/json

請求主體

{
  "data": {
    "title": "New Post",
    "content": [...]
  },
  "slug": "new-post",
  "status": "draft"
}

回應

{
  "success": true,
  "data": {
    "item": { ... }
  }
}

更新內容

PUT /_emdash/api/content/:collection/:id
Content-Type: application/json

請求主體

{
	"data": {
		"title": "Updated Title"
	},
	"status": "published"
}

刪除內容

DELETE /_emdash/api/content/:collection/:id

回應

{
	"success": true,
	"data": {
		"success": true
	}
}

媒體端點

列出媒體

GET /_emdash/api/media?includeUsage=1

參數

參數型別描述
cursorstring不透明分頁游標
limitnumber每頁項目數,1 到 100(預設:50)
mimeTypestring依一個或多個以逗號分隔的 MIME 型別篩選
qstring不區分大小寫的檔案名稱搜尋
includeUsage1在每個回傳項目上包含覆蓋率感知的 usage 摘要

回應

{
	"data": {
		"items": [
			{
				"id": "01HXK5MZSN...",
				"filename": "photo.jpg",
				"mimeType": "image/jpeg",
				"size": 102400,
				"width": 1920,
				"height": 1080,
				"url": "/_emdash/api/media/file/uploads/photo.jpg",
				"createdAt": "2025-01-24T12:00:00Z",
				"usage": {
					"count": 3,
					"coverage": {
						"scope": "all_content_collections",
						"status": "complete"
					}
				}
			}
		],
		"nextCursor": "eyJpZCI6..."
	}
}

取得媒體

GET /_emdash/api/media/:id?includeUsage=1

includeUsage 在列表和取得中都是選擇性的。其唯一接受的值為 1。省略時, usage 屬性將被省略,伺服器不會執行使用情況查詢。

使用情況摘要

usage.count 是其所選當前索引來源參考該媒體項目的 EmDash 不同活躍內容列或語系的數量。同一內容項目的重複參考和多個來源變體只計算一次。資源回收桶中的內容不計入。

數字計數可能會揭示類似草稿的內容。僅在工作階段使用者具有 content:read_drafts 時,或當 API 權杖具有 admin 範圍且其關聯使用者也具有該權限時才回傳。其他媒體讀取者收到 usage.count: null;這是成功的已編輯回應,不是錯誤。

每個請求的摘要包含當前所有已註冊內容集合的彙總覆蓋率:

狀態含義
complete每個已註冊集合都有當前的、已完成的使用情況覆蓋
never沒有已註冊集合完成過初始使用情況修復
running使用情況修復當前正在執行
partial覆蓋率混合或僅註冊範圍的部分被索引
failed在註冊範圍內覆蓋率失敗
stale索引覆蓋率已過時
unknown儲存的覆蓋率包含此版本無法識別的狀態

只有 complete 支援在下面描述的 EmDash 管理欄位內的有範圍的完全零宣告。具有任何其他狀態的計數是索引投影,可能過度報告或不足報告。即使是完整的結果在並行寫入期間也是參考性的;使用情況讀取不是交易鎖,不得用作刪除保證。

取得媒體使用情況詳情

GET /_emdash/api/media/:id/usage?limit=50&cursor=...

此端點需要 media:readcontent:read_drafts。權杖認證的呼叫者還需要 admin 範圍;權杖範圍不會繞過關聯使用者的權限。

limit 控制每頁的內容項目群組,範圍為 1 到 100(預設:50)。分頁永遠不會拆分回傳項目群組的來源或出現次數。

{
	"data": {
		"items": [
			{
				"collection": "posts",
				"contentId": "01CONTENT...",
				"title": "Launch notes",
				"slug": "launch-notes",
				"locale": "en",
				"status": "published",
				"scheduledAt": null,
				"deletedAt": null,
				"sources": [
					{
						"variant": "columns",
						"occurrences": [
							{
								"fieldSlug": "hero",
								"fieldPath": "hero",
								"occurrenceIndex": 0,
								"referenceType": "image_field"
							}
						]
					}
				]
			}
		],
		"nextCursor": "eyJvcmRlclZhbHVlIjoicG9zdHMiLCJpZCI6IjAxLi4uIn0",
		"coverage": {
			"scope": "all_content_collections",
			"status": "complete"
		}
	}
}

授權詳情包括活躍和已刪除的項目。非空的 deletedAt 標識資源回收桶項目。來源為 columnsdraft_overlay;出現次數標識支援的欄位和路徑,而不暴露內部索引中繼資料。

媒體使用情況涵蓋 EmDash 內容集合管理的頂層圖片和檔案欄位、重複器圖片欄位和 Portable Text 圖片區塊中的本地媒體參考。它不掃描自訂程式碼、渲染的 HTML、設定、選單、小工具、外掛程式私有資料、外部網站或僅供應商的資產。

建立媒體

POST /_emdash/api/media
Content-Type: application/json

請求主體

{
	"filename": "photo.jpg",
	"mimeType": "image/jpeg",
	"size": 102400,
	"width": 1920,
	"height": 1080,
	"storageKey": "uploads/photo.jpg"
}

更新媒體

PUT /_emdash/api/media/:id
Content-Type: application/json

請求主體

{
	"alt": "Photo description",
	"caption": "Photo caption"
}

刪除媒體

DELETE /_emdash/api/media/:id

修復媒體使用情況

POST /_emdash/api/admin/media-usage/repair
Content-Type: application/json
X-EmDash-Request: 1

修復一個集合或所有內容集合的內容媒體使用情況索引。這是管理員/營運端點:工作階段認證的呼叫者需要 schema:manage,Bearer 權杖必須具有 admin 範圍,因為路由在 /_emdash/api/admin 下。

全內容修復在當前版本中同步順序執行。在大型網站上可能代價高昂,因此呼叫者應有意觸發並等待回應。

請求主體

修復一個集合:

{
	"scope": "collection",
	"collection": "posts"
}

修復所有內容集合:

{
	"scope": "all"
}

請求主體是必需的。無效的 slug、未知的請求金鑰、缺少 scope 和無請求主體的請求回傳 400,而不是預設修復所有內容。

回應

當修復呼叫產生結構化結果時,端點回傳 200。檢查 data.statusfailedstale 是修復領域狀態,不是傳輸錯誤。

{
	"data": {
		"status": "complete",
		"indexedSourceCount": 12,
		"failedSourceCount": 0,
		"skippedSourceCount": 0,
		"deletedSourceCount": 1,
		"collections": [
			{
				"collection": "posts",
				"status": "complete",
				"indexedSourceCount": 12,
				"failedSourceCount": 0,
				"skippedSourceCount": 0,
				"deletedSourceCount": 1,
				"lastErrorCode": null,
				"startedAt": "2026-07-07T12:00:00.000Z",
				"completedAt": "2026-07-07T12:00:01.000Z"
			}
		]
	}
}

頂層回應欄位:

欄位型別描述
statuscomplete | partial | failed | stale彙總修復狀態
indexedSourceCountnumber修復期間索引的來源
failedSourceCountnumber修復期間失敗的來源
skippedSourceCountnumber跳過的來源,包括過時衝突
deletedSourceCountnumber修復期間刪除的過時使用列
collectionsarray每個集合的修復摘要

集合摘要欄位:

欄位型別描述
collectionstring集合識別碼
statuscomplete | partial | failed | stale集合修復狀態
indexedSourceCountnumber此集合索引的來源
failedSourceCountnumber此集合失敗的來源
skippedSourceCountnumber此集合跳過的來源
deletedSourceCountnumber此集合刪除的過時使用列
lastErrorCodestring | null最後的集合修復錯誤(如果可用)
startedAtstring修復開始時間
completedAtstring | null完成時間,過時結果為 null

未知集合回傳 200,帶有 data.status: "failed" 和每個集合的 lastErrorCode(如 COLLECTION_NOT_FOUND)。傳輸錯誤仍使用標準錯誤信封,包括 400401403413500

取得媒體檔案

GET /_emdash/api/media/file/:key

提供實際的檔案內容。僅用於本地儲存。

修訂版端點

列出修訂版

GET /_emdash/api/content/:collection/:entryId/revisions

參數

參數型別描述
limitnumber回傳的最大修訂版數(預設:50)

回應

{
  "success": true,
  "data": {
    "items": [
      {
        "id": "01HXK5MZSN...",
        "collection": "posts",
        "entryId": "01HXK5MZSN...",
        "data": { ... },
        "createdAt": "2025-01-24T12:00:00Z"
      }
    ],
    "total": 5
  }
}

取得修訂版

GET /_emdash/api/revisions/:revisionId

還原修訂版

POST /_emdash/api/revisions/:revisionId/restore

將內容還原到此修訂版的狀態並建立新的修訂版。

架構端點

列出集合

GET /_emdash/api/schema/collections

回應

{
	"success": true,
	"data": {
		"items": [
			{
				"id": "01HXK5MZSN...",
				"slug": "posts",
				"label": "Posts",
				"labelSingular": "Post",
				"supports": ["drafts", "revisions", "preview"]
			}
		]
	}
}

取得集合

GET /_emdash/api/schema/collections/:slug

參數

參數型別描述
includeFieldsboolean包含欄位定義(查詢)

建立集合

POST /_emdash/api/schema/collections
Content-Type: application/json

請求主體

{
	"slug": "products",
	"label": "Products",
	"labelSingular": "Product",
	"description": "Product catalog",
	"supports": ["drafts", "revisions"]
}

更新集合

PUT /_emdash/api/schema/collections/:slug
Content-Type: application/json

刪除集合

DELETE /_emdash/api/schema/collections/:slug

參數

參數型別描述
forceboolean即使集合有內容也刪除(查詢)

列出欄位

GET /_emdash/api/schema/collections/:slug/fields

建立欄位

POST /_emdash/api/schema/collections/:slug/fields
Content-Type: application/json

請求主體

{
	"slug": "price",
	"label": "Price",
	"type": "number",
	"required": true,
	"validation": {
		"min": 0
	}
}

更新欄位

PUT /_emdash/api/schema/collections/:collectionSlug/fields/:fieldSlug
Content-Type: application/json

刪除欄位

DELETE /_emdash/api/schema/collections/:collectionSlug/fields/:fieldSlug

重新排序欄位

POST /_emdash/api/schema/collections/:slug/fields/reorder
Content-Type: application/json

請求主體

{
	"fieldSlugs": ["title", "content", "author", "publishedAt"]
}

架構匯出

匯出架構(JSON)

GET /_emdash/api/schema
Accept: application/json

匯出架構(TypeScript)

GET /_emdash/api/schema?format=typescript
Accept: text/typescript

回傳所有集合的 TypeScript 介面。

外掛程式端點

列出外掛程式

GET /_emdash/api/admin/plugins

取得外掛程式

GET /_emdash/api/admin/plugins/:id

啟用外掛程式

POST /_emdash/api/admin/plugins/:id/enable

停用外掛程式

POST /_emdash/api/admin/plugins/:id/disable

錯誤代碼

代碼HTTP 狀態描述
NOT_FOUND404資源未找到
VALIDATION_ERROR400無效的輸入資料
UNAUTHORIZED401權杖缺失或無效
FORBIDDEN403權限不足
CONTENT_LIST_ERROR500列出內容失敗
CONTENT_CREATE_ERROR500建立內容失敗
CONTENT_UPDATE_ERROR500更新內容失敗
CONTENT_DELETE_ERROR500刪除內容失敗
MEDIA_LIST_ERROR500列出媒體失敗
MEDIA_CREATE_ERROR500建立媒體失敗
SCHEMA_CREATE_ERROR500架構操作失敗
SLUG_CONFLICT409Slug 已存在
RESERVED_SLUG400Slug 被保留

搜尋端點

全域搜尋

GET /_emdash/api/search?q=hello+world

參數

參數型別描述
qstring搜尋查詢(必填)
collectionsstring逗號分隔的集合識別碼
statusstring依狀態篩選(預設:published)
limitnumber最大結果數(預設:20)
cursorstring分頁游標

回應

{
  "success": true,
  "data": {
    "items": [
      {
        "collection": "posts",
        "id": "01HXK5MZSN...",
        "slug": "hello-world",
        "locale": "en",
        "title": "Hello World",
        "snippet": "...this is a <mark>hello</mark> <mark>world</mark> example...",
        "score": 0.95
      }
    ],
    "nextCursor": "eyJvZmZzZXQiOjIwfQ"
  }
}

搜尋建議

GET /_emdash/api/search/suggest?q=hel&limit=5

回傳用於自動完成的前綴匹配標題。

重建搜尋索引

POST /_emdash/api/search/rebuild

為所有或特定集合重建 FTS 索引。

搜尋統計

GET /_emdash/api/search/stats

回傳每個集合的索引文件計數。

區塊端點

列出區塊

GET /_emdash/api/sections
GET /_emdash/api/sections?source=theme
GET /_emdash/api/sections?search=newsletter

取得區塊

GET /_emdash/api/sections/:slug

建立區塊

POST /_emdash/api/sections
Content-Type: application/json

{
  "slug": "my-section",
  "title": "My Section",
  "keywords": ["keyword1"],
  "content": [...]
}

更新區塊

PUT /_emdash/api/sections/:slug

刪除區塊

DELETE /_emdash/api/sections/:slug

設定端點

取得所有設定

GET /_emdash/api/settings

更新設定

POST /_emdash/api/settings
Content-Type: application/json

{
  "siteTitle": "My Site",
  "tagline": "A great site",
  "postsPerPage": 10
}

選單端點

列出選單

GET /_emdash/api/menus

取得選單

GET /_emdash/api/menus/:name

建立選單

POST /_emdash/api/menus
Content-Type: application/json

{
  "name": "main",
  "label": "Main Navigation",
  "items": []
}

更新選單

PUT /_emdash/api/menus/:name

刪除選單

DELETE /_emdash/api/menus/:name

新增選單項目

POST /_emdash/api/menus/:name/items
Content-Type: application/json

{
  "label": "About",
  "url": "/about",
  "position": 0
}

重新排序選單項目

POST /_emdash/api/menus/:name/reorder
Content-Type: application/json

{
  "itemIds": ["item_1", "item_2", "item_3"]
}

分類法端點

列出分類法定義

GET /_emdash/api/taxonomies

建立分類法

POST /_emdash/api/taxonomies
Content-Type: application/json

{
  "name": "categories",
  "label": "Categories",
  "hierarchical": true,
  "collections": ["posts"]
}

列出術語

GET /_emdash/api/taxonomies/:name/terms

建立術語

POST /_emdash/api/taxonomies/:name/terms
Content-Type: application/json

{
  "slug": "tutorials",
  "label": "Tutorials",
  "parentId": "term_abc",
  "description": "How-to guides"
}

更新術語

PUT /_emdash/api/taxonomies/:name/terms/:slug

刪除術語

DELETE /_emdash/api/taxonomies/:name/terms/:slug

設定條目術語

POST /_emdash/api/content/:collection/:id/terms/:taxonomy
Content-Type: application/json

{
  "termIds": ["term_news", "term_featured"]
}

小工具區域端點

列出小工具區域

GET /_emdash/api/widget-areas

取得小工具區域

GET /_emdash/api/widget-areas/:name

建立小工具區域

POST /_emdash/api/widget-areas
Content-Type: application/json

{
  "name": "sidebar",
  "label": "Main Sidebar",
  "description": "Appears on posts"
}

刪除小工具區域

DELETE /_emdash/api/widget-areas/:name

新增小工具

POST /_emdash/api/widget-areas/:name/widgets
Content-Type: application/json

{
  "type": "content",
  "title": "About",
  "content": [...]
}

更新小工具

PUT /_emdash/api/widget-areas/:name/widgets/:id

刪除小工具

DELETE /_emdash/api/widget-areas/:name/widgets/:id

重新排序小工具

POST /_emdash/api/widget-areas/:name/reorder
Content-Type: application/json

{
  "widgetIds": ["widget_1", "widget_2", "widget_3"]
}

使用者管理端點

列出使用者

GET /_emdash/api/admin/users
GET /_emdash/api/admin/users?role=40
GET /_emdash/api/admin/users?search=john

取得使用者

GET /_emdash/api/admin/users/:id

更新使用者

PUT /_emdash/api/admin/users/:id
Content-Type: application/json

{
  "name": "John Doe",
  "role": 40
}

啟用使用者

POST /_emdash/api/admin/users/:id/enable

停用使用者

POST /_emdash/api/admin/users/:id/disable

認證端點

設定狀態

GET /_emdash/api/setup/status

回傳設定是否完成以及是否存在使用者。

Passkey 登入

POST /_emdash/api/auth/passkey/options

取得 WebAuthn 認證選項。

POST /_emdash/api/auth/passkey/verify
Content-Type: application/json

{
  "id": "credential-id",
  "rawId": "...",
  "response": {...},
  "type": "public-key"
}

驗證 Passkey 並建立工作階段。

魔法連結

POST /_emdash/api/auth/magic-link/send
Content-Type: application/json

{
  "email": "[email protected]"
}
GET /_emdash/api/auth/magic-link/verify?token=xxx

登出

POST /_emdash/api/auth/logout

目前使用者

GET /_emdash/api/auth/me

邀請使用者

POST /_emdash/api/auth/invite
Content-Type: application/json

{
  "email": "[email protected]",
  "role": 30
}

Passkey 管理

GET /_emdash/api/auth/passkey

列出使用者的 Passkey。

POST /_emdash/api/auth/passkey/register/options
POST /_emdash/api/auth/passkey/register/verify

註冊新 Passkey。

PATCH /_emdash/api/auth/passkey/:id
Content-Type: application/json

{
  "name": "MacBook Pro"
}

重新命名 Passkey。

DELETE /_emdash/api/auth/passkey/:id

刪除 Passkey。

匯入端點

分析 WordPress 匯出

POST /_emdash/api/import/wordpress/analyze
Content-Type: multipart/form-data

file: <WXR file>

執行 WordPress 匯入

POST /_emdash/api/import/wordpress/execute
Content-Type: application/json

{
  "analysisId": "...",
  "options": {
    "includeMedia": true,
    "includeTaxonomies": true,
    "includeMenus": true
  }
}

速率限制

API 端點可能根據部署設定進行速率限制。速率限制時,回應包含:

HTTP/1.1 429 Too Many Requests
Retry-After: 60

CORS

API 支援瀏覽器請求的 CORS。在部署中設定允許的來源。