O EmDash expõe uma API REST em /_emdash/api/ para gerenciamento de conteúdo, upload de mídia e operações de esquema.
Autenticação
As requisições da API requerem autenticação via token Bearer no cabeçalho Authorization:
Authorization: Bearer <token>
Gere tokens pela interface de administração ou programaticamente.
Formato de resposta
Todas as respostas seguem um formato consistente. Uma resposta bem-sucedida envolve o resultado em data:
{
"success": true,
"data": { ... }
}
Uma resposta de erro inclui um código, mensagem e detalhes opcionais:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable message",
"details": { ... }
}
}
Endpoints de conteúdo
Listar conteúdo
GET /_emdash/api/content/:collection
Parâmetros
| Parâmetro | Tipo | Descrição |
|---|---|---|
collection | string | Slug da coleção (caminho) |
cursor | string | Cursor de paginação (query) |
limit | number | Itens por página (query, padrão: 50) |
status | string | Filtrar por status (query) |
orderBy | string | Campo de ordenação (query) |
order | string | Direção da ordenação: asc ou desc (query) |
Resposta
{
"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..."
}
}
Obter conteúdo
GET /_emdash/api/content/:collection/:id
Resposta
{
"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"
}
}
}
Criar conteúdo
POST /_emdash/api/content/:collection
Content-Type: application/json
Corpo da requisição
{
"data": {
"title": "New Post",
"content": [...]
},
"slug": "new-post",
"status": "draft"
}
Resposta
{
"success": true,
"data": {
"item": { ... }
}
}
Atualizar conteúdo
PUT /_emdash/api/content/:collection/:id
Content-Type: application/json
Corpo da requisição
{
"data": {
"title": "Updated Title"
},
"status": "published"
}
Excluir conteúdo
DELETE /_emdash/api/content/:collection/:id
Resposta
{
"success": true,
"data": {
"success": true
}
}
Endpoints de mídia
Listar mídia
GET /_emdash/api/media?includeUsage=1
Parâmetros
| Parâmetro | Tipo | Descrição |
|---|---|---|
cursor | string | Cursor de paginação opaco |
limit | number | Itens por página, de 1 a 100 (padrão: 50) |
mimeType | string | Filtrar por um ou mais tipos MIME separados por vírgula |
q | string | Pesquisa de nome de arquivo insensível a maiúsculas |
includeUsage | 1 | Incluir resumo de usage com cobertura em cada item retornado |
Resposta
{
"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..."
}
}
Obter mídia
GET /_emdash/api/media/:id?includeUsage=1
includeUsage é opcional tanto na listagem quanto na obtenção. Seu único valor aceito é 1. Quando omitido,
a propriedade usage é omitida e o servidor não executa consultas de uso.
Resumos de uso
usage.count é o número de linhas de conteúdo ou locais ativos distintos do EmDash cuja fonte
indexada atual selecionada referencia o item de mídia. Referências repetidas e múltiplas variantes
de fonte para a mesma entrada de conteúdo contam uma vez. Conteúdo na lixeira não conta.
Uma contagem numérica pode revelar conteúdo semelhante a rascunhos. É retornada apenas quando um usuário de sessão tem
content:read_drafts, ou quando um token de API tem o escopo admin e seu usuário associado também tem
essa permissão. Outros leitores de mídia recebem usage.count: null; esta é uma resposta editada bem-sucedida,
não um erro.
Cada resumo solicitado inclui cobertura agregada para todas as coleções de conteúdo atualmente registradas:
| Status | Significado |
|---|---|
complete | Cada coleção registrada tem cobertura de uso atual e completada |
never | Nenhuma coleção registrada completou uma reparação de uso inicial |
running | Uma reparação de uso está atualmente em execução |
partial | A cobertura é mista ou apenas parte do escopo registrado foi indexado |
failed | A cobertura falhou em todo o escopo registrado |
stale | A cobertura indexada está desatualizada |
unknown | A cobertura armazenada contém um estado que esta versão não reconhece |
Apenas complete suporta uma declaração de zero completo com escopo dentro dos campos gerenciados pelo EmDash
descritos abaixo. Contagens com qualquer outro status são projeções indexadas e podem sobre-reportar ou
sub-reportar. Mesmo resultados completos são consultivos durante gravações concorrentes; leituras de uso não são um
bloqueio transacional e não devem ser usadas como garantia de exclusão.
Obter detalhes de uso de mídia
GET /_emdash/api/media/:id/usage?limit=50&cursor=...
Este endpoint requer media:read e content:read_drafts. Chamadores autenticados por token também
requerem o escopo admin; o escopo do token não ignora as permissões do usuário associado.
limit controla os grupos de entradas de conteúdo por página, de 1 a 100 (padrão: 50). A paginação nunca
divide as fontes ou ocorrências para um grupo de entrada retornado.
{
"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"
}
}
}
Os detalhes autorizados incluem entradas ativas e excluídas. Um deletedAt não nulo identifica uma
entrada na lixeira. As fontes são columns ou draft_overlay; as ocorrências identificam o campo suportado
e o caminho sem expor metadados internos do índice.
O uso de mídia cobre referências de mídia local em campos de imagem e arquivo de nível superior, campos de imagem de repetidor e blocos de imagem Portable Text gerenciados pelas coleções de conteúdo do EmDash. Não escaneia código personalizado, HTML renderizado, configurações, menus, widgets, dados privados de plugins, sites externos ou ativos exclusivos do provedor.
Criar mídia
POST /_emdash/api/media
Content-Type: application/json
Corpo da requisição
{
"filename": "photo.jpg",
"mimeType": "image/jpeg",
"size": 102400,
"width": 1920,
"height": 1080,
"storageKey": "uploads/photo.jpg"
}
Atualizar mídia
PUT /_emdash/api/media/:id
Content-Type: application/json
Corpo da requisição
{
"alt": "Photo description",
"caption": "Photo caption"
}
Excluir mídia
DELETE /_emdash/api/media/:id
Reparar uso de mídia
POST /_emdash/api/admin/media-usage/repair
Content-Type: application/json
X-EmDash-Request: 1
Repara o índice de uso de mídia de conteúdo para uma coleção ou para todas as coleções de conteúdo. Este é um endpoint de administrador/operador: chamadores autenticados por sessão precisam de schema:manage, e tokens Bearer devem ter o escopo admin porque a rota está sob /_emdash/api/admin.
A reparação de todo o conteúdo é executada de forma síncrona e sequencial na versão atual. Pode ser custosa em sites grandes, então os chamadores devem ativá-la deliberadamente e aguardar a resposta.
Corpo da requisição
Reparar uma coleção:
{
"scope": "collection",
"collection": "posts"
}
Reparar todas as coleções de conteúdo:
{
"scope": "all"
}
O corpo da requisição é obrigatório. Slugs inválidos, chaves de requisição desconhecidas, scope ausente e requisições sem corpo retornam 400 em vez de reparar todo o conteúdo por padrão.
Resposta
O endpoint retorna 200 quando uma invocação de reparação produz um resultado estruturado. Inspecione data.status: failed e stale são status do domínio de reparação, não erros de transporte.
{
"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"
}
]
}
}
Campos de resposta de nível superior:
| Campo | Tipo | Descrição |
|---|---|---|
status | complete | partial | failed | stale | Status de reparação agregado |
indexedSourceCount | number | Fontes indexadas durante a reparação |
failedSourceCount | number | Fontes que falharam durante a reparação |
skippedSourceCount | number | Fontes ignoradas, incluindo conflitos obsoletos |
deletedSourceCount | number | Linhas de uso obsoletas excluídas durante a reparação |
collections | array | Resumos de reparação por coleção |
Campos de resumo por coleção:
| Campo | Tipo | Descrição |
|---|---|---|
collection | string | Slug da coleção |
status | complete | partial | failed | stale | Status de reparação da coleção |
indexedSourceCount | number | Fontes indexadas para esta coleção |
failedSourceCount | number | Fontes que falharam para esta coleção |
skippedSourceCount | number | Fontes ignoradas para esta coleção |
deletedSourceCount | number | Linhas de uso obsoletas excluídas para esta coleção |
lastErrorCode | string | null | Último erro de reparação da coleção, quando disponível |
startedAt | string | Hora de início da reparação |
completedAt | string | null | Hora de conclusão, ou null para resultados obsoletos |
Coleções desconhecidas retornam 200 com data.status: "failed" e um lastErrorCode por coleção como COLLECTION_NOT_FOUND. Erros de transporte continuam usando o envelope de erro padrão, incluindo 400, 401, 403, 413 e 500.
Obter arquivo de mídia
GET /_emdash/api/media/file/:key
Serve o conteúdo real do arquivo. Apenas para armazenamento local.
Endpoints de revisões
Listar revisões
GET /_emdash/api/content/:collection/:entryId/revisions
Parâmetros
| Parâmetro | Tipo | Descrição |
|---|---|---|
limit | number | Máx. revisões a retornar (padrão: 50) |
Resposta
{
"success": true,
"data": {
"items": [
{
"id": "01HXK5MZSN...",
"collection": "posts",
"entryId": "01HXK5MZSN...",
"data": { ... },
"createdAt": "2025-01-24T12:00:00Z"
}
],
"total": 5
}
}
Obter revisão
GET /_emdash/api/revisions/:revisionId
Restaurar revisão
POST /_emdash/api/revisions/:revisionId/restore
Restaura o conteúdo ao estado desta revisão e cria uma nova revisão.
Endpoints de esquema
Listar coleções
GET /_emdash/api/schema/collections
Resposta
{
"success": true,
"data": {
"items": [
{
"id": "01HXK5MZSN...",
"slug": "posts",
"label": "Posts",
"labelSingular": "Post",
"supports": ["drafts", "revisions", "preview"]
}
]
}
}
Obter coleção
GET /_emdash/api/schema/collections/:slug
Parâmetros
| Parâmetro | Tipo | Descrição |
|---|---|---|
includeFields | boolean | Incluir definições de campos (query) |
Criar coleção
POST /_emdash/api/schema/collections
Content-Type: application/json
Corpo da requisição
{
"slug": "products",
"label": "Products",
"labelSingular": "Product",
"description": "Product catalog",
"supports": ["drafts", "revisions"]
}
Atualizar coleção
PUT /_emdash/api/schema/collections/:slug
Content-Type: application/json
Excluir coleção
DELETE /_emdash/api/schema/collections/:slug
Parâmetros
| Parâmetro | Tipo | Descrição |
|---|---|---|
force | boolean | Excluir mesmo se a coleção tem conteúdo (query) |
Listar campos
GET /_emdash/api/schema/collections/:slug/fields
Criar campo
POST /_emdash/api/schema/collections/:slug/fields
Content-Type: application/json
Corpo da requisição
{
"slug": "price",
"label": "Price",
"type": "number",
"required": true,
"validation": {
"min": 0
}
}
Atualizar campo
PUT /_emdash/api/schema/collections/:collectionSlug/fields/:fieldSlug
Content-Type: application/json
Excluir campo
DELETE /_emdash/api/schema/collections/:collectionSlug/fields/:fieldSlug
Reordenar campos
POST /_emdash/api/schema/collections/:slug/fields/reorder
Content-Type: application/json
Corpo da requisição
{
"fieldSlugs": ["title", "content", "author", "publishedAt"]
}
Exportação de esquema
Exportar esquema (JSON)
GET /_emdash/api/schema
Accept: application/json
Exportar esquema (TypeScript)
GET /_emdash/api/schema?format=typescript
Accept: text/typescript
Retorna interfaces TypeScript para todas as coleções.
Endpoints de plugins
Listar plugins
GET /_emdash/api/admin/plugins
Obter plugin
GET /_emdash/api/admin/plugins/:id
Ativar plugin
POST /_emdash/api/admin/plugins/:id/enable
Desativar plugin
POST /_emdash/api/admin/plugins/:id/disable
Códigos de erro
| Código | Status HTTP | Descrição |
|---|---|---|
NOT_FOUND | 404 | Recurso não encontrado |
VALIDATION_ERROR | 400 | Dados de entrada inválidos |
UNAUTHORIZED | 401 | Token ausente ou inválido |
FORBIDDEN | 403 | Permissões insuficientes |
CONTENT_LIST_ERROR | 500 | Falha ao listar conteúdo |
CONTENT_CREATE_ERROR | 500 | Falha ao criar conteúdo |
CONTENT_UPDATE_ERROR | 500 | Falha ao atualizar conteúdo |
CONTENT_DELETE_ERROR | 500 | Falha ao excluir conteúdo |
MEDIA_LIST_ERROR | 500 | Falha ao listar mídia |
MEDIA_CREATE_ERROR | 500 | Falha ao criar mídia |
SCHEMA_CREATE_ERROR | 500 | Operação de esquema falhou |
SLUG_CONFLICT | 409 | Slug já existe |
RESERVED_SLUG | 400 | Slug é reservado |
Endpoints de pesquisa
Pesquisa global
GET /_emdash/api/search?q=hello+world
Parâmetros
| Parâmetro | Tipo | Descrição |
|---|---|---|
q | string | Consulta de pesquisa (obrigatório) |
collections | string | Slugs de coleções separados por vírgula |
status | string | Filtrar por status (padrão: published) |
limit | number | Máx. resultados (padrão: 20) |
cursor | string | Cursor de paginação |
Resposta
{
"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"
}
}
Sugestões de pesquisa
GET /_emdash/api/search/suggest?q=hel&limit=5
Retorna títulos com correspondência de prefixo para autocompletar.
Reconstruir índice de pesquisa
POST /_emdash/api/search/rebuild
Reconstruir o índice FTS para todas ou coleções específicas.
Estatísticas de pesquisa
GET /_emdash/api/search/stats
Retorna contagens de documentos indexados por coleção.
Endpoints de seções
Listar seções
GET /_emdash/api/sections
GET /_emdash/api/sections?source=theme
GET /_emdash/api/sections?search=newsletter
Obter seção
GET /_emdash/api/sections/:slug
Criar seção
POST /_emdash/api/sections
Content-Type: application/json
{
"slug": "my-section",
"title": "My Section",
"keywords": ["keyword1"],
"content": [...]
}
Atualizar seção
PUT /_emdash/api/sections/:slug
Excluir seção
DELETE /_emdash/api/sections/:slug
Endpoints de configurações
Obter todas as configurações
GET /_emdash/api/settings
Atualizar configurações
POST /_emdash/api/settings
Content-Type: application/json
{
"siteTitle": "My Site",
"tagline": "A great site",
"postsPerPage": 10
}
Endpoints de menus
Listar menus
GET /_emdash/api/menus
Obter menu
GET /_emdash/api/menus/:name
Criar menu
POST /_emdash/api/menus
Content-Type: application/json
{
"name": "main",
"label": "Main Navigation",
"items": []
}
Atualizar menu
PUT /_emdash/api/menus/:name
Excluir menu
DELETE /_emdash/api/menus/:name
Adicionar item de menu
POST /_emdash/api/menus/:name/items
Content-Type: application/json
{
"label": "About",
"url": "/about",
"position": 0
}
Reordenar itens de menu
POST /_emdash/api/menus/:name/reorder
Content-Type: application/json
{
"itemIds": ["item_1", "item_2", "item_3"]
}
Endpoints de taxonomias
Listar definições de taxonomias
GET /_emdash/api/taxonomies
Criar taxonomia
POST /_emdash/api/taxonomies
Content-Type: application/json
{
"name": "categories",
"label": "Categories",
"hierarchical": true,
"collections": ["posts"]
}
Listar termos
GET /_emdash/api/taxonomies/:name/terms
Criar termo
POST /_emdash/api/taxonomies/:name/terms
Content-Type: application/json
{
"slug": "tutorials",
"label": "Tutorials",
"parentId": "term_abc",
"description": "How-to guides"
}
Atualizar termo
PUT /_emdash/api/taxonomies/:name/terms/:slug
Excluir termo
DELETE /_emdash/api/taxonomies/:name/terms/:slug
Definir termos da entrada
POST /_emdash/api/content/:collection/:id/terms/:taxonomy
Content-Type: application/json
{
"termIds": ["term_news", "term_featured"]
}
Endpoints de áreas de widgets
Listar áreas de widgets
GET /_emdash/api/widget-areas
Obter área de widgets
GET /_emdash/api/widget-areas/:name
Criar área de widgets
POST /_emdash/api/widget-areas
Content-Type: application/json
{
"name": "sidebar",
"label": "Main Sidebar",
"description": "Appears on posts"
}
Excluir área de widgets
DELETE /_emdash/api/widget-areas/:name
Adicionar widget
POST /_emdash/api/widget-areas/:name/widgets
Content-Type: application/json
{
"type": "content",
"title": "About",
"content": [...]
}
Atualizar widget
PUT /_emdash/api/widget-areas/:name/widgets/:id
Excluir widget
DELETE /_emdash/api/widget-areas/:name/widgets/:id
Reordenar widgets
POST /_emdash/api/widget-areas/:name/reorder
Content-Type: application/json
{
"widgetIds": ["widget_1", "widget_2", "widget_3"]
}
Endpoints de gerenciamento de usuários
Listar usuários
GET /_emdash/api/admin/users
GET /_emdash/api/admin/users?role=40
GET /_emdash/api/admin/users?search=john
Obter usuário
GET /_emdash/api/admin/users/:id
Atualizar usuário
PUT /_emdash/api/admin/users/:id
Content-Type: application/json
{
"name": "John Doe",
"role": 40
}
Ativar usuário
POST /_emdash/api/admin/users/:id/enable
Desativar usuário
POST /_emdash/api/admin/users/:id/disable
Endpoints de autenticação
Status de configuração
GET /_emdash/api/setup/status
Retorna se a configuração está completa e se existem usuários.
Login com Passkey
POST /_emdash/api/auth/passkey/options
Obter opções de autenticação WebAuthn.
POST /_emdash/api/auth/passkey/verify
Content-Type: application/json
{
"id": "credential-id",
"rawId": "...",
"response": {...},
"type": "public-key"
}
Verificar passkey e criar sessão.
Magic Link
POST /_emdash/api/auth/magic-link/send
Content-Type: application/json
{
"email": "[email protected]"
}
GET /_emdash/api/auth/magic-link/verify?token=xxx
Logout
POST /_emdash/api/auth/logout
Usuário atual
GET /_emdash/api/auth/me
Convidar usuário
POST /_emdash/api/auth/invite
Content-Type: application/json
{
"email": "[email protected]",
"role": 30
}
Gerenciamento de Passkeys
GET /_emdash/api/auth/passkey
Listar passkeys do usuário.
POST /_emdash/api/auth/passkey/register/options
POST /_emdash/api/auth/passkey/register/verify
Registrar novo passkey.
PATCH /_emdash/api/auth/passkey/:id
Content-Type: application/json
{
"name": "MacBook Pro"
}
Renomear passkey.
DELETE /_emdash/api/auth/passkey/:id
Excluir passkey.
Endpoints de importação
Analisar exportação WordPress
POST /_emdash/api/import/wordpress/analyze
Content-Type: multipart/form-data
file: <WXR file>
Executar importação WordPress
POST /_emdash/api/import/wordpress/execute
Content-Type: application/json
{
"analysisId": "...",
"options": {
"includeMedia": true,
"includeTaxonomies": true,
"includeMenus": true
}
}
Limitação de taxa
Os endpoints da API podem ser limitados em taxa com base na configuração do deployment. Quando limitados, as respostas incluem:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
CORS
A API suporta CORS para requisições do navegador. Configure as origens permitidas no seu deployment.