EmDash stellt eine REST-API unter /_emdash/api/ für Inhaltsverwaltung, Medien-Uploads und Schema-Operationen bereit.
Authentifizierung
API-Anfragen erfordern Authentifizierung über ein Bearer-Token im Authorization-Header:
Authorization: Bearer <token>
Generieren Sie Token über die Admin-Oberfläche oder programmgesteuert.
Antwortformat
Alle Antworten folgen einem einheitlichen Format. Eine erfolgreiche Antwort umhüllt das Ergebnis in data:
{
"success": true,
"data": { ... }
}
Eine Fehlerantwort enthält einen Code, eine Nachricht und optionale Details:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable message",
"details": { ... }
}
}
Inhalts-Endpunkte
Inhalte auflisten
GET /_emdash/api/content/:collection
Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
collection | string | Collection-Slug (Pfad) |
cursor | string | Paginierungs-Cursor (Query) |
limit | number | Einträge pro Seite (Query, Standard: 50) |
status | string | Nach Status filtern (Query) |
orderBy | string | Sortierfeld (Query) |
order | string | Sortierrichtung: asc oder desc (Query) |
Antwort
{
"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..."
}
}
Inhalt abrufen
GET /_emdash/api/content/:collection/:id
Antwort
{
"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"
}
}
}
Inhalt erstellen
POST /_emdash/api/content/:collection
Content-Type: application/json
Anfragekörper
{
"data": {
"title": "New Post",
"content": [...]
},
"slug": "new-post",
"status": "draft"
}
Antwort
{
"success": true,
"data": {
"item": { ... }
}
}
Inhalt aktualisieren
PUT /_emdash/api/content/:collection/:id
Content-Type: application/json
Anfragekörper
{
"data": {
"title": "Updated Title"
},
"status": "published"
}
Inhalt löschen
DELETE /_emdash/api/content/:collection/:id
Antwort
{
"success": true,
"data": {
"success": true
}
}
Medien-Endpunkte
Medien auflisten
GET /_emdash/api/media?includeUsage=1
Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
cursor | string | Undurchsichtiger Paginierungs-Cursor |
limit | number | Einträge pro Seite, von 1 bis 100 (Standard: 50) |
mimeType | string | Nach einem oder mehreren kommaseparierten MIME-Typen filtern |
q | string | Groß-/Kleinschreibung-unabhängige Dateinamensuche |
includeUsage | 1 | Abdeckungsbezogene usage-Zusammenfassung für jeden zurückgegebenen Eintrag einschließen |
Antwort
{
"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..."
}
}
Medien abrufen
GET /_emdash/api/media/:id?includeUsage=1
includeUsage ist sowohl bei List als auch bei Get optional. Der einzige akzeptierte Wert ist 1. Wenn weggelassen,
wird die usage-Eigenschaft weggelassen und der Server führt keine Nutzungsabfragen durch.
Nutzungszusammenfassungen
usage.count ist die Anzahl der eindeutigen aktiven EmDash-Inhaltszeilen oder Locales, deren ausgewählte
aktuelle indizierte Quelle das Medienelement referenziert. Wiederholte Referenzen und mehrere Quellvarianten
für denselben Inhaltseintrag zählen einmal. Papierkorb-Inhalte werden nicht gezählt.
Eine numerische Anzahl kann Entwurfs-ähnliche Inhalte offenlegen. Sie wird nur zurückgegeben, wenn ein Sitzungsbenutzer
content:read_drafts hat, oder wenn ein API-Token den admin-Scope hat und sein zugehöriger Benutzer ebenfalls
diese Berechtigung besitzt. Andere Medienleser erhalten usage.count: null; dies ist eine erfolgreiche geschwärzte
Antwort, kein Fehler.
Jede angeforderte Zusammenfassung enthält eine aggregierte Abdeckung für alle aktuell registrierten Inhalts-Collections:
| Status | Bedeutung |
|---|---|
complete | Jede registrierte Collection hat aktuelle, vollständige Nutzungsabdeckung |
never | Keine registrierte Collection hat eine erste Nutzungsreparatur abgeschlossen |
running | Eine Nutzungsreparatur läuft gerade |
partial | Die Abdeckung ist gemischt oder nur ein Teil des registrierten Umfangs wurde indiziert |
failed | Die Abdeckung ist im registrierten Umfang fehlgeschlagen |
stale | Die indizierte Abdeckung ist veraltet |
unknown | Die gespeicherte Abdeckung enthält einen Zustand, den diese Version nicht erkennt |
Nur complete unterstützt eine umfangsbezogene vollständige Null-Aussage innerhalb der von EmDash verwalteten Felder,
die unten beschrieben werden. Zählungen mit einem anderen Status sind indizierte Projektionen und können über- oder
unterberichten. Selbst vollständige Ergebnisse sind bei gleichzeitigen Schreibvorgängen beratend; Nutzungslesungen sind kein
transaktionaler Lock und dürfen nicht als Löschgarantie verwendet werden.
Medien-Nutzungsdetails abrufen
GET /_emdash/api/media/:id/usage?limit=50&cursor=...
Dieser Endpunkt erfordert media:read und content:read_drafts. Token-authentifizierte Aufrufer benötigen
auch den admin-Scope; der Token-Scope umgeht nicht die Berechtigungen des zugehörigen Benutzers.
limit steuert Inhaltseintrag-Gruppen pro Seite, von 1 bis 100 (Standard: 50). Die Paginierung teilt
niemals die Quellen oder Vorkommen für eine zurückgegebene Eintragsgruppe auf.
{
"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"
}
}
}
Autorisierte Details umfassen aktive und gelöschte Einträge. Ein nicht-null deletedAt identifiziert einen
gelöschten Eintrag. Quellen sind columns oder draft_overlay; Vorkommen identifizieren das unterstützte Feld
und den Pfad, ohne interne Index-Metadaten offenzulegen.
Die Mediennutzung umfasst lokale Medienreferenzen in Top-Level-Bild- und Dateifeldern, Repeater-Bildfeldern und Portable-Text-Bildblöcken, die von EmDash-Inhalts-Collections verwaltet werden. Sie scannt keinen benutzerdefinierten Code, gerendertes HTML, Einstellungen, Menüs, Widgets, Plugin-private Daten, externe Seiten oder ausschließlich anbieterspezifische Assets.
Medien erstellen
POST /_emdash/api/media
Content-Type: application/json
Anfragekörper
{
"filename": "photo.jpg",
"mimeType": "image/jpeg",
"size": 102400,
"width": 1920,
"height": 1080,
"storageKey": "uploads/photo.jpg"
}
Medien aktualisieren
PUT /_emdash/api/media/:id
Content-Type: application/json
Anfragekörper
{
"alt": "Photo description",
"caption": "Photo caption"
}
Medien löschen
DELETE /_emdash/api/media/:id
Mediennutzung reparieren
POST /_emdash/api/admin/media-usage/repair
Content-Type: application/json
X-EmDash-Request: 1
Repariert den Inhalts-Mediennutzungs-Index für eine Collection oder für alle Inhalts-Collections. Dies ist ein Admin-/Operator-Endpunkt: Sitzungs-authentifizierte Aufrufer benötigen schema:manage, und Bearer-Token müssen den admin-Scope haben, da die Route unter /_emdash/api/admin liegt.
Die Reparatur aller Inhalte läuft synchron und sequenziell in der aktuellen Version. Sie kann bei großen Websites teuer sein, daher sollten Aufrufer sie bewusst auslösen und auf die Antwort warten.
Anfragekörper
Eine Collection reparieren:
{
"scope": "collection",
"collection": "posts"
}
Alle Inhalts-Collections reparieren:
{
"scope": "all"
}
Der Anfragekörper ist erforderlich. Ungültige Slugs, unbekannte Anfrageschlüssel, fehlender scope und Anfragen ohne Body geben 400 zurück, anstatt standardmäßig alle Inhalte zu reparieren.
Antwort
Der Endpunkt gibt 200 zurück, wenn ein Reparaturaufruf ein strukturiertes Ergebnis erzeugt. Überprüfen Sie data.status: failed und stale sind Reparatur-Domain-Status, keine Transportfehler.
{
"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"
}
]
}
}
Antwortfelder auf oberster Ebene:
| Feld | Typ | Beschreibung |
|---|---|---|
status | complete | partial | failed | stale | Aggregierter Reparaturstatus |
indexedSourceCount | number | Während der Reparatur indizierte Quellen |
failedSourceCount | number | Während der Reparatur fehlgeschlagene Quellen |
skippedSourceCount | number | Übersprungene Quellen, einschließlich veralteter Konflikte |
deletedSourceCount | number | Während der Reparatur gelöschte veraltete Nutzungszeilen |
collections | array | Reparaturzusammenfassungen pro Collection |
Zusammenfassungsfelder pro Collection:
| Feld | Typ | Beschreibung |
|---|---|---|
collection | string | Collection-Slug |
status | complete | partial | failed | stale | Collection-Reparaturstatus |
indexedSourceCount | number | Für diese Collection indizierte Quellen |
failedSourceCount | number | Für diese Collection fehlgeschlagene Quellen |
skippedSourceCount | number | Für diese Collection übersprungene Quellen |
deletedSourceCount | number | Für diese Collection gelöschte veraltete Nutzungszeilen |
lastErrorCode | string | null | Letzter Collection-Reparaturfehler, wenn verfügbar |
startedAt | string | Startzeitpunkt der Reparatur |
completedAt | string | null | Abschlusszeit, oder null für veraltete Ergebnisse |
Unbekannte Collections geben 200 mit data.status: "failed" und einem pro-Collection-lastErrorCode wie COLLECTION_NOT_FOUND zurück. Transportfehler verwenden weiterhin den Standard-Fehlerumschlag, einschließlich 400, 401, 403, 413 und 500.
Mediendatei abrufen
GET /_emdash/api/media/file/:key
Liefert den eigentlichen Dateiinhalt. Nur für lokalen Speicher.
Revisions-Endpunkte
Revisionen auflisten
GET /_emdash/api/content/:collection/:entryId/revisions
Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
limit | number | Max. zurückzugebende Revisionen (Standard: 50) |
Antwort
{
"success": true,
"data": {
"items": [
{
"id": "01HXK5MZSN...",
"collection": "posts",
"entryId": "01HXK5MZSN...",
"data": { ... },
"createdAt": "2025-01-24T12:00:00Z"
}
],
"total": 5
}
}
Revision abrufen
GET /_emdash/api/revisions/:revisionId
Revision wiederherstellen
POST /_emdash/api/revisions/:revisionId/restore
Stellt den Inhalt auf den Zustand dieser Revision wieder her und erstellt eine neue Revision.
Schema-Endpunkte
Collections auflisten
GET /_emdash/api/schema/collections
Antwort
{
"success": true,
"data": {
"items": [
{
"id": "01HXK5MZSN...",
"slug": "posts",
"label": "Posts",
"labelSingular": "Post",
"supports": ["drafts", "revisions", "preview"]
}
]
}
}
Collection abrufen
GET /_emdash/api/schema/collections/:slug
Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
includeFields | boolean | Felddefinitionen einschließen (Query) |
Collection erstellen
POST /_emdash/api/schema/collections
Content-Type: application/json
Anfragekörper
{
"slug": "products",
"label": "Products",
"labelSingular": "Product",
"description": "Product catalog",
"supports": ["drafts", "revisions"]
}
Collection aktualisieren
PUT /_emdash/api/schema/collections/:slug
Content-Type: application/json
Collection löschen
DELETE /_emdash/api/schema/collections/:slug
Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
force | boolean | Auch löschen, wenn die Collection Inhalte hat (Query) |
Felder auflisten
GET /_emdash/api/schema/collections/:slug/fields
Feld erstellen
POST /_emdash/api/schema/collections/:slug/fields
Content-Type: application/json
Anfragekörper
{
"slug": "price",
"label": "Price",
"type": "number",
"required": true,
"validation": {
"min": 0
}
}
Feld aktualisieren
PUT /_emdash/api/schema/collections/:collectionSlug/fields/:fieldSlug
Content-Type: application/json
Feld löschen
DELETE /_emdash/api/schema/collections/:collectionSlug/fields/:fieldSlug
Felder neu sortieren
POST /_emdash/api/schema/collections/:slug/fields/reorder
Content-Type: application/json
Anfragekörper
{
"fieldSlugs": ["title", "content", "author", "publishedAt"]
}
Schema-Export
Schema exportieren (JSON)
GET /_emdash/api/schema
Accept: application/json
Schema exportieren (TypeScript)
GET /_emdash/api/schema?format=typescript
Accept: text/typescript
Gibt TypeScript-Interfaces für alle Collections zurück.
Plugin-Endpunkte
Plugins auflisten
GET /_emdash/api/admin/plugins
Plugin abrufen
GET /_emdash/api/admin/plugins/:id
Plugin aktivieren
POST /_emdash/api/admin/plugins/:id/enable
Plugin deaktivieren
POST /_emdash/api/admin/plugins/:id/disable
Fehlercodes
| Code | HTTP-Status | Beschreibung |
|---|---|---|
NOT_FOUND | 404 | Ressource nicht gefunden |
VALIDATION_ERROR | 400 | Ungültige Eingabedaten |
UNAUTHORIZED | 401 | Fehlendes oder ungültiges Token |
FORBIDDEN | 403 | Unzureichende Berechtigungen |
CONTENT_LIST_ERROR | 500 | Inhalte auflisten fehlgeschlagen |
CONTENT_CREATE_ERROR | 500 | Inhalt erstellen fehlgeschlagen |
CONTENT_UPDATE_ERROR | 500 | Inhalt aktualisieren fehlgeschlagen |
CONTENT_DELETE_ERROR | 500 | Inhalt löschen fehlgeschlagen |
MEDIA_LIST_ERROR | 500 | Medien auflisten fehlgeschlagen |
MEDIA_CREATE_ERROR | 500 | Medien erstellen fehlgeschlagen |
SCHEMA_CREATE_ERROR | 500 | Schema-Operation fehlgeschlagen |
SLUG_CONFLICT | 409 | Slug existiert bereits |
RESERVED_SLUG | 400 | Slug ist reserviert |
Such-Endpunkte
Globale Suche
GET /_emdash/api/search?q=hello+world
Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
q | string | Suchabfrage (erforderlich) |
collections | string | Kommaseparierte Collection-Slugs |
status | string | Nach Status filtern (Standard: published) |
limit | number | Max. Ergebnisse (Standard: 20) |
cursor | string | Paginierungs-Cursor |
Antwort
{
"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"
}
}
Suchvorschläge
GET /_emdash/api/search/suggest?q=hel&limit=5
Gibt präfixübereinstimmende Titel für die Autovervollständigung zurück.
Suchindex neu erstellen
POST /_emdash/api/search/rebuild
FTS-Index für alle oder bestimmte Collections neu erstellen.
Suchstatistiken
GET /_emdash/api/search/stats
Gibt die Anzahl indizierter Dokumente pro Collection zurück.
Abschnitts-Endpunkte
Abschnitte auflisten
GET /_emdash/api/sections
GET /_emdash/api/sections?source=theme
GET /_emdash/api/sections?search=newsletter
Abschnitt abrufen
GET /_emdash/api/sections/:slug
Abschnitt erstellen
POST /_emdash/api/sections
Content-Type: application/json
{
"slug": "my-section",
"title": "My Section",
"keywords": ["keyword1"],
"content": [...]
}
Abschnitt aktualisieren
PUT /_emdash/api/sections/:slug
Abschnitt löschen
DELETE /_emdash/api/sections/:slug
Einstellungs-Endpunkte
Alle Einstellungen abrufen
GET /_emdash/api/settings
Einstellungen aktualisieren
POST /_emdash/api/settings
Content-Type: application/json
{
"siteTitle": "My Site",
"tagline": "A great site",
"postsPerPage": 10
}
Menü-Endpunkte
Menüs auflisten
GET /_emdash/api/menus
Menü abrufen
GET /_emdash/api/menus/:name
Menü erstellen
POST /_emdash/api/menus
Content-Type: application/json
{
"name": "main",
"label": "Main Navigation",
"items": []
}
Menü aktualisieren
PUT /_emdash/api/menus/:name
Menü löschen
DELETE /_emdash/api/menus/:name
Menüeintrag hinzufügen
POST /_emdash/api/menus/:name/items
Content-Type: application/json
{
"label": "About",
"url": "/about",
"position": 0
}
Menüeinträge neu sortieren
POST /_emdash/api/menus/:name/reorder
Content-Type: application/json
{
"itemIds": ["item_1", "item_2", "item_3"]
}
Taxonomie-Endpunkte
Taxonomie-Definitionen auflisten
GET /_emdash/api/taxonomies
Taxonomie erstellen
POST /_emdash/api/taxonomies
Content-Type: application/json
{
"name": "categories",
"label": "Categories",
"hierarchical": true,
"collections": ["posts"]
}
Begriffe auflisten
GET /_emdash/api/taxonomies/:name/terms
Begriff erstellen
POST /_emdash/api/taxonomies/:name/terms
Content-Type: application/json
{
"slug": "tutorials",
"label": "Tutorials",
"parentId": "term_abc",
"description": "How-to guides"
}
Begriff aktualisieren
PUT /_emdash/api/taxonomies/:name/terms/:slug
Begriff löschen
DELETE /_emdash/api/taxonomies/:name/terms/:slug
Eintragsbegriffe setzen
POST /_emdash/api/content/:collection/:id/terms/:taxonomy
Content-Type: application/json
{
"termIds": ["term_news", "term_featured"]
}
Widget-Bereich-Endpunkte
Widget-Bereiche auflisten
GET /_emdash/api/widget-areas
Widget-Bereich abrufen
GET /_emdash/api/widget-areas/:name
Widget-Bereich erstellen
POST /_emdash/api/widget-areas
Content-Type: application/json
{
"name": "sidebar",
"label": "Main Sidebar",
"description": "Appears on posts"
}
Widget-Bereich löschen
DELETE /_emdash/api/widget-areas/:name
Widget hinzufügen
POST /_emdash/api/widget-areas/:name/widgets
Content-Type: application/json
{
"type": "content",
"title": "About",
"content": [...]
}
Widget aktualisieren
PUT /_emdash/api/widget-areas/:name/widgets/:id
Widget löschen
DELETE /_emdash/api/widget-areas/:name/widgets/:id
Widgets neu sortieren
POST /_emdash/api/widget-areas/:name/reorder
Content-Type: application/json
{
"widgetIds": ["widget_1", "widget_2", "widget_3"]
}
Benutzerverwaltungs-Endpunkte
Benutzer auflisten
GET /_emdash/api/admin/users
GET /_emdash/api/admin/users?role=40
GET /_emdash/api/admin/users?search=john
Benutzer abrufen
GET /_emdash/api/admin/users/:id
Benutzer aktualisieren
PUT /_emdash/api/admin/users/:id
Content-Type: application/json
{
"name": "John Doe",
"role": 40
}
Benutzer aktivieren
POST /_emdash/api/admin/users/:id/enable
Benutzer deaktivieren
POST /_emdash/api/admin/users/:id/disable
Authentifizierungs-Endpunkte
Setup-Status
GET /_emdash/api/setup/status
Gibt zurück, ob das Setup abgeschlossen ist und ob Benutzer existieren.
Passkey-Anmeldung
POST /_emdash/api/auth/passkey/options
WebAuthn-Authentifizierungsoptionen abrufen.
POST /_emdash/api/auth/passkey/verify
Content-Type: application/json
{
"id": "credential-id",
"rawId": "...",
"response": {...},
"type": "public-key"
}
Passkey verifizieren und Sitzung erstellen.
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
Abmelden
POST /_emdash/api/auth/logout
Aktueller Benutzer
GET /_emdash/api/auth/me
Benutzer einladen
POST /_emdash/api/auth/invite
Content-Type: application/json
{
"email": "[email protected]",
"role": 30
}
Passkey-Verwaltung
GET /_emdash/api/auth/passkey
Passkeys des Benutzers auflisten.
POST /_emdash/api/auth/passkey/register/options
POST /_emdash/api/auth/passkey/register/verify
Neuen Passkey registrieren.
PATCH /_emdash/api/auth/passkey/:id
Content-Type: application/json
{
"name": "MacBook Pro"
}
Passkey umbenennen.
DELETE /_emdash/api/auth/passkey/:id
Passkey löschen.
Import-Endpunkte
WordPress-Export analysieren
POST /_emdash/api/import/wordpress/analyze
Content-Type: multipart/form-data
file: <WXR file>
WordPress-Import ausführen
POST /_emdash/api/import/wordpress/execute
Content-Type: application/json
{
"analysisId": "...",
"options": {
"includeMedia": true,
"includeTaxonomies": true,
"includeMenus": true
}
}
Ratenbegrenzung
API-Endpunkte können je nach Deployment-Konfiguration ratenbegrenzt sein. Bei Ratenbegrenzung enthalten die Antworten:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
CORS
Die API unterstützt CORS für Browser-Anfragen. Konfigurieren Sie erlaubte Origins in Ihrem Deployment.