Referência da API REST

Nesta página

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âmetroTipoDescrição
collectionstringSlug da coleção (caminho)
cursorstringCursor de paginação (query)
limitnumberItens por página (query, padrão: 50)
statusstringFiltrar por status (query)
orderBystringCampo de ordenação (query)
orderstringDireçã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âmetroTipoDescrição
cursorstringCursor de paginação opaco
limitnumberItens por página, de 1 a 100 (padrão: 50)
mimeTypestringFiltrar por um ou mais tipos MIME separados por vírgula
qstringPesquisa de nome de arquivo insensível a maiúsculas
includeUsage1Incluir 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:

StatusSignificado
completeCada coleção registrada tem cobertura de uso atual e completada
neverNenhuma coleção registrada completou uma reparação de uso inicial
runningUma reparação de uso está atualmente em execução
partialA cobertura é mista ou apenas parte do escopo registrado foi indexado
failedA cobertura falhou em todo o escopo registrado
staleA cobertura indexada está desatualizada
unknownA 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:

CampoTipoDescrição
statuscomplete | partial | failed | staleStatus de reparação agregado
indexedSourceCountnumberFontes indexadas durante a reparação
failedSourceCountnumberFontes que falharam durante a reparação
skippedSourceCountnumberFontes ignoradas, incluindo conflitos obsoletos
deletedSourceCountnumberLinhas de uso obsoletas excluídas durante a reparação
collectionsarrayResumos de reparação por coleção

Campos de resumo por coleção:

CampoTipoDescrição
collectionstringSlug da coleção
statuscomplete | partial | failed | staleStatus de reparação da coleção
indexedSourceCountnumberFontes indexadas para esta coleção
failedSourceCountnumberFontes que falharam para esta coleção
skippedSourceCountnumberFontes ignoradas para esta coleção
deletedSourceCountnumberLinhas de uso obsoletas excluídas para esta coleção
lastErrorCodestring | nullÚltimo erro de reparação da coleção, quando disponível
startedAtstringHora de início da reparação
completedAtstring | nullHora 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âmetroTipoDescrição
limitnumberMá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âmetroTipoDescrição
includeFieldsbooleanIncluir 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âmetroTipoDescrição
forcebooleanExcluir 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ódigoStatus HTTPDescrição
NOT_FOUND404Recurso não encontrado
VALIDATION_ERROR400Dados de entrada inválidos
UNAUTHORIZED401Token ausente ou inválido
FORBIDDEN403Permissões insuficientes
CONTENT_LIST_ERROR500Falha ao listar conteúdo
CONTENT_CREATE_ERROR500Falha ao criar conteúdo
CONTENT_UPDATE_ERROR500Falha ao atualizar conteúdo
CONTENT_DELETE_ERROR500Falha ao excluir conteúdo
MEDIA_LIST_ERROR500Falha ao listar mídia
MEDIA_CREATE_ERROR500Falha ao criar mídia
SCHEMA_CREATE_ERROR500Operação de esquema falhou
SLUG_CONFLICT409Slug já existe
RESERVED_SLUG400Slug é reservado

Endpoints de pesquisa

Pesquisa global

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

Parâmetros

ParâmetroTipoDescrição
qstringConsulta de pesquisa (obrigatório)
collectionsstringSlugs de coleções separados por vírgula
statusstringFiltrar por status (padrão: published)
limitnumberMáx. resultados (padrão: 20)
cursorstringCursor 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.

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.