EmDash 在 /_emdash/api/ 下公開其支援的應用程式設計介面(API)。請使用產生的 OpenAPI 3.1 文件查看請求參數、請求主體、回應 schema、狀態碼以及用戶端產生資訊:
GET /_emdash/api/openapi.json
該文件由 API 使用的同一套 Zod schema 產生,並反映所設定的最大媒體上傳大小。
公開契約邊界
OpenAPI 文件是所支援 REST API 的邊界。EmDash 還有管理介面與協定工作流的路由。原始碼中存在但未出現在 OpenAPI 中的路由,對外部用戶端而言不是受支援的 REST 操作。
這一區分適用於備份、署名管理、關係遍歷、外掛管理、安裝、匯入與認證等路由。備份請參閱備份指南;受支援的署名管理請使用 MCP 署名工具。OAuth 端點是協定端點,請透過 MCP OAuth 章節 中的詮釋資料探索,而不要將其當作應用 REST 端點。
認證與授權
大多數操作接受 EmDash 工作階段 cookie 或 Bearer 權杖。在 Authorization 標頭中傳送個人存取權杖或 OAuth 存取權杖:
Authorization: Bearer $EMDASH_TOKEN
Bearer 權杖受其 scope 與關聯使用者角色限制。工作階段請求使用使用者角色。授權模型請參閱使用者角色與權杖 scope。
GET 與 POST /_emdash/api/comments/{collection}/{contentId} 為公開介面。GET 傳回已核准評論;POST 提交待審核評論。其餘評論審核操作需要認證。
跨站請求偽造防護
透過工作階段 cookie 認證的狀態變更請求需包含此標頭:
X-EmDash-Request: 1
Bearer 權杖請求不需要該標頭,因其不使用瀏覽器隱式憑證。瀏覽器對公開寫入操作的請求須傳送該標頭,或 Origin 與 EmDash 站點的公開/請求來源一致。
回應封裝
成功的 JSON 回應會將 success 設為 true,並在 data 中放置操作特定結果:
{
"success": true,
"data": {
"items": []
}
}
錯誤時 success 為 false,並包含穩定的機器可讀程式碼與訊息。部分錯誤還包含結構化 details:
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Content item not found"
}
}
請使用各 OpenAPI 操作的狀態碼與錯誤 schema。常見狀態:400 無效輸入,401 憑證缺失或無效,403 scope 或權限不足,404 資源不存在,409 狀態衝突,413 上傳過大,422 外掛拒絕儲存,500 內部錯誤。
端點清單
操作 ID 在產生的契約中穩定,OpenAPI 用戶端產生器常將其用作方法名。以下清單與產生的 OpenAPI 文件對照校驗。
內容
| 方法 | 路徑 | 操作 | 摘要 |
|---|---|---|---|
GET | /_emdash/api/content/{collection} | listContent | List content items |
POST | /_emdash/api/content/{collection} | createContent | Create a content item |
GET | /_emdash/api/content/{collection}/{id} | getContent | Get a content item |
PUT | /_emdash/api/content/{collection}/{id} | updateContent | Update a content item |
DELETE | /_emdash/api/content/{collection}/{id} | deleteContent | Delete a content item (soft delete) |
POST | /_emdash/api/content/{collection}/{id}/publish | publishContent | Publish a content item |
POST | /_emdash/api/content/{collection}/{id}/unpublish | unpublishContent | Unpublish a content item |
POST | /_emdash/api/content/{collection}/{id}/schedule | scheduleContent | Schedule content for future publishing |
DELETE | /_emdash/api/content/{collection}/{id}/schedule | unscheduleContent | Cancel scheduled publishing |
POST | /_emdash/api/content/{collection}/{id}/duplicate | duplicateContent | Duplicate a content item |
POST | /_emdash/api/content/{collection}/{id}/restore | restoreContent | Restore a content item from trash |
DELETE | /_emdash/api/content/{collection}/{id}/permanent | permanentDeleteContent | Permanently delete a content item |
GET | /_emdash/api/content/{collection}/{id}/compare | compareContent | Compare live and draft revisions |
POST | /_emdash/api/content/{collection}/{id}/discard-draft | discardDraft | Discard draft changes |
GET | /_emdash/api/content/{collection}/{id}/lock | getEntryLock | Read the entry’s edit lock |
POST | /_emdash/api/content/{collection}/{id}/lock | acquireEntryLock | Take or refresh the entry’s edit lock |
DELETE | /_emdash/api/content/{collection}/{id}/lock | releaseEntryLock | Release the caller’s edit lock |
GET | /_emdash/api/content/{collection}/{id}/translations | getContentTranslations | Get translations for a content item |
GET | /_emdash/api/content/{collection}/{id}/terms/{taxonomy} | getContentTerms | Get taxonomy terms assigned to a content item |
POST | /_emdash/api/content/{collection}/{id}/terms/{taxonomy} | setContentTerms | Set taxonomy terms on a content item |
GET | /_emdash/api/content/{collection}/authors | listContentAuthors | List distinct authors of a collection’s content |
GET | /_emdash/api/content/{collection}/trash | listTrashedContent | List trashed content items |
媒體
| 方法 | 路徑 | 操作 | 摘要 |
|---|---|---|---|
GET | /_emdash/api/media | listMedia | List media items |
POST | /_emdash/api/media | uploadMedia | Upload a media item |
GET | /_emdash/api/media/folders | listMediaFolders | List media folders |
POST | /_emdash/api/media/folders | createMediaFolder | Create a media folder |
GET | /_emdash/api/media/folders/{id} | getMediaFolder | Get a media folder |
PUT | /_emdash/api/media/folders/{id} | updateMediaFolder | Update a media folder |
DELETE | /_emdash/api/media/folders/{id} | deleteMediaFolder | Delete a media folder |
GET | /_emdash/api/media/{id} | getMedia | Get a media item |
PUT | /_emdash/api/media/{id} | updateMedia | Update media metadata |
DELETE | /_emdash/api/media/{id} | deleteMedia | Delete a media item |
GET | /_emdash/api/media/{id}/usage | getMediaUsage | Get media usage details |
PUT | /_emdash/api/media/{id}/replace | replaceMediaImage | Replace a media image |
POST | /_emdash/api/admin/media-usage/repair | repairMediaUsage | Repair media usage indexes |
GET | /_emdash/api/admin/media-usage/progress | getMediaUsageProgress | Get media usage indexing progress |
POST | /_emdash/api/admin/media-usage/progress | advanceMediaUsageProgress | Advance media usage indexing |
GET | /_emdash/api/admin/media-usage/work | listMediaUsageWork | List durable media usage work |
GET | /_emdash/api/admin/media-usage/activation | getMediaUsageActivation | Get media usage activation status |
POST | /_emdash/api/admin/media-usage/activation | advanceMediaUsageActivation | Advance media usage activation |
POST | /_emdash/api/admin/media-usage/work/retry | retryMediaUsageWork | Retry one durable media usage job |
GET | /_emdash/api/admin/media-usage/collection-deletions | listMediaUsageCollectionDeletions | List durable collection deletions |
POST | /_emdash/api/admin/media-usage/collection-deletions/retry | retryMediaUsageCollectionDeletion | Retry one collection deletion |
POST | /_emdash/api/media/upload-url | getMediaUploadUrl | Get a media upload target |
POST | /_emdash/api/media/{id}/confirm | confirmMediaUpload | Confirm a media upload |
PUT | /_emdash/api/media/{id}/upload | uploadPendingMedia | Upload a pending media file through EmDash |
Schema
| 方法 | 路徑 | 操作 | 摘要 |
|---|---|---|---|
GET | /_emdash/api/schema/block-types | listBlockTypes | List block types |
POST | /_emdash/api/schema/block-types | createBlockType | Create a block type |
GET | /_emdash/api/schema/block-types/{slug} | getBlockType | Get a block type |
PUT | /_emdash/api/schema/block-types/{slug} | updateBlockType | Update a block type |
POST | /_emdash/api/schema/block-types/{slug}/versions/{version}/activate | activateBlockTypeVersion | Activate a block type version |
GET | /_emdash/api/schema/collections | listCollections | List all collections |
POST | /_emdash/api/schema/collections | createCollection | Create a collection |
GET | /_emdash/api/schema/collections/{slug} | getCollection | Get a collection |
PUT | /_emdash/api/schema/collections/{slug} | updateCollection | Update a collection |
DELETE | /_emdash/api/schema/collections/{slug} | deleteCollection | Delete a collection |
GET | /_emdash/api/schema/collections/{slug}/fields | listFields | List fields for a collection |
POST | /_emdash/api/schema/collections/{slug}/fields | createField | Create a field |
GET | /_emdash/api/schema/collections/{slug}/fields/{fieldSlug} | getField | Get a field |
PUT | /_emdash/api/schema/collections/{slug}/fields/{fieldSlug} | updateField | Update a field |
DELETE | /_emdash/api/schema/collections/{slug}/fields/{fieldSlug} | deleteField | Delete a field |
POST | /_emdash/api/schema/collections/reorder | reorderCollections | Reorder collections in the admin sidebar |
POST | /_emdash/api/schema/collections/{slug}/fields/reorder | reorderFields | Reorder fields in a collection |
GET | /_emdash/api/schema/orphans | listOrphanedTables | List orphaned content tables |
POST | /_emdash/api/schema/orphans/{slug} | registerOrphanedTable | Register an orphaned table as a collection |
評論
| 方法 | 路徑 | 操作 | 摘要 |
|---|---|---|---|
GET | /_emdash/api/comments/{collection}/{contentId} | listPublicComments | List approved comments for content |
POST | /_emdash/api/comments/{collection}/{contentId} | createComment | Submit a new comment |
GET | /_emdash/api/admin/comments | listAdminComments | List comments for moderation |
GET | /_emdash/api/admin/comments/counts | getCommentCounts | Get comment status counts |
POST | /_emdash/api/admin/comments/bulk | bulkCommentAction | Bulk approve, spam, trash, or delete comments |
GET | /_emdash/api/admin/comments/{id} | getComment | Get a single comment |
DELETE | /_emdash/api/admin/comments/{id} | deleteComment | Permanently delete a comment |
PUT | /_emdash/api/admin/comments/{id}/status | updateCommentStatus | Change comment status |
分類法
| 方法 | 路徑 | 操作 | 摘要 |
|---|---|---|---|
GET | /_emdash/api/taxonomies | listTaxonomies | List all taxonomy definitions |
GET | /_emdash/api/taxonomies/{name} | getTaxonomy | Get a taxonomy definition |
PUT | /_emdash/api/taxonomies/{name} | updateTaxonomy | Update a taxonomy definition |
DELETE | /_emdash/api/taxonomies/{name} | deleteTaxonomy | Delete a taxonomy, its terms, and their content assignments |
GET | /_emdash/api/taxonomies/{name}/translations | listTaxonomyTranslations | List every locale variant of a taxonomy definition |
POST | /_emdash/api/taxonomies/{name}/reorder | reorderTerms | Set the manual order of one sibling group of terms |
GET | /_emdash/api/taxonomies/{name}/terms | listTerms | List terms for a taxonomy |
POST | /_emdash/api/taxonomies/{name}/terms | createTerm | Create a term |
GET | /_emdash/api/taxonomies/{name}/terms/{slug} | getTerm | Get a term by slug |
PUT | /_emdash/api/taxonomies/{name}/terms/{slug} | updateTerm | Update a term |
DELETE | /_emdash/api/taxonomies/{name}/terms/{slug} | deleteTerm | Delete a term |
選單
| 方法 | 路徑 | 操作 | 摘要 |
|---|---|---|---|
GET | /_emdash/api/menus | listMenus | List all menus with item counts |
POST | /_emdash/api/menus | createMenu | Create a menu |
GET | /_emdash/api/menus/{name} | getMenu | Get a menu with all items |
PUT | /_emdash/api/menus/{name} | updateMenu | Update a menu |
DELETE | /_emdash/api/menus/{name} | deleteMenu | Delete a menu and its items |
POST | /_emdash/api/menus/{name}/items | createMenuItem | Add an item to a menu |
PUT | /_emdash/api/menus/{name}/items/{id} | updateMenuItem | Update a menu item |
DELETE | /_emdash/api/menus/{name}/items/{id} | deleteMenuItem | Delete a menu item |
POST | /_emdash/api/menus/{name}/reorder | reorderMenuItems | Batch reorder menu items |
區段
| 方法 | 路徑 | 操作 | 摘要 |
|---|---|---|---|
GET | /_emdash/api/sections | listSections | List sections |
POST | /_emdash/api/sections | createSection | Create a section |
GET | /_emdash/api/sections/{slug} | getSection | Get a section by slug |
PUT | /_emdash/api/sections/{slug} | updateSection | Update a section |
DELETE | /_emdash/api/sections/{slug} | deleteSection | Delete a section |
小工具
| 方法 | 路徑 | 操作 | 摘要 |
|---|---|---|---|
GET | /_emdash/api/widget-areas | listWidgetAreas | List all widget areas |
POST | /_emdash/api/widget-areas | createWidgetArea | Create a widget area |
GET | /_emdash/api/widget-areas/{name} | getWidgetArea | Get a widget area with widgets |
DELETE | /_emdash/api/widget-areas/{name} | deleteWidgetArea | Delete a widget area and its widgets |
POST | /_emdash/api/widget-areas/{name}/widgets | createWidget | Add a widget to an area |
PUT | /_emdash/api/widget-areas/{name}/widgets/{id} | updateWidget | Update a widget |
DELETE | /_emdash/api/widget-areas/{name}/widgets/{id} | deleteWidget | Delete a widget |
POST | /_emdash/api/widget-areas/{name}/reorder | reorderWidgets | Reorder widgets in an area |
設定
| 方法 | 路徑 | 操作 | 摘要 |
|---|---|---|---|
GET | /_emdash/api/settings | getSettings | Get site settings |
PUT | /_emdash/api/settings | updateSettings | Update site settings |
搜尋
| 方法 | 路徑 | 操作 | 摘要 |
|---|---|---|---|
GET | /_emdash/api/search | search | Full-text search across collections |
GET | /_emdash/api/search/suggest | searchSuggest | Autocomplete search suggestions |
POST | /_emdash/api/search/rebuild | rebuildSearchIndex | Rebuild the search index for a collection |
POST | /_emdash/api/search/enable | enableSearch | Enable or disable search for a collection |
GET | /_emdash/api/search/stats | getSearchStats | Get search index statistics |
重新導向
| 方法 | 路徑 | 操作 | 摘要 |
|---|---|---|---|
GET | /_emdash/api/redirects | listRedirects | List redirects |
POST | /_emdash/api/redirects | createRedirect | Create a redirect rule |
GET | /_emdash/api/redirects/{id} | getRedirect | Get a redirect |
PUT | /_emdash/api/redirects/{id} | updateRedirect | Update a redirect |
DELETE | /_emdash/api/redirects/{id} | deleteRedirect | Delete a redirect |
GET | /_emdash/api/redirects/404s | listNotFoundEntries | List 404 log entries |
POST | /_emdash/api/redirects/404s | pruneNotFoundLog | Prune old 404 log entries |
DELETE | /_emdash/api/redirects/404s | clearNotFoundLog | Clear all 404 log entries |
GET | /_emdash/api/redirects/404s/summary | getNotFoundSummary | Get 404 summary grouped by path |
使用者
| 方法 | 路徑 | 操作 | 摘要 |
|---|---|---|---|
GET | /_emdash/api/admin/users | listUsers | List users |
GET | /_emdash/api/admin/users/{id} | getUser | Get user details |
PUT | /_emdash/api/admin/users/{id} | updateUser | Update a user |
POST | /_emdash/api/admin/users/{id}/disable | disableUser | Disable a user account |
POST | /_emdash/api/admin/users/{id}/enable | enableUser | Enable a user account |
GET | /_emdash/api/admin/allowed-domains | listAllowedDomains | List allowed email domains |
POST | /_emdash/api/admin/allowed-domains | createAllowedDomain | Add an allowed email domain |
PUT | /_emdash/api/admin/allowed-domains/{domain} | updateAllowedDomain | Update an allowed domain |
DELETE | /_emdash/api/admin/allowed-domains/{domain} | deleteAllowedDomain | Remove an allowed domain |
站點遷移
| 方法 | 路徑 | 操作 | 摘要 |
|---|---|---|---|
GET | /_emdash/api/admin/transfer/capabilities | getTransferCapabilities | Get site transfer capabilities |
GET | /_emdash/api/admin/transfer/imports | listTransferImports | List site imports |
POST | /_emdash/api/admin/transfer/imports | createTransferImport | Create a site import |
GET | /_emdash/api/admin/transfer/imports/{id} | getTransferImport | Get a site import |
GET | /_emdash/api/admin/transfer/imports/{id}/missing | listTransferImportMissingFiles | List package files still to upload |
PUT | /_emdash/api/admin/transfer/imports/{id}/files/{path} | uploadTransferImportFile | Upload one package file |
POST | /_emdash/api/admin/transfer/imports/{id}/analyze | analyzeTransferImport | Advance import analysis |
GET | /_emdash/api/admin/transfer/imports/{id}/plan | getTransferImportPlan | Get an import plan |
POST | /_emdash/api/admin/transfer/imports/{id}/cancel | cancelTransferImport | Cancel a site import |
POST | /_emdash/api/admin/transfer/imports/{id}/abandon | abandonTransferImport | Abandon a failed or cancelled import |
POST | /_emdash/api/admin/transfer/imports/{id}/execute | executeTransferImport | Start a planned import |
POST | /_emdash/api/admin/transfer/imports/{id}/advance | advanceTransferImport | Advance an executing import |
GET | /_emdash/api/admin/transfer/imports/{id}/receipt | getTransferImportReceipt | Get an import receipt |
GET | /_emdash/api/admin/transfer/exports | listTransferExports | List site exports |
POST | /_emdash/api/admin/transfer/exports | createTransferExport | Start a site export |
GET | /_emdash/api/admin/transfer/exports/{id} | getTransferExport | Get a site export |
POST | /_emdash/api/admin/transfer/exports/{id}/advance | advanceTransferExport | Advance a site export |
GET | /_emdash/api/admin/transfer/exports/{id}/manifest | getTransferExportManifest | Download an export manifest |
GET | /_emdash/api/admin/transfer/exports/{id}/files/{path} | downloadTransferExportFile | Download one export file |
GET | /_emdash/api/admin/transfer/exports/{id}/archive | downloadTransferExportArchive | Download an export archive |
GET | /_emdash/api/admin/transfer/approvals | listTransferApprovals | List transfer approvals |
POST | /_emdash/api/admin/transfer/approvals/{id}/approve | approveTransferApproval | Approve a transfer request |
POST | /_emdash/api/admin/transfer/approvals/{id}/deny | denyTransferApproval | Deny a transfer request |
內容生命週期與署名
內容生命週期參考 定義了 REST、MCP、CLI 與管理後台共享的狀態、修訂、權限、衝突與掛鉤行為。
內容讀取在可用時會傳回不透明的 _rev 權杖。在 PUT /content/{collection}/{id} 時附带 _rev,以免覆蓋自讀取以来发生的变更。過期的權杖會產生冲突;重试前請再次讀取項目。CLI 對 content update 強制此檢查,而 REST 欄位對有意選擇无条件寫入的用戶端仍為可选。
讀取並更新項目
修改前先讀取項目:
GET /_emdash/api/content/articles/01JARTICLE0000000000000000
Authorization: Bearer $EMDASH_TOKEN
回應包含其欄位、發佈狀態與修订權杖:
{
"success": true,
"data": {
"item": {
"id": "01JARTICLE0000000000000000",
"type": "articles",
"slug": "launch-notes",
"status": "published",
"data": { "title": "Launch notes" }
},
"_rev": "opaque-revision-token"
}
}
仅傳送需要变更的欄位,以及該次讀取得到的權杖:
PUT /_emdash/api/content/articles/01JARTICLE0000000000000000
Authorization: Bearer $EMDASH_TOKEN
Content-Type: application/json
{
"data": { "title": "Updated launch notes" },
"_rev": "opaque-revision-token"
}
修改已發佈項目會创建草稿,先前版本仍保持线上。调用 compare 操作查看两個版本,然后發佈草稿或丢弃。取消發佈會保留內容及其發佈日期、取消任何待执行计划,並將項目从线上站點移除。
创建與更新請求体可接受署名 credits,內容回應包含主署名與有序 credits。內容列表可按存储的署名 ID 筛选,並可選擇包含作者推断的署名。署名记录本身的创建與管理通過 MCP 署名工具 提供,不在公開 REST 契約内。
生命周期操作区分软删除與永久删除。還原會將回收站內容恢复為无计划的草稿;永久删除會移除回收站中的項目且不可撤销。發佈、取消發佈、计划、取消计划、比较、丢弃草稿與复制是独立操作,用戶端可一次請求一种狀態转换。
項目編輯鎖
編輯者打开項目時,集合可获取七分钟編輯锁。使用 /content/{collection}/{id}/lock 上的三個操作来讀取、获取或刷新以及释放租约。
讀取或获取回應會显示是否启用锁定、调用方是否持有租约以及当前持有者:
{
"success": true,
"data": {
"enabled": true,
"heldByCaller": false,
"holder": {
"userId": "01JUSER000000000000000000",
"userName": "Ada",
"acquiredAt": "2026-05-01T09:12:04.117Z",
"expiresAt": "2026-05-01T09:19:04.117Z"
}
}
}
集合禁用編輯锁時,enabled 為 false 且不會占用租约。再次获取同一把锁並保存項目都會延长调用方持有的租约。
获取請求体可包含标识单次編輯工作階段的不透明 token,以及使用者選擇取代其他編輯者租约時的 takeover: true。释放锁時將同一 token 作為查询参数传入。同一账户的第二個标签页便无法误释放第一個标签页的租约。
当其他使用者持有租约時,受保护的內容寫入傳回 409 ENTRY_LOCKED。錯誤 details 标明持有者與過期時间。要覆蓋锁,在有請求体的寫入 JSON 中傳送 "overrideLock": true,或對无請求体的 DELETE 操作使用 ?overrideLock=true。
引用選擇
reference 欄位 通過关系將項目链接到另一集合中的項目。其值不属于 data,且按翻译组键控,因此項目的各语言翻译共享同一選擇。
创建與更新請求体在 references 下携带選擇,按欄位 slug 键控,每项為最多 1000 個項目 ID 的数组,顺序為展示顺序。EmDash 在與項目同一事务中寫入選擇。以下更新替换項目的作者:
PUT /_emdash/api/content/articles/01JARTICLE0000000000000000
Authorization: Bearer $EMDASH_TOKEN
Content-Type: application/json
{
"data": { "title": "Updated launch notes" },
"references": { "author": ["01JAUTHOR00000000000000000"] },
"_rev": "opaque-revision-token"
}
绑定到关系子端的欄位會選擇指向当前寫入項目的項目,這些項目本身没有顺序。关系两端都會強制执行限制,因此若選擇會使链接項目拥有超過关系允许的上级数量,會與链接過多項目一样被拒绝。
在保留修订的集合上,已發佈項目上变更的選擇會與項目其他待处理編輯一起暂存于草稿。項目發佈時生效,随草稿丢弃。發佈會针對关系限制重新檢查整個選擇。
单項目讀取傳回按欄位 slug 键控的 references。每個欄位包含其链接項目的第一页(50 条),若還有更多则带 nextCursor,並报告各項目的 ID、slug、集合、展示标题、解析后的 locale 與翻译组。可讀取草稿的调用方會看到草稿中暂存的選擇。內容列表操作不包含 references。
关系定义與链接遍历是管理路由,不在 OpenAPI 中,也不属于公開契約。通過上述內容操作寫入與讀取選擇,並在站點上使用 getEmDashEntry() 與 getEmDashReferences() 渲染。
翻譯
公開 REST 契約暴露內容翻译與分类法定义翻译。內容创建接受 translationOf,分类法创建使用同一欄位添加 locale 变体。內容-术语操作傳回感知 locale 的分配。
省略 locale 時,GET /taxonomies/{name} 傳回站點默认 locale 的定义;仅当默认 locale 无定义時才回退到最低 locale 代码。更新行為不同:省略 locale 時會修改最低 locale 代码的定义。請传入 locale,使翻译分类法的更新作用于目标定义。若該 locale 无定义,更新傳回 NOT_FOUND 而非回退到其他 locale。translations 操作傳回共享组中的全部定义,並提供 translationOf 接受的 ID。
label 與 labelSingular 属于某一 locale 的定义。hierarchical 與 collections 属于分类法:各 locale 傳回相同值,更新中傳送任一项會改变所有 locale。為已在其他 locale 存在的名称创建定义會加入該分类法,无论請求是否傳送 translationOf。新定义采用分类法的 hierarchical 與 collections;创建時傳送不同值會傳回 VALIDATION_ERROR。
删除分类法會移除其定义的所有 locale、全部术语以及這些术语對內容的全部分配,不會删除內容項目本身。
术语重排操作改变一個兄弟组。ids 数组可只包含該组的一部分;列出的术语交换现有位置,未列出的术语保持原位。例如對 [A, B, C] 用 ids: ["C", "A"] 重排得到 [C, B, A]。重排不改变父子关系,同一术语顺序适用于其翻译组中的各 locale。
選單、分类法术语與署名翻译路由不在公開 REST 契約内。其受支持的翻译列表可通過 MCP 服务器 上的 menu_translations、taxonomy_term_translations 與 byline_translations 获取。
媒體端點
媒體操作涵盖列表、上傳、元数据更新、图片替换、資料夾、使用信息與使用索引维护。媒體库指南 说明面向使用者的工作流及使用覆蓋的含义。
列出與檢視媒體
GET /media 支持游标或页码分页、MIME 类型與文件名筛选、資料夾以及可选的使用摘要。省略 folderId 包含所有資料夾,或传入 folderId=unfiled 仅傳回主库。列表或单项讀取時设置 includeUsage=1 以包含使用信息;其他值无效。
usage.count 统计当前索引源引用該媒體项的不同活跃內容行或 locale,以及選擇它的各站點设置(logo、favicon、seo.defaultOgImage)。同一項目内重复引用只计一次,回收站項目不计入。仅可讀取草稿的调用方可见該数字;其他已授權媒體读者收到 count: null,因為计数可能泄露草稿內容。
GET /media/{id}/usage 分页傳回引用該媒體的內容項目。每页還包含 siteSettings(選擇該媒體项的站點设置),例如 [{ "setting": "favicon" }]。站點设置每次請求从存储的设置讀取,不依赖使用索引。
每個使用结果包含覆蓋狀態:
| 狀態 | 含义 |
|---|---|
complete | 每個已注册集合都有当前使用覆蓋。 |
never | 没有已注册集合完成初始使用修復。 |
running | 修復进行中。 |
partial | 仅部分已注册集合有当前覆蓋。 |
failed | 已注册集合集上的覆蓋失败。 |
stale | 索引早于其所描述的內容。 |
unknown | 存储狀態不被此 EmDash 版本识别。 |
仅 complete 支持在已索引欄位类型内將零计数视為完整。並发寫入期间计数仅供参考;不會锁定媒體项或保证删除安全。使用索引覆蓋图片與文件欄位、Repeater 图片欄位、Portable Text 图片與图库块,以及 EmDash 集合中保留块版本声明的媒體。站點 logo、favicon 與默认社交图设置也會报告。使用不包括自定义 Portable Text 块、应用代码、渲染 HTML、其他设置、選單、小部件、插件数据、外部站點或仅提供商资产。
直接 multipart 上傳
通過 multipart 請求將文件作為 file 欄位 POST 到 EmDash:
curl --request POST \
--header "Authorization: Bearer $EMDASH_TOKEN" \
--form "file=@./cover.jpg;type=image/jpeg" \
https://example.com/_emdash/api/media
curl 會自动添加 multipart 边界。請勿手动设置 Content-Type 標頭。OpenAPI MediaDirectUploadBody schema 列出可选元数据欄位,回應 schema 区分新上傳與去重后的现有项。
multipart 請求体還可包含图片 width、height、应应用 MIME 类型 allowlist 的 fieldId,以及用于创建低质量占位符的缩小 thumbnail。新文件傳回 201 Created 並立即可用。相同字节傳回现有媒體项,200 OK 且 deduplicated: true。
上傳目標流程
当用戶端可直接上傳到 S3 兼容存储時使用上傳目标流程。媒體项保持 pending,确认成功前不會出现在标准库中。
-
請求上傳目标
POST /_emdash/api/media/upload-url Authorization: Bearer $EMDASH_TOKEN Content-Type: application/json { "filename": "cover.jpg", "contentType": "image/jpeg", "size": 102400 }回應提供
uploadUrl、method、headers、mediaId、storageKey與過期時间。当contentHash與相同 MIME 类型與大小的现有文件匹配時,回應改為设置existing: true;使用該媒體项,勿再上傳或确认另一份副本。 -
上傳字节
使用傳回的 method 與 headers。將根相對 URL 解析為 EmDash 站點並包含 Bearer 權杖。向其他源的绝對 URL 仅傳送傳回的上傳 headers。
-
确认上傳
POST /_emdash/api/media/01JMEDIA000000000000000000/confirm Authorization: Bearer $EMDASH_TOKEN Content-Type: application/json { "size": 102400, "width": 1920, "height": 1080 }确认會校验存储對象並將项从
pending变為ready。提供的 size 與尺寸必须與上傳文件一致。
本地存储與原生 R2 傳回同源的 EmDash 上傳目标。S3 兼容存储可能傳回签名的外部 URL。pending 项在确认成功前不會出现在标准媒體列表中。
上傳錯誤
以下錯誤需要不同的恢复操作:
| 狀態 | 代码 | 操作 |
|---|---|---|
400 | NO_FILE | 在 multipart 請求中添加 file 欄位,或傳送缺失的上傳体。 |
400 | INVALID_TYPE | 使用與 pending 媒體项匹配的允许 MIME 类型。 |
400 | VALIDATION_ERROR | 修正缺失或无效的元数据,包括超過配置大小限制的值。 |
400 | FILE_NOT_FOUND | 确认前先將對象上傳到傳回的目标。 |
400 | UPLOAD_SIZE_MISMATCH | 以正确 size 重新开始流程;声明、上傳與确认的 size 必须一致。 |
400 或 409 | INVALID_STATE | 重试前讀取媒體项。它可能已非 pending,或在确认期间被其他請求更改。 |
404 | NOT_FOUND | 使用现有的 pending 媒體 ID。 |
413 | PAYLOAD_TOO_LARGE | 减小文件大小或增大 maxUploadSize 后再开始上傳。 |
媒體資料夾
資料夾名称會 trim、限制 200 字符,並在 Unicode 规范化與小写后比较。因此 Photos、photos 與 PHOTOS 等名称會冲突。删除資料夾會將其媒體移回主库;不會删除媒體、更改媒體 ID 或 URL,或更改使用记录。
修復媒體使用
媒體使用激活、进度、工作队列、删除清理與修復是 /_emdash/api/admin/media-usage/ 下的运维操作。工作階段使用者需要 schema:manage;Bearer 權杖還需要 admin scope。
跟踪关闭時,激活前暂停直接写数据库的进程。EmDash 在设置运行期间會暂時阻止通過其 API 傳送的內容與 schema 寫入,但无法阻止直接写数据库的其他进程。
- 停止直接写数据库的进程,等待进行中的寫入完成。
- 讀取激活狀態。
expanded表示跟踪关闭,activating表示 EmDash 正在准备集合,active表示新的媒體引用变更會被跟踪。 - 傳送一次激活請求
{ "writersDrained": true }。 - 逐次傳送进度請求,等待每次傳回的
nextRequestInMs,直到激活為active。 - 恢复直接写数据库。
- 继续进度請求,直到历史索引為
ready且nextRequestInMs為null。
若寫入請求超時或傳回 409 或 500,重试前讀取激活與进度狀態。已完成的批次仍會记录。当设置 lastErrorCode 時,保持直接寫入停止,解决报告的问题,並傳送一次确认的重试。激活开始后无法取消或重置,請在 staging 副本上测试此流程並保持当前数据库备份。
工作列表操作暴露失败或延迟的項目索引,不傳回內容、媒體引用、租约權杖、原始数据库錯誤或精确积压计数。重试单项是幂等的。409 WORK_LEASE_ACTIVE 表示 worker 仍在处理該项;回應包含 details.leaseExpiresAt,請等到該時间並再次讀取项后再重试。409 WORK_CHANGED 表示其他請求更改了工作项;讀取其当前狀態,勿覆蓋较新的工作。
修復操作接受 { "scope": "collection", "collection": "articles" } 或 { "scope": "all" }。全集合修復同步且顺序执行,大型站點可能耗時很长。200 回應仍可能报告 partial、failed 或 stale;在视為修復完成前檢查 data.status、各集合狀態與源计数。
站點遷移
/_emdash/api/admin/transfer/ 下的遷移操作將站點导出為站點包並导入到空站點。站點遷移指南 描述导出、上傳、分析、执行與回执工作流。
工作階段使用者需要 transfer:export 或 transfer:import 权限,仅管理员持有。Bearer 權杖需要 admin 或各操作指定的 transfer:export、transfer:analyze 或 transfer:execute scope。审批操作仅接受已登录工作階段。它们裁决 MCP site_export_start 與 site_import_start 工具发起的請求;REST 导出與执行操作不需要审批。
导入执行期间,以及失败或取消后直至放弃之前,大多数其他寫入操作傳回 503 TRANSFER_IMPORT_IN_PROGRESS。指南列出导入期间仍可用的操作。
分頁
列表操作在 OpenAPI 中描述其分页参数。大多数游标分页操作接受不透明 cursor 與 1 至 100 的 limit,默认 50。原样傳回上一回應的 nextCursor;請勿解析或构造它。部分媒體操作還支持页码,部分专用列表使用不同 limit,生成的用戶端应遵循各操作的 schema。
搜尋分詞器
search-enable 操作為每個集合存储分词器。在已启用搜索的集合上更改它會重建該集合索引。
| 值 | 用途 |
|---|---|
porter unicode61 | 适合 Porter 词干提取的英文內容的默认值。 |
unicode61 | 使用词分隔符但不应使用英文词干提取的语言。 |
trigram | 无空格文本(含日文、中文、泰文、高棉文、老挝文、缅甸文)或需要子串匹配的集合。少于三個 Unicode 字符的查询无匹配。 |
禁用搜索會保留存储的分词器供下次启用。rebuild 操作使用集合存储的分词器與欄位权重。
評論與重新導向
公開評論提交进入审核队列。管理評論操作列出所有狀態、傳回计数、更新单一狀態、批量审核並永久删除評論。429 回應表示达到提交速率限制。
重定向操作分别管理重定向规则與记录的 404 日志。修剪按請求体所选項目移除,而 DELETE /redirects/404s 清空整個日志。两者均不删除重定向规则。