EmDash espone un’API REST in /_emdash/api/ per la gestione dei contenuti, l’upload di media e le operazioni sugli schemi.
Autenticazione
Le richieste API richiedono l’autenticazione tramite un token Bearer nell’header Authorization:
Authorization: Bearer <token>
Genera token tramite l’interfaccia di amministrazione o in modo programmatico.
Formato di risposta
Tutte le risposte seguono un formato coerente. Una risposta di successo avvolge il risultato in data:
{
"success": true,
"data": { ... }
}
Una risposta di errore include un codice, un messaggio e dettagli opzionali:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable message",
"details": { ... }
}
}
Endpoint dei contenuti
Elencare i contenuti
GET /_emdash/api/content/:collection
Parametri
| Parametro | Tipo | Descrizione |
|---|---|---|
collection | string | Slug della collezione (percorso) |
cursor | string | Cursore di paginazione (query) |
limit | number | Elementi per pagina (query, predefinito: 50) |
status | string | Filtrare per stato (query) |
orderBy | string | Campo di ordinamento (query) |
order | string | Direzione di ordinamento: asc o desc (query) |
Risposta
{
"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..."
}
}
Ottenere un contenuto
GET /_emdash/api/content/:collection/:id
Risposta
{
"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"
}
}
}
Creare un contenuto
POST /_emdash/api/content/:collection
Content-Type: application/json
Corpo della richiesta
{
"data": {
"title": "New Post",
"content": [...]
},
"slug": "new-post",
"status": "draft"
}
Risposta
{
"success": true,
"data": {
"item": { ... }
}
}
Aggiornare un contenuto
PUT /_emdash/api/content/:collection/:id
Content-Type: application/json
Corpo della richiesta
{
"data": {
"title": "Updated Title"
},
"status": "published"
}
Eliminare un contenuto
DELETE /_emdash/api/content/:collection/:id
Risposta
{
"success": true,
"data": {
"success": true
}
}
Endpoint dei media
Elencare i media
GET /_emdash/api/media?includeUsage=1
Parametri
| Parametro | Tipo | Descrizione |
|---|---|---|
cursor | string | Cursore di paginazione opaco |
limit | number | Elementi per pagina, da 1 a 100 (predefinito: 50) |
mimeType | string | Filtrare per uno o più tipi MIME separati da virgole |
q | string | Ricerca del nome file senza distinzione maiuscole/minuscole |
includeUsage | 1 | Includere un riepilogo di usage con copertura su ogni elemento restituito |
Risposta
{
"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..."
}
}
Ottenere un media
GET /_emdash/api/media/:id?includeUsage=1
includeUsage è opzionale sia per l’elenco che per l’ottenimento. Il suo unico valore accettato è 1. Quando omesso,
la proprietà usage viene omessa e il server non esegue query di utilizzo.
Riepiloghi di utilizzo
usage.count è il numero di righe di contenuto o locali attivi distinti di EmDash la cui sorgente
indicizzata corrente selezionata fa riferimento all’elemento media. I riferimenti ripetuti e le varianti
di sorgente multiple per la stessa voce di contenuto contano una volta. Il contenuto nel cestino non conta.
Un conteggio numerico può rivelare contenuti simili a bozze. Viene restituito solo quando un utente di sessione ha
content:read_drafts, o quando un token API ha lo scope admin e il suo utente associato ha anche
quel permesso. Gli altri lettori di media ricevono usage.count: null; questa è una risposta oscurata con successo,
non un errore.
Ogni riepilogo richiesto include la copertura aggregata per tutte le collezioni di contenuto attualmente registrate:
| Stato | Significato |
|---|---|
complete | Ogni collezione registrata ha una copertura di utilizzo corrente e completata |
never | Nessuna collezione registrata ha completato una riparazione di utilizzo iniziale |
running | Una riparazione di utilizzo è attualmente in corso |
partial | La copertura è mista o solo parte dell’ambito registrato è stato indicizzato |
failed | La copertura è fallita nell’ambito registrato |
stale | La copertura indicizzata è obsoleta |
unknown | La copertura memorizzata contiene uno stato che questa versione non riconosce |
Solo complete supporta una dichiarazione di zero completo con ambito nei campi gestiti da EmDash
descritti di seguito. I conteggi con qualsiasi altro stato sono proiezioni indicizzate e possono sovra-riportare o
sotto-riportare. Anche i risultati completi sono consultivi durante le scritture concorrenti; le letture di utilizzo non sono un
blocco transazionale e non devono essere usate come garanzia di eliminazione.
Ottenere i dettagli di utilizzo dei media
GET /_emdash/api/media/:id/usage?limit=50&cursor=...
Questo endpoint richiede media:read e content:read_drafts. I chiamanti autenticati con token richiedono
anche lo scope admin; lo scope del token non bypassa i permessi dell’utente associato.
limit controlla i gruppi di voci di contenuto per pagina, da 1 a 100 (predefinito: 50). La paginazione non
divide mai le sorgenti o le occorrenze per un gruppo di voci restituito.
{
"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"
}
}
}
I dettagli autorizzati includono voci attive e eliminate. Un deletedAt non null identifica una
voce nel cestino. Le sorgenti sono columns o draft_overlay; le occorrenze identificano il campo supportato
e il percorso senza esporre i metadati interni dell’indice.
L’utilizzo dei media copre i riferimenti ai media locali nei campi immagine e file di livello superiore, nei campi immagine dei ripetitori e nei blocchi immagine Portable Text gestiti dalle collezioni di contenuto EmDash. Non scansiona codice personalizzato, HTML renderizzato, impostazioni, menu, widget, dati privati dei plugin, siti esterni o asset esclusivi del provider.
Creare un media
POST /_emdash/api/media
Content-Type: application/json
Corpo della richiesta
{
"filename": "photo.jpg",
"mimeType": "image/jpeg",
"size": 102400,
"width": 1920,
"height": 1080,
"storageKey": "uploads/photo.jpg"
}
Aggiornare un media
PUT /_emdash/api/media/:id
Content-Type: application/json
Corpo della richiesta
{
"alt": "Photo description",
"caption": "Photo caption"
}
Eliminare un media
DELETE /_emdash/api/media/:id
Riparare l’utilizzo dei media
POST /_emdash/api/admin/media-usage/repair
Content-Type: application/json
X-EmDash-Request: 1
Ripara l’indice di utilizzo dei media di contenuto per una collezione o per tutte le collezioni di contenuto. Questo è un endpoint amministratore/operatore: i chiamanti autenticati per sessione necessitano di schema:manage, e i token Bearer devono avere lo scope admin perché la rotta è sotto /_emdash/api/admin.
La riparazione di tutto il contenuto viene eseguita in modo sincrono e sequenziale nella versione corrente. Può essere costosa sui siti di grandi dimensioni, quindi i chiamanti dovrebbero attivarla deliberatamente e attendere la risposta.
Corpo della richiesta
Riparare una collezione:
{
"scope": "collection",
"collection": "posts"
}
Riparare tutte le collezioni di contenuto:
{
"scope": "all"
}
Il corpo della richiesta è obbligatorio. Slug non validi, chiavi di richiesta sconosciute, scope mancante e richieste senza corpo restituiscono 400 invece di riparare tutto il contenuto per impostazione predefinita.
Risposta
L’endpoint restituisce 200 quando un’invocazione di riparazione produce un risultato strutturato. Ispeziona data.status: failed e stale sono stati del dominio di riparazione, non errori di trasporto.
{
"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"
}
]
}
}
Campi di risposta di livello superiore:
| Campo | Tipo | Descrizione |
|---|---|---|
status | complete | partial | failed | stale | Stato di riparazione aggregato |
indexedSourceCount | number | Sorgenti indicizzate durante la riparazione |
failedSourceCount | number | Sorgenti fallite durante la riparazione |
skippedSourceCount | number | Sorgenti saltate, inclusi conflitti obsoleti |
deletedSourceCount | number | Righe di utilizzo obsolete eliminate durante la riparazione |
collections | array | Riepiloghi di riparazione per collezione |
Campi di riepilogo per collezione:
| Campo | Tipo | Descrizione |
|---|---|---|
collection | string | Slug della collezione |
status | complete | partial | failed | stale | Stato di riparazione della collezione |
indexedSourceCount | number | Sorgenti indicizzate per questa collezione |
failedSourceCount | number | Sorgenti fallite per questa collezione |
skippedSourceCount | number | Sorgenti saltate per questa collezione |
deletedSourceCount | number | Righe di utilizzo obsolete eliminate per questa collezione |
lastErrorCode | string | null | Ultimo errore di riparazione della collezione, se disponibile |
startedAt | string | Ora di inizio della riparazione |
completedAt | string | null | Ora di completamento, o null per risultati obsoleti |
Le collezioni sconosciute restituiscono 200 con data.status: "failed" e un lastErrorCode per collezione come COLLECTION_NOT_FOUND. Gli errori di trasporto usano ancora l’involucro di errore standard, inclusi 400, 401, 403, 413 e 500.
Ottenere un file media
GET /_emdash/api/media/file/:key
Serve il contenuto effettivo del file. Solo per l’archiviazione locale.
Endpoint delle revisioni
Elencare le revisioni
GET /_emdash/api/content/:collection/:entryId/revisions
Parametri
| Parametro | Tipo | Descrizione |
|---|---|---|
limit | number | Max revisioni da restituire (predefinito: 50) |
Risposta
{
"success": true,
"data": {
"items": [
{
"id": "01HXK5MZSN...",
"collection": "posts",
"entryId": "01HXK5MZSN...",
"data": { ... },
"createdAt": "2025-01-24T12:00:00Z"
}
],
"total": 5
}
}
Ottenere una revisione
GET /_emdash/api/revisions/:revisionId
Ripristinare una revisione
POST /_emdash/api/revisions/:revisionId/restore
Ripristina il contenuto allo stato di questa revisione e crea una nuova revisione.
Endpoint dello schema
Elencare le collezioni
GET /_emdash/api/schema/collections
Risposta
{
"success": true,
"data": {
"items": [
{
"id": "01HXK5MZSN...",
"slug": "posts",
"label": "Posts",
"labelSingular": "Post",
"supports": ["drafts", "revisions", "preview"]
}
]
}
}
Ottenere una collezione
GET /_emdash/api/schema/collections/:slug
Parametri
| Parametro | Tipo | Descrizione |
|---|---|---|
includeFields | boolean | Includere le definizioni dei campi (query) |
Creare una collezione
POST /_emdash/api/schema/collections
Content-Type: application/json
Corpo della richiesta
{
"slug": "products",
"label": "Products",
"labelSingular": "Product",
"description": "Product catalog",
"supports": ["drafts", "revisions"]
}
Aggiornare una collezione
PUT /_emdash/api/schema/collections/:slug
Content-Type: application/json
Eliminare una collezione
DELETE /_emdash/api/schema/collections/:slug
Parametri
| Parametro | Tipo | Descrizione |
|---|---|---|
force | boolean | Eliminare anche se la collezione ha contenuti (query) |
Elencare i campi
GET /_emdash/api/schema/collections/:slug/fields
Creare un campo
POST /_emdash/api/schema/collections/:slug/fields
Content-Type: application/json
Corpo della richiesta
{
"slug": "price",
"label": "Price",
"type": "number",
"required": true,
"validation": {
"min": 0
}
}
Aggiornare un campo
PUT /_emdash/api/schema/collections/:collectionSlug/fields/:fieldSlug
Content-Type: application/json
Eliminare un campo
DELETE /_emdash/api/schema/collections/:collectionSlug/fields/:fieldSlug
Riordinare i campi
POST /_emdash/api/schema/collections/:slug/fields/reorder
Content-Type: application/json
Corpo della richiesta
{
"fieldSlugs": ["title", "content", "author", "publishedAt"]
}
Esportazione dello schema
Esportare lo schema (JSON)
GET /_emdash/api/schema
Accept: application/json
Esportare lo schema (TypeScript)
GET /_emdash/api/schema?format=typescript
Accept: text/typescript
Restituisce interfacce TypeScript per tutte le collezioni.
Endpoint dei plugin
Elencare i plugin
GET /_emdash/api/admin/plugins
Ottenere un plugin
GET /_emdash/api/admin/plugins/:id
Abilitare un plugin
POST /_emdash/api/admin/plugins/:id/enable
Disabilitare un plugin
POST /_emdash/api/admin/plugins/:id/disable
Codici di errore
| Codice | Stato HTTP | Descrizione |
|---|---|---|
NOT_FOUND | 404 | Risorsa non trovata |
VALIDATION_ERROR | 400 | Dati di input non validi |
UNAUTHORIZED | 401 | Token mancante o non valido |
FORBIDDEN | 403 | Permessi insufficienti |
CONTENT_LIST_ERROR | 500 | Errore nell’elencare i contenuti |
CONTENT_CREATE_ERROR | 500 | Errore nella creazione del contenuto |
CONTENT_UPDATE_ERROR | 500 | Errore nell’aggiornamento del contenuto |
CONTENT_DELETE_ERROR | 500 | Errore nell’eliminazione del contenuto |
MEDIA_LIST_ERROR | 500 | Errore nell’elencare i media |
MEDIA_CREATE_ERROR | 500 | Errore nella creazione del media |
SCHEMA_CREATE_ERROR | 500 | Operazione sullo schema fallita |
SLUG_CONFLICT | 409 | Lo slug esiste già |
RESERVED_SLUG | 400 | Lo slug è riservato |
Endpoint di ricerca
Ricerca globale
GET /_emdash/api/search?q=hello+world
Parametri
| Parametro | Tipo | Descrizione |
|---|---|---|
q | string | Query di ricerca (obbligatorio) |
collections | string | Slug delle collezioni separati da virgole |
status | string | Filtrare per stato (predefinito: published) |
limit | number | Max risultati (predefinito: 20) |
cursor | string | Cursore di paginazione |
Risposta
{
"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"
}
}
Suggerimenti di ricerca
GET /_emdash/api/search/suggest?q=hel&limit=5
Restituisce titoli con corrispondenza di prefisso per l’autocompletamento.
Ricostruire l’indice di ricerca
POST /_emdash/api/search/rebuild
Ricostruire l’indice FTS per tutte o specifiche collezioni.
Statistiche di ricerca
GET /_emdash/api/search/stats
Restituisce il conteggio dei documenti indicizzati per collezione.
Endpoint delle sezioni
Elencare le sezioni
GET /_emdash/api/sections
GET /_emdash/api/sections?source=theme
GET /_emdash/api/sections?search=newsletter
Ottenere una sezione
GET /_emdash/api/sections/:slug
Creare una sezione
POST /_emdash/api/sections
Content-Type: application/json
{
"slug": "my-section",
"title": "My Section",
"keywords": ["keyword1"],
"content": [...]
}
Aggiornare una sezione
PUT /_emdash/api/sections/:slug
Eliminare una sezione
DELETE /_emdash/api/sections/:slug
Endpoint delle impostazioni
Ottenere tutte le impostazioni
GET /_emdash/api/settings
Aggiornare le impostazioni
POST /_emdash/api/settings
Content-Type: application/json
{
"siteTitle": "My Site",
"tagline": "A great site",
"postsPerPage": 10
}
Endpoint dei menu
Elencare i menu
GET /_emdash/api/menus
Ottenere un menu
GET /_emdash/api/menus/:name
Creare un menu
POST /_emdash/api/menus
Content-Type: application/json
{
"name": "main",
"label": "Main Navigation",
"items": []
}
Aggiornare un menu
PUT /_emdash/api/menus/:name
Eliminare un menu
DELETE /_emdash/api/menus/:name
Aggiungere un elemento al menu
POST /_emdash/api/menus/:name/items
Content-Type: application/json
{
"label": "About",
"url": "/about",
"position": 0
}
Riordinare gli elementi del menu
POST /_emdash/api/menus/:name/reorder
Content-Type: application/json
{
"itemIds": ["item_1", "item_2", "item_3"]
}
Endpoint delle tassonomie
Elencare le definizioni delle tassonomie
GET /_emdash/api/taxonomies
Creare una tassonomia
POST /_emdash/api/taxonomies
Content-Type: application/json
{
"name": "categories",
"label": "Categories",
"hierarchical": true,
"collections": ["posts"]
}
Elencare i termini
GET /_emdash/api/taxonomies/:name/terms
Creare un termine
POST /_emdash/api/taxonomies/:name/terms
Content-Type: application/json
{
"slug": "tutorials",
"label": "Tutorials",
"parentId": "term_abc",
"description": "How-to guides"
}
Aggiornare un termine
PUT /_emdash/api/taxonomies/:name/terms/:slug
Eliminare un termine
DELETE /_emdash/api/taxonomies/:name/terms/:slug
Impostare i termini di una voce
POST /_emdash/api/content/:collection/:id/terms/:taxonomy
Content-Type: application/json
{
"termIds": ["term_news", "term_featured"]
}
Endpoint delle aree widget
Elencare le aree widget
GET /_emdash/api/widget-areas
Ottenere un’area widget
GET /_emdash/api/widget-areas/:name
Creare un’area widget
POST /_emdash/api/widget-areas
Content-Type: application/json
{
"name": "sidebar",
"label": "Main Sidebar",
"description": "Appears on posts"
}
Eliminare un’area widget
DELETE /_emdash/api/widget-areas/:name
Aggiungere un widget
POST /_emdash/api/widget-areas/:name/widgets
Content-Type: application/json
{
"type": "content",
"title": "About",
"content": [...]
}
Aggiornare un widget
PUT /_emdash/api/widget-areas/:name/widgets/:id
Eliminare un widget
DELETE /_emdash/api/widget-areas/:name/widgets/:id
Riordinare i widget
POST /_emdash/api/widget-areas/:name/reorder
Content-Type: application/json
{
"widgetIds": ["widget_1", "widget_2", "widget_3"]
}
Endpoint di gestione utenti
Elencare gli utenti
GET /_emdash/api/admin/users
GET /_emdash/api/admin/users?role=40
GET /_emdash/api/admin/users?search=john
Ottenere un utente
GET /_emdash/api/admin/users/:id
Aggiornare un utente
PUT /_emdash/api/admin/users/:id
Content-Type: application/json
{
"name": "John Doe",
"role": 40
}
Abilitare un utente
POST /_emdash/api/admin/users/:id/enable
Disabilitare un utente
POST /_emdash/api/admin/users/:id/disable
Endpoint di autenticazione
Stato della configurazione
GET /_emdash/api/setup/status
Restituisce se la configurazione è completata e se esistono utenti.
Accesso con Passkey
POST /_emdash/api/auth/passkey/options
Ottenere le opzioni di autenticazione WebAuthn.
POST /_emdash/api/auth/passkey/verify
Content-Type: application/json
{
"id": "credential-id",
"rawId": "...",
"response": {...},
"type": "public-key"
}
Verificare il passkey e creare una sessione.
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
Disconnessione
POST /_emdash/api/auth/logout
Utente corrente
GET /_emdash/api/auth/me
Invitare un utente
POST /_emdash/api/auth/invite
Content-Type: application/json
{
"email": "[email protected]",
"role": 30
}
Gestione dei Passkey
GET /_emdash/api/auth/passkey
Elencare i passkey dell’utente.
POST /_emdash/api/auth/passkey/register/options
POST /_emdash/api/auth/passkey/register/verify
Registrare un nuovo passkey.
PATCH /_emdash/api/auth/passkey/:id
Content-Type: application/json
{
"name": "MacBook Pro"
}
Rinominare un passkey.
DELETE /_emdash/api/auth/passkey/:id
Eliminare un passkey.
Endpoint di importazione
Analizzare l’esportazione WordPress
POST /_emdash/api/import/wordpress/analyze
Content-Type: multipart/form-data
file: <WXR file>
Eseguire l’importazione WordPress
POST /_emdash/api/import/wordpress/execute
Content-Type: application/json
{
"analysisId": "...",
"options": {
"includeMedia": true,
"includeTaxonomies": true,
"includeMenus": true
}
}
Limitazione del tasso
Gli endpoint API possono essere limitati nel tasso in base alla configurazione del deployment. Quando limitati, le risposte includono:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
CORS
L’API supporta CORS per le richieste dal browser. Configura le origini consentite nel tuo deployment.