EmDash expone su interfaz de programación de aplicaciones (API) admitida en /_emdash/api/. Use el documento OpenAPI 3.1 generado para parámetros de solicitud, cuerpos, esquemas de respuesta, códigos de estado y generación de clientes:
GET /_emdash/api/openapi.json
El documento se genera a partir de los mismos esquemas Zod que usa la API. También refleja el tamaño máximo configurado para la subida de medios.
Límite del contrato público
El documento OpenAPI delimita la API REST admitida. EmDash también tiene rutas para su interfaz de administración y flujos de protocolo. Una ruta que existe en el árbol de código pero no aparece en OpenAPI no es una operación REST admitida para clientes externos.
Esta distinción aplica a rutas de copias de seguridad, administración de bylines, recorrido de relaciones, gestión de plugins, configuración inicial, importación y autenticación. Use la guía de copias de seguridad para backups y las herramientas MCP de bylines para la gestión de bylines admitida. Los endpoints OAuth son endpoints de protocolo; descúbralos a partir de los metadatos descritos en la sección OAuth de MCP en lugar de tratarlos como endpoints REST de aplicación.
Autenticación y autorización
La mayoría de las operaciones aceptan una cookie de sesión de EmDash o un token Bearer. Envíe un token de acceso personal o un token de acceso OAuth en el encabezado Authorization:
Authorization: Bearer $EMDASH_TOKEN
Los tokens Bearer están limitados por sus ámbitos (scopes) y el rol del usuario asociado. Las solicitudes con sesión usan el rol del usuario. Consulte roles de usuario y ámbitos de token para el modelo de autorización.
GET y POST /_emdash/api/comments/{collection}/{contentId} son públicos. La operación GET devuelve comentarios aprobados; la operación POST envía un comentario a moderación. El resto de operaciones de moderación de comentarios requieren autenticación.
Protección contra falsificación de solicitudes entre sitios
Para una solicitud que cambia estado y se autentica con una cookie de sesión, incluya este encabezado:
X-EmDash-Request: 1
Las solicitudes con token Bearer no requieren el encabezado porque no usan credenciales ambientales del navegador. Las solicitudes del navegador a una operación de escritura pública deben enviar el encabezado o tener un Origin que coincida con el origen público o de solicitud del sitio EmDash.
Envoltorios de respuesta
Una respuesta JSON correcta establece success en true y coloca el resultado específico de la operación en data:
{
"success": true,
"data": {
"items": []
}
}
Un error establece success en false e incluye un código estable legible por máquina y un mensaje. Algunos errores también incluyen details estructurados:
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Content item not found"
}
}
Use los códigos de estado y los esquemas de error de cada operación OpenAPI. Los estados habituales son 400 para entrada no válida, 401 para credenciales ausentes o no válidas, 403 por ámbito o permiso insuficiente, 404 para un recurso inexistente, 409 por conflicto de estado, 413 por una subida demasiado grande, 422 cuando un plugin rechaza el guardado y 500 por un fallo interno.
Inventario de endpoints
El ID de operación es estable dentro del contrato generado y los generadores de clientes OpenAPI suelen usarlo como nombre de método. El siguiente inventario se contrasta con el documento OpenAPI generado.
Contenido
| Método | Ruta | Operación | Resumen |
|---|---|---|---|
GET | /_emdash/api/content/{collection} | listContent | Listar elementos de contenido |
POST | /_emdash/api/content/{collection} | createContent | Crear un elemento de contenido |
GET | /_emdash/api/content/{collection}/{id} | getContent | Obtener un elemento de contenido |
PUT | /_emdash/api/content/{collection}/{id} | updateContent | Actualizar un elemento de contenido |
DELETE | /_emdash/api/content/{collection}/{id} | deleteContent | Eliminar un elemento de contenido (eliminación lógica) |
POST | /_emdash/api/content/{collection}/{id}/publish | publishContent | Publicar un elemento de contenido |
POST | /_emdash/api/content/{collection}/{id}/unpublish | unpublishContent | Despublicar un elemento de contenido |
POST | /_emdash/api/content/{collection}/{id}/schedule | scheduleContent | Programar contenido para publicación futura |
DELETE | /_emdash/api/content/{collection}/{id}/schedule | unscheduleContent | Cancelar la publicación programada |
POST | /_emdash/api/content/{collection}/{id}/duplicate | duplicateContent | Duplicar un elemento de contenido |
POST | /_emdash/api/content/{collection}/{id}/restore | restoreContent | Restaurar un elemento de contenido desde la papelera |
DELETE | /_emdash/api/content/{collection}/{id}/permanent | permanentDeleteContent | Eliminar permanentemente un elemento de contenido |
GET | /_emdash/api/content/{collection}/{id}/compare | compareContent | Comparar revisiones en vivo y borrador |
POST | /_emdash/api/content/{collection}/{id}/discard-draft | discardDraft | Descartar cambios del borrador |
GET | /_emdash/api/content/{collection}/{id}/lock | getEntryLock | Leer el bloqueo de edición de la entrada |
POST | /_emdash/api/content/{collection}/{id}/lock | acquireEntryLock | Tomar o renovar el bloqueo de edición de la entrada |
DELETE | /_emdash/api/content/{collection}/{id}/lock | releaseEntryLock | Liberar el bloqueo de edición del llamador |
GET | /_emdash/api/content/{collection}/{id}/translations | getContentTranslations | Obtener traducciones de un elemento de contenido |
GET | /_emdash/api/content/{collection}/{id}/terms/{taxonomy} | getContentTerms | Obtener términos de taxonomía asignados a un elemento |
POST | /_emdash/api/content/{collection}/{id}/terms/{taxonomy} | setContentTerms | Establecer términos de taxonomía en un elemento |
GET | /_emdash/api/content/{collection}/authors | listContentAuthors | Listar autores distintos del contenido de una collection |
GET | /_emdash/api/content/{collection}/trash | listTrashedContent | Listar elementos de contenido en la papelera |
Medios
| Método | Ruta | Operación | Resumen |
|---|---|---|---|
GET | /_emdash/api/media | listMedia | Listar elementos multimedia |
POST | /_emdash/api/media | uploadMedia | Subir un elemento multimedia |
GET | /_emdash/api/media/folders | listMediaFolders | Listar carpetas de medios |
POST | /_emdash/api/media/folders | createMediaFolder | Crear una carpeta de medios |
GET | /_emdash/api/media/folders/{id} | getMediaFolder | Obtener una carpeta de medios |
PUT | /_emdash/api/media/folders/{id} | updateMediaFolder | Actualizar una carpeta de medios |
DELETE | /_emdash/api/media/folders/{id} | deleteMediaFolder | Eliminar una carpeta de medios |
GET | /_emdash/api/media/{id} | getMedia | Obtener un elemento multimedia |
PUT | /_emdash/api/media/{id} | updateMedia | Actualizar metadatos de medios |
DELETE | /_emdash/api/media/{id} | deleteMedia | Eliminar un elemento multimedia |
GET | /_emdash/api/media/{id}/usage | getMediaUsage | Obtener detalles de uso de medios |
PUT | /_emdash/api/media/{id}/replace | replaceMediaImage | Reemplazar una imagen multimedia |
POST | /_emdash/api/admin/media-usage/repair | repairMediaUsage | Reparar índices de uso de medios |
GET | /_emdash/api/admin/media-usage/progress | getMediaUsageProgress | Obtener progreso de indexación de uso de medios |
POST | /_emdash/api/admin/media-usage/progress | advanceMediaUsageProgress | Avanzar la indexación de uso de medios |
GET | /_emdash/api/admin/media-usage/work | listMediaUsageWork | Listar trabajo durable de uso de medios |
GET | /_emdash/api/admin/media-usage/activation | getMediaUsageActivation | Obtener estado de activación de uso de medios |
POST | /_emdash/api/admin/media-usage/activation | advanceMediaUsageActivation | Avanzar la activación de uso de medios |
POST | /_emdash/api/admin/media-usage/work/retry | retryMediaUsageWork | Reintentar un trabajo durable de uso de medios |
GET | /_emdash/api/admin/media-usage/collection-deletions | listMediaUsageCollectionDeletions | Listar eliminaciones durable de collections |
POST | /_emdash/api/admin/media-usage/collection-deletions/retry | retryMediaUsageCollectionDeletion | Reintentar una eliminación de collection |
POST | /_emdash/api/media/upload-url | getMediaUploadUrl | Obtener un destino de subida de medios |
POST | /_emdash/api/media/{id}/confirm | confirmMediaUpload | Confirmar una subida de medios |
PUT | /_emdash/api/media/{id}/upload | uploadPendingMedia | Subir un archivo multimedia pendiente a través de EmDash |
Esquema
| Método | Ruta | Operación | Resumen |
|---|---|---|---|
GET | /_emdash/api/schema/block-types | listBlockTypes | Listar tipos de bloque |
POST | /_emdash/api/schema/block-types | createBlockType | Crear un tipo de bloque |
GET | /_emdash/api/schema/block-types/{slug} | getBlockType | Obtener un tipo de bloque |
PUT | /_emdash/api/schema/block-types/{slug} | updateBlockType | Actualizar un tipo de bloque |
POST | /_emdash/api/schema/block-types/{slug}/versions/{version}/activate | activateBlockTypeVersion | Activar una versión de tipo de bloque |
GET | /_emdash/api/schema/collections | listCollections | Listar todas las collections |
POST | /_emdash/api/schema/collections | createCollection | Crear una collection |
GET | /_emdash/api/schema/collections/{slug} | getCollection | Obtener una collection |
PUT | /_emdash/api/schema/collections/{slug} | updateCollection | Actualizar una collection |
DELETE | /_emdash/api/schema/collections/{slug} | deleteCollection | Eliminar una collection |
GET | /_emdash/api/schema/collections/{slug}/fields | listFields | Listar campos de una collection |
POST | /_emdash/api/schema/collections/{slug}/fields | createField | Crear un campo |
GET | /_emdash/api/schema/collections/{slug}/fields/{fieldSlug} | getField | Obtener un campo |
PUT | /_emdash/api/schema/collections/{slug}/fields/{fieldSlug} | updateField | Actualizar un campo |
DELETE | /_emdash/api/schema/collections/{slug}/fields/{fieldSlug} | deleteField | Eliminar un campo |
POST | /_emdash/api/schema/collections/reorder | reorderCollections | Reordenar collections en la barra lateral del admin |
POST | /_emdash/api/schema/collections/{slug}/fields/reorder | reorderFields | Reordenar campos en una collection |
GET | /_emdash/api/schema/orphans | listOrphanedTables | Listar tablas de contenido huérfanas |
POST | /_emdash/api/schema/orphans/{slug} | registerOrphanedTable | Registrar una tabla huérfana como collection |
Comentarios
| Método | Ruta | Operación | Resumen |
|---|---|---|---|
GET | /_emdash/api/comments/{collection}/{contentId} | listPublicComments | Listar comentarios aprobados del contenido |
POST | /_emdash/api/comments/{collection}/{contentId} | createComment | Enviar un comentario nuevo |
GET | /_emdash/api/admin/comments | listAdminComments | Listar comentarios para moderación |
GET | /_emdash/api/admin/comments/counts | getCommentCounts | Obtener recuentos por estado de comentarios |
POST | /_emdash/api/admin/comments/bulk | bulkCommentAction | Aprobar, marcar spam, enviar a papelera o eliminar comentarios en lote |
GET | /_emdash/api/admin/comments/{id} | getComment | Obtener un comentario |
DELETE | /_emdash/api/admin/comments/{id} | deleteComment | Eliminar permanentemente un comentario |
PUT | /_emdash/api/admin/comments/{id}/status | updateCommentStatus | Cambiar el estado de un comentario |
Taxonomías
| Método | Ruta | Operación | Resumen |
|---|---|---|---|
GET | /_emdash/api/taxonomies | listTaxonomies | Listar todas las definiciones de taxonomía |
GET | /_emdash/api/taxonomies/{name} | getTaxonomy | Obtener una definición de taxonomía |
PUT | /_emdash/api/taxonomies/{name} | updateTaxonomy | Actualizar una definición de taxonomía |
DELETE | /_emdash/api/taxonomies/{name} | deleteTaxonomy | Eliminar una taxonomía, sus términos y sus asignaciones al contenido |
GET | /_emdash/api/taxonomies/{name}/translations | listTaxonomyTranslations | Listar cada variante de locale de una definición de taxonomía |
POST | /_emdash/api/taxonomies/{name}/reorder | reorderTerms | Establecer el orden manual de un grupo de términos hermanos |
GET | /_emdash/api/taxonomies/{name}/terms | listTerms | Listar términos de una taxonomía |
POST | /_emdash/api/taxonomies/{name}/terms | createTerm | Crear un término |
GET | /_emdash/api/taxonomies/{name}/terms/{slug} | getTerm | Obtener un término por slug |
PUT | /_emdash/api/taxonomies/{name}/terms/{slug} | updateTerm | Actualizar un término |
DELETE | /_emdash/api/taxonomies/{name}/terms/{slug} | deleteTerm | Eliminar un término |
Menús
| Método | Ruta | Operación | Resumen |
|---|---|---|---|
GET | /_emdash/api/menus | listMenus | Listar todos los menús con recuento de elementos |
POST | /_emdash/api/menus | createMenu | Crear un menú |
GET | /_emdash/api/menus/{name} | getMenu | Obtener un menú con todos sus elementos |
PUT | /_emdash/api/menus/{name} | updateMenu | Actualizar un menú |
DELETE | /_emdash/api/menus/{name} | deleteMenu | Eliminar un menú y sus elementos |
POST | /_emdash/api/menus/{name}/items | createMenuItem | Añadir un elemento a un menú |
PUT | /_emdash/api/menus/{name}/items/{id} | updateMenuItem | Actualizar un elemento de menú |
DELETE | /_emdash/api/menus/{name}/items/{id} | deleteMenuItem | Eliminar un elemento de menú |
POST | /_emdash/api/menus/{name}/reorder | reorderMenuItems | Reordenar elementos de menú en lote |
Secciones
| Método | Ruta | Operación | Resumen |
|---|---|---|---|
GET | /_emdash/api/sections | listSections | Listar secciones |
POST | /_emdash/api/sections | createSection | Crear una sección |
GET | /_emdash/api/sections/{slug} | getSection | Obtener una sección por slug |
PUT | /_emdash/api/sections/{slug} | updateSection | Actualizar una sección |
DELETE | /_emdash/api/sections/{slug} | deleteSection | Eliminar una sección |
Widgets
| Método | Ruta | Operación | Resumen |
|---|---|---|---|
GET | /_emdash/api/widget-areas | listWidgetAreas | Listar todas las áreas de widgets |
POST | /_emdash/api/widget-areas | createWidgetArea | Crear un área de widgets |
GET | /_emdash/api/widget-areas/{name} | getWidgetArea | Obtener un área de widgets con sus widgets |
DELETE | /_emdash/api/widget-areas/{name} | deleteWidgetArea | Eliminar un área de widgets y sus widgets |
POST | /_emdash/api/widget-areas/{name}/widgets | createWidget | Añadir un widget a un área |
PUT | /_emdash/api/widget-areas/{name}/widgets/{id} | updateWidget | Actualizar un widget |
DELETE | /_emdash/api/widget-areas/{name}/widgets/{id} | deleteWidget | Eliminar un widget |
POST | /_emdash/api/widget-areas/{name}/reorder | reorderWidgets | Reordenar widgets en un área |
Configuración
| Método | Ruta | Operación | Resumen |
|---|---|---|---|
GET | /_emdash/api/settings | getSettings | Obtener la configuración del sitio |
PUT | /_emdash/api/settings | updateSettings | Actualizar la configuración del sitio |
Búsqueda
| Método | Ruta | Operación | Resumen |
|---|---|---|---|
GET | /_emdash/api/search | search | Búsqueda de texto completo en collections |
GET | /_emdash/api/search/suggest | searchSuggest | Sugerencias de autocompletado de búsqueda |
POST | /_emdash/api/search/rebuild | rebuildSearchIndex | Reconstruir el índice de búsqueda de una collection |
POST | /_emdash/api/search/enable | enableSearch | Activar o desactivar la búsqueda para una collection |
GET | /_emdash/api/search/stats | getSearchStats | Obtener estadísticas del índice de búsqueda |
Redirecciones
| Método | Ruta | Operación | Resumen |
|---|---|---|---|
GET | /_emdash/api/redirects | listRedirects | Listar redirecciones |
POST | /_emdash/api/redirects | createRedirect | Crear una regla de redirección |
GET | /_emdash/api/redirects/{id} | getRedirect | Obtener una redirección |
PUT | /_emdash/api/redirects/{id} | updateRedirect | Actualizar una redirección |
DELETE | /_emdash/api/redirects/{id} | deleteRedirect | Eliminar una redirección |
GET | /_emdash/api/redirects/404s | listNotFoundEntries | Listar entradas del registro 404 |
POST | /_emdash/api/redirects/404s | pruneNotFoundLog | Podar entradas antiguas del registro 404 |
DELETE | /_emdash/api/redirects/404s | clearNotFoundLog | Borrar todas las entradas del registro 404 |
GET | /_emdash/api/redirects/404s/summary | getNotFoundSummary | Obtener resumen 404 agrupado por ruta |
Usuarios
| Método | Ruta | Operación | Resumen |
|---|---|---|---|
GET | /_emdash/api/admin/users | listUsers | Listar usuarios |
GET | /_emdash/api/admin/users/{id} | getUser | Obtener detalles de un usuario |
PUT | /_emdash/api/admin/users/{id} | updateUser | Actualizar un usuario |
POST | /_emdash/api/admin/users/{id}/disable | disableUser | Desactivar una cuenta de usuario |
POST | /_emdash/api/admin/users/{id}/enable | enableUser | Activar una cuenta de usuario |
GET | /_emdash/api/admin/allowed-domains | listAllowedDomains | Listar dominios de correo permitidos |
POST | /_emdash/api/admin/allowed-domains | createAllowedDomain | Añadir un dominio de correo permitido |
PUT | /_emdash/api/admin/allowed-domains/{domain} | updateAllowedDomain | Actualizar un dominio permitido |
DELETE | /_emdash/api/admin/allowed-domains/{domain} | deleteAllowedDomain | Quitar un dominio permitido |
Transferencia
| Método | Ruta | Operación | Resumen |
|---|---|---|---|
GET | /_emdash/api/admin/transfer/capabilities | getTransferCapabilities | Obtener capacidades de transferencia del sitio |
GET | /_emdash/api/admin/transfer/imports | listTransferImports | Listar importaciones del sitio |
POST | /_emdash/api/admin/transfer/imports | createTransferImport | Crear una importación del sitio |
GET | /_emdash/api/admin/transfer/imports/{id} | getTransferImport | Obtener una importación del sitio |
GET | /_emdash/api/admin/transfer/imports/{id}/missing | listTransferImportMissingFiles | Listar archivos del paquete pendientes de subir |
PUT | /_emdash/api/admin/transfer/imports/{id}/files/{path} | uploadTransferImportFile | Subir un archivo del paquete |
POST | /_emdash/api/admin/transfer/imports/{id}/analyze | analyzeTransferImport | Avanzar el análisis de importación |
GET | /_emdash/api/admin/transfer/imports/{id}/plan | getTransferImportPlan | Obtener un plan de importación |
POST | /_emdash/api/admin/transfer/imports/{id}/cancel | cancelTransferImport | Cancelar una importación del sitio |
POST | /_emdash/api/admin/transfer/imports/{id}/abandon | abandonTransferImport | Abandonar una importación fallida o cancelada |
POST | /_emdash/api/admin/transfer/imports/{id}/execute | executeTransferImport | Iniciar una importación planificada |
POST | /_emdash/api/admin/transfer/imports/{id}/advance | advanceTransferImport | Avanzar una importación en ejecución |
GET | /_emdash/api/admin/transfer/imports/{id}/receipt | getTransferImportReceipt | Obtener un recibo de importación |
GET | /_emdash/api/admin/transfer/exports | listTransferExports | Listar exportaciones del sitio |
POST | /_emdash/api/admin/transfer/exports | createTransferExport | Iniciar una exportación del sitio |
GET | /_emdash/api/admin/transfer/exports/{id} | getTransferExport | Obtener una exportación del sitio |
POST | /_emdash/api/admin/transfer/exports/{id}/advance | advanceTransferExport | Avanzar una exportación del sitio |
GET | /_emdash/api/admin/transfer/exports/{id}/manifest | getTransferExportManifest | Descargar un manifiesto de exportación |
GET | /_emdash/api/admin/transfer/exports/{id}/files/{path} | downloadTransferExportFile | Descargar un archivo de exportación |
GET | /_emdash/api/admin/transfer/exports/{id}/archive | downloadTransferExportArchive | Descargar un archivo de exportación comprimido |
GET | /_emdash/api/admin/transfer/approvals | listTransferApprovals | Listar aprobaciones de transferencia |
POST | /_emdash/api/admin/transfer/approvals/{id}/approve | approveTransferApproval | Aprobar una solicitud de transferencia |
POST | /_emdash/api/admin/transfer/approvals/{id}/deny | denyTransferApproval | Rechazar una solicitud de transferencia |
Ciclo de vida del contenido y bylines
La referencia del ciclo de vida del contenido define el estado, la revisión, los permisos, los conflictos y el comportamiento de hooks compartidos por REST, MCP, la CLI y el panel de administración.
Las lecturas de contenido devuelven un token opaco _rev cuando está disponible. Envíe _rev con PUT /content/{collection}/{id} para evitar sobrescribir un cambio hecho desde la lectura. Un token obsoleto produce un conflicto; vuelva a leer el elemento antes de reintentar. La CLI hace obligatoria esta comprobación para content update, mientras que el campo REST sigue siendo opcional para clientes que eligen deliberadamente una escritura incondicional.
Leer y actualizar una entrada
Lea la entrada antes de modificarla:
GET /_emdash/api/content/articles/01JARTICLE0000000000000000
Authorization: Bearer $EMDASH_TOKEN
La respuesta contiene sus campos, el estado de publicación y el token de revisión:
{
"success": true,
"data": {
"item": {
"id": "01JARTICLE0000000000000000",
"type": "articles",
"slug": "launch-notes",
"status": "published",
"data": { "title": "Launch notes" }
},
"_rev": "opaque-revision-token"
}
}
Envíe solo los campos que deben cambiar, junto con el token de esa lectura:
PUT /_emdash/api/content/articles/01JARTICLE0000000000000000
Authorization: Bearer $EMDASH_TOKEN
Content-Type: application/json
{
"data": { "title": "Updated launch notes" },
"_rev": "opaque-revision-token"
}
Al cambiar una entrada publicada se crea un borrador mientras la versión anterior sigue en vivo. Use la operación de comparación para revisar ambas versiones y luego publique el borrador o descártelo. Despublicar conserva el contenido y su fecha de publicación, cancela cualquier programación pendiente y quita la entrada del sitio en vivo.
Los cuerpos de creación y actualización aceptan créditos de byline, y las respuestas de contenido incluyen la byline principal y los créditos ordenados. La lista de contenido puede filtrar por IDs de byline almacenados e incluir opcionalmente la byline inferida de un autor. Crear y gestionar los registros de byline en sí está disponible mediante las herramientas MCP de bylines, no el contrato REST público.
Las operaciones del ciclo de vida distinguen la eliminación lógica de la eliminación permanente. Restaurar devuelve el contenido de la papelera como borrador sin programación; la eliminación permanente quita un elemento de la papelera y no se puede deshacer. Publicar, despublicar, programar, cancelar programación, comparar, descartar borrador y duplicar son operaciones separadas para que los clientes soliciten una transición de estado a la vez.
Bloqueo de edición de entradas
Las collections pueden tomar un bloqueo de edición de siete minutos cuando un editor abre una entrada. Use las tres operaciones en /content/{collection}/{id}/lock para leer, adquirir o renovar y liberar la concesión.
Una respuesta de lectura o adquisición indica si el bloqueo está activado, si el llamador tiene la concesión y quién la tiene actualmente:
{
"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"
}
}
}
Cuando una collection tiene desactivado el bloqueo de edición, enabled es false y no se toma ninguna concesión. Volver a adquirir el mismo bloqueo y guardar la entrada prolongan una concesión del llamador.
El cuerpo de adquisición puede incluir un token opaco que identifica una sesión de edición y takeover: true cuando el usuario elige reemplazar la concesión de otro editor. Pase el mismo token como parámetro de consulta al liberar el bloqueo. Una segunda pestaña de la misma cuenta no podrá liberar por error la concesión de la primera.
Cuando otro usuario tiene la concesión, las escrituras protegidas de contenido devuelven 409 ENTRY_LOCKED. Los detalles del error identifican al titular y la caducidad. Para anular el bloqueo, envíe "overrideLock": true en el cuerpo JSON de una escritura con cuerpo, o ?overrideLock=true para una operación DELETE sin cuerpo.
Selecciones de referencia
Un campo reference enlaza una entrada con entradas de otra collection mediante una relación. Su valor no forma parte de data y está indexado por grupo de traducción, de modo que cada traducción de una entrada comparte una selección.
Los cuerpos de creación y actualización llevan selecciones bajo references, indexadas por slug de campo, cada una un array de como máximo 1000 IDs de entrada en orden de visualización. EmDash escribe la selección en la misma transacción que la entrada. La siguiente actualización reemplaza el autor de la entrada:
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"
}
Un campo ligado al extremo hijo de su relación selecciona las entradas que apuntan a la que se escribe, sin orden propio. Los límites de relación se aplican en ambos extremos; se rechaza una selección que daría a una entrada enlazada más padres de los que permite la relación, igual que una que enlaza demasiadas entradas.
En una collection que conserva revisiones, una selección cambiada en una entrada publicada se prepara en el borrador con el resto de cambios pendientes. Pasa a estar en vivo al publicar la entrada y se descarta con el borrador. Al publicar se vuelve a comprobar toda la selección frente a los límites de la relación.
Una lectura de un solo elemento devuelve references indexadas por slug de campo. Cada campo contiene la primera página de entradas enlazadas, 50, con nextCursor cuando hay más, e informa del ID, slug, collection, título mostrado, locale resuelto y grupo de traducción de cada entrada. Un llamador autorizado a leer borradores ve una selección preparada cuando el borrador la lleva. La operación de listado de contenido no incluye referencias.
Las definiciones de relación y el recorrido de enlaces son rutas de administración, ausentes de OpenAPI y fuera del contrato público. Escriba y lea selecciones mediante las operaciones de contenido anteriores y muéstrelas en un sitio con getEmDashEntry() y getEmDashReferences().
Traducciones
El contrato REST público expone traducciones de contenido y traducciones de definiciones de taxonomía. La creación de contenido acepta translationOf, y la creación de taxonomías usa el mismo campo para añadir una variante de locale. Las operaciones de términos de contenido devuelven asignaciones conscientes del locale.
GET /taxonomies/{name} devuelve la definición del locale predeterminado del sitio cuando se omite locale, recurriendo al código de locale más bajo solo cuando el locale predeterminado no tiene definición. Una actualización se comporta distinto: cuando se omite locale, cambia la definición con el código de locale más bajo. Pase locale para que una actualización de taxonomía traducida alcance la definición prevista. Si ese locale no tiene definición, la actualización devuelve NOT_FOUND en lugar de recurrir a otro locale. La operación de traducciones devuelve cada definición del grupo compartido y los IDs aceptados por translationOf.
label y labelSingular pertenecen a la definición de un locale. hierarchical y collections pertenecen a la taxonomía: cada locale devuelve los mismos valores, y una actualización que envía cualquiera de ellos lo cambia para todos los locales. Crear una definición para un nombre que ya existe en otro locale la añade a esa taxonomía, haya o no translationOf en la solicitud. La nueva definición toma hierarchical y collections de la taxonomía, y una creación con valores distintos devuelve VALIDATION_ERROR.
Eliminar una taxonomía quita cada locale de su definición, todos sus términos y todas las asignaciones de esos términos al contenido. No elimina las entradas de contenido en sí.
La operación de reordenación de términos cambia un grupo de hermanos. El array ids puede contener solo parte de ese grupo; los términos listados intercambian sus posiciones existentes y los omitidos permanecen donde están. Por ejemplo, reordenar [A, B, C] con ids: ["C", "A"] produce [C, B, A]. Reordenar no cambia relaciones padre, y un orden de términos aplica en cada locale de su grupo de traducción.
Las rutas de traducción de menús, términos de taxonomía y bylines no están en el contrato REST público. Sus listados de traducción admitidos están disponibles mediante menu_translations, taxonomy_term_translations y byline_translations en el servidor MCP.
Endpoints de medios
Las operaciones de medios cubren listado, subida, actualización de metadatos, reemplazo de imágenes, carpetas, información de uso y mantenimiento del índice de uso. La guía de biblioteca de medios explica el flujo orientado al usuario y el significado de la cobertura de uso.
Listar e inspeccionar medios
GET /media admite paginación por cursor o por páginas numeradas, filtros por tipo MIME y nombre de archivo, carpetas y resúmenes de uso opcionales. Omita folderId para incluir todas las carpetas, o pase folderId=unfiled para devolver solo la biblioteca principal. Establezca includeUsage=1 en un listado o lectura de un elemento para incluir información de uso; cualquier otro valor no es válido.
usage.count cuenta filas de contenido activas distintas o locales cuya fuente indexada actual referencia el elemento multimedia, más cada configuración del sitio que lo selecciona (logo, favicon, seo.defaultOgImage). Las referencias repetidas en una entrada cuentan una vez, y las entradas en la papelera no cuentan. El número solo es visible para llamadores que pueden leer borradores; otros lectores autorizados de medios reciben count: null porque el recuento podría revelar contenido en borrador.
GET /media/{id}/usage devuelve las entradas de contenido que referencian el medio, paginadas. Cada página incluye también siteSettings, la configuración del sitio que selecciona el elemento multimedia, por ejemplo [{ "setting": "favicon" }]. La configuración del sitio se lee de los valores almacenados en cada solicitud y no depende de la indexación de uso.
Cada resultado de uso incluye un estado de cobertura:
| Estado | Significado |
|---|---|
complete | Cada collection registrada tiene cobertura de uso actual. |
never | Ninguna collection registrada ha completado una reparación inicial de uso. |
running | Hay una reparación en curso. |
partial | Solo parte del conjunto de collections registradas tiene cobertura actual. |
failed | La cobertura falló en el conjunto de collections registradas. |
stale | El índice es más antiguo que el contenido que describe. |
unknown | El estado almacenado no es reconocido por esta versión de EmDash. |
Solo complete permite tratar un recuento cero como completo dentro de los tipos de campo indexados. Los recuentos son orientativos durante escrituras concurrentes; no bloquean el elemento multimedia ni garantizan que la eliminación sea segura. La indexación de uso cubre campos de imagen y archivo, campos repetidor de imagen, bloques de imagen y galería de Portable Text, y medios declarados por versiones de bloque retenidas en collections de EmDash. También se informan el logo del sitio, el favicon y la imagen social predeterminada. El uso no incluye bloques Portable Text personalizados, código de aplicación, HTML renderizado, otras configuraciones, menús, widgets, datos de plugins, sitios externos ni activos solo del proveedor.
Subida multipart directa
Envíe un archivo a través de EmDash publicándolo como campo file de una solicitud multipart:
curl --request POST \
--header "Authorization: Bearer $EMDASH_TOKEN" \
--form "file=@./cover.jpg;type=image/jpeg" \
https://example.com/_emdash/api/media
curl añade el límite multipart. No establezca manualmente el encabezado Content-Type. El esquema OpenAPI MediaDirectUploadBody enumera los campos de metadatos opcionales y los esquemas de respuesta distinguen una subida nueva de un elemento existente deduplicado.
El cuerpo multipart también puede incluir width y height de imagen, un fieldId cuya lista de tipos MIME permitidos debe aplicarse y una thumbnail reducida para crear un marcador de posición de baja calidad. Un archivo nuevo devuelve 201 Created y está listo de inmediato. Bytes idénticos devuelven el elemento multimedia existente con 200 OK y deduplicated: true.
Flujo de destino de subida
Use el flujo de destino de subida cuando el cliente pueda subir directamente a almacenamiento compatible con S3. El elemento multimedia permanece pendiente y no aparece en la biblioteca estándar hasta que la confirmación tenga éxito.
-
Solicitar un destino de subida
POST /_emdash/api/media/upload-url Authorization: Bearer $EMDASH_TOKEN Content-Type: application/json { "filename": "cover.jpg", "contentType": "image/jpeg", "size": 102400 }La respuesta proporciona
uploadUrl,method,headers,mediaId,storageKeyy una caducidad. CuandocontentHashcoincide con un archivo existente del mismo tipo MIME y tamaño, la respuesta estableceexisting: true; use ese elemento multimedia y no suba ni confirme otra copia. -
Subir los bytes
Use el método y los encabezados devueltos. Resuelva una URL relativa a la raíz frente al sitio EmDash e incluya el token Bearer. Envíe solo los encabezados de subida devueltos a una URL absoluta en otro origen.
-
Confirmar la subida
POST /_emdash/api/media/01JMEDIA000000000000000000/confirm Authorization: Bearer $EMDASH_TOKEN Content-Type: application/json { "size": 102400, "width": 1920, "height": 1080 }La confirmación verifica el objeto almacenado y cambia el elemento de
pendingaready. El tamaño y las dimensiones indicados deben coincidir con el archivo subido.
El almacenamiento local y R2 nativo devuelven un destino de subida EmDash del mismo origen. El almacenamiento compatible con S3 puede devolver una URL externa firmada. Los elementos pendientes quedan fuera del listado estándar de medios hasta que la confirmación tenga éxito.
Errores de subida
Los siguientes errores requieren una acción de recuperación distinta:
| Estado | Código | Acción |
|---|---|---|
400 | NO_FILE | Añada el campo file a una solicitud multipart o envíe el cuerpo de subida faltante. |
400 | INVALID_TYPE | Use un tipo MIME permitido que coincida con el elemento multimedia pendiente. |
400 | VALIDATION_ERROR | Corrija metadatos faltantes o no válidos, incluidos valores por encima del límite de tamaño configurado. |
400 | FILE_NOT_FOUND | Suba el objeto al destino devuelto antes de confirmarlo. |
400 | UPLOAD_SIZE_MISMATCH | Reinicie el flujo con el tamaño correcto; los tamaños declarado, subido y confirmado deben coincidir. |
400 or 409 | INVALID_STATE | Lea el elemento multimedia antes de reintentar. Puede que ya no esté pendiente, u otra solicitud pudo haberlo cambiado durante la confirmación. |
404 | NOT_FOUND | Use un ID de medio pendiente existente. |
413 | PAYLOAD_TOO_LARGE | Reduzca el tamaño del archivo o aumente maxUploadSize antes de iniciar otra subida. |
Carpetas de medios
Los nombres de carpeta se recortan, limitan a 200 caracteres y se comparan tras normalización Unicode y minúsculas. Nombres como Photos, photos y PHOTOS entran en conflicto. Eliminar una carpeta devuelve sus medios a la biblioteca principal; no elimina medios, no cambia IDs ni URLs de medios ni registros de uso.
Reparar uso de medios
La activación, el progreso, las colas de trabajo, la limpieza de eliminaciones y la reparación del uso de medios son operaciones de operador bajo /_emdash/api/admin/media-usage/. Los usuarios con sesión necesitan schema:manage; los tokens Bearer también necesitan el ámbito admin.
Si el seguimiento está desactivado, pause los escritores directos de base de datos antes de la activación. EmDash bloquea temporalmente escrituras de contenido y esquema enviadas por sus API durante la configuración, pero no puede detener otro proceso que escriba directamente en la base de datos.
- Detenga los escritores directos de base de datos y espere a que terminen las escrituras en curso.
- Lea el estado de activación.
expandedsignifica seguimiento desactivado,activatingsignifica que EmDash prepara collections, yactivesignifica que se rastrean los cambios de referencia de medios nuevos. - Envíe una solicitud de activación con
{ "writersDrained": true }. - Envíe solicitudes de progreso de una en una, esperando cada
nextRequestInMsdevuelto, hasta que la activación seaactive. - Reanude las escrituras directas en la base de datos.
- Continúe las solicitudes de progreso hasta que la indexación histórica sea
readyynextRequestInMsseanull.
Si una solicitud de escritura agota el tiempo o devuelve 409 o 500, lea el estado de activación y progreso antes de reintentar. Los lotes completados siguen registrados. Cuando lastErrorCode está establecido, mantenga detenidos los escritores directos, resuelva el problema indicado y envíe un reintento confirmado. La activación no se puede cancelar ni restablecer después de iniciarse; pruebe este procedimiento en una copia de staging y mantenga una copia de seguridad actual de la base de datos.
Las operaciones de listado de trabajo exponen indexación de entradas fallida o retrasada sin devolver contenido, referencias de medios, tokens de concesión, errores crudos de base de datos ni un recuento exacto de backlog. Reintentar un elemento es idempotente. 409 WORK_LEASE_ACTIVE significa que un worker sigue procesando el elemento; la respuesta incluye details.leaseExpiresAt, así que espere hasta ese momento y vuelva a leer el elemento antes de reintentar. 409 WORK_CHANGED significa que otra solicitud cambió el elemento de trabajo; lea su estado actual en lugar de sobrescribir el trabajo más reciente.
La operación de reparación acepta { "scope": "collection", "collection": "articles" } o { "scope": "all" }. Una reparación de todas las collections se ejecuta de forma síncrona y secuencial, por lo que puede tardar mucho en un sitio grande. Una respuesta 200 aún puede informar partial, failed o stale; inspeccione data.status, el estado por collection y los recuentos de origen antes de considerar completa la reparación.
Transferencia del sitio
Las operaciones de transferencia bajo /_emdash/api/admin/transfer/ exportan un sitio como paquete del sitio e importan uno en un sitio vacío. La guía de transferencia del sitio describe el flujo de exportación, subida, análisis, ejecución y recibo.
Los usuarios con sesión necesitan el permiso transfer:export o transfer:import, que solo tienen los administradores. Los tokens Bearer necesitan admin o el ámbito transfer:export, transfer:analyze o transfer:execute que indique cada operación. Las operaciones de aprobación aceptan solo sesiones iniciadas. Deciden solicitudes hechas por las herramientas MCP site_export_start y site_import_start; las operaciones REST de exportación y ejecución no requieren aprobación.
Mientras una importación se ejecuta, y tras fallar o cancelarse hasta que se abandone, la mayoría de las demás operaciones de escritura devuelven 503 TRANSFER_IMPORT_IN_PROGRESS. La guía enumera las operaciones que siguen disponibles.
Paginación
Las operaciones de listado describen sus parámetros de paginación en OpenAPI. La mayoría de operaciones paginadas por cursor aceptan un cursor opaco y un limit de 1 a 100, con valor predeterminado 50. Devuelva el nextCursor de la respuesta anterior sin modificar; no lo inspeccione ni lo construya. Algunas operaciones de medios también admiten páginas numeradas, y algunos listados especializados usan límites distintos, así que los clientes generados deben seguir el esquema de cada operación.
Tokenizadores de búsqueda
La operación de activación de búsqueda almacena un tokenizador por collection. Cambiarlo en una collection con búsqueda activada reconstruye el índice de esa collection.
| Valor | Uso |
|---|---|
porter unicode61 | Predeterminado para contenido en inglés que se beneficia del stemming Porter. |
unicode61 | Idiomas que usan separadores de palabras pero no deben usar stemming inglés. |
trigram | Texto sin espacios, incluidos japonés, chino, tailandés, jemer, lao y birmano, o collections que necesitan coincidencia por subcadena. Las consultas de menos de tres caracteres Unicode no devuelven coincidencias. |
Desactivar la búsqueda conserva el tokenizador almacenado para la próxima activación. La operación de reconstrucción usa el tokenizador almacenado y los pesos de campo de la collection.
Comentarios y redirecciones
Los envíos públicos de comentarios entran en la cola de moderación. Las operaciones de comentarios de administración listan todos los estados, devuelven recuentos, actualizan un estado, realizan moderación en lote y eliminan permanentemente un comentario. Una respuesta 429 significa que se alcanzó el límite de velocidad de envío.
Las operaciones de redirección gestionan reglas de redirección y el registro 404 por separado. Podar elimina entradas seleccionadas por el cuerpo de la solicitud, mientras que DELETE /redirects/404s borra todo el registro. Ninguna de las operaciones elimina reglas de redirección.