Delivery API
Die öffentliche Lese-API von Entrydeck: Authentifizierung mit x-api-key oder Plattform-Schlüssel, alle Endpunkte, expand für Relationen und Medien, das SEO-Objekt, Musterseiten, Beispiele mit curl und fetch.
Stand: 23.09.2026
Auf dieser Seite
Die Delivery API ist die Lese-Schnittstelle, über die Frontends veröffentlichte Inhalte abrufen. Sie ist bewusst schlank: wenige Endpunkte, JSON, ein Header zur Authentifizierung, HTTP-Caching mit ETag. Jedes Frontend-Framework kann sie verwenden — Nuxt, Next, Astro, SvelteKit, PHP, statische Generatoren.
Basis-URL: https://entrydeck.app/api/v1/delivery
Authentifizierung
| Header | Wer | Bedeutung |
|---|---|---|
x-api-key |
jedes Frontend | der geheime API-Key einer Website (Website-Einstellungen) |
x-site-id |
optional | öffentliche Site-ID; mit x-api-key muss sie zum Key passen |
x-platform-key |
Plattform-Renderer | ein gemeinsamer Schlüssel für einen Renderer, der viele Websites bedient |
x-site-host |
nur mit Plattform-Schlüssel | Hostname der gewünschten Website (der Host des Browsers) |
Der API-Key gehört in die Server-Umgebung, nie in Browser-Code. x-site-host allein wird nie beachtet — ohne Plattform-Schlüssel kann niemand durch einen gefälschten Header den Mandanten wechseln. Fehlt oder stimmt der Schlüssel nicht, antwortet die API mit 401.
export ENTRYDECK_API_KEY="ed_live_…"
curl https://entrydeck.app/api/v1/delivery/site -H "x-api-key: $ENTRYDECK_API_KEY"Endpunkte
| Methode und Pfad | Zweck |
|---|---|
GET /site |
Website-Info: Site-ID, Name, Sprachen, Domains, SEO-Einstellungen, Theme |
GET /page?route=/pfad&locale=de |
eine veröffentlichte Seite mit Blöcken, Breadcrumbs, SEO |
GET /pages/tree?locale=de |
veröffentlichter Seitenbaum für Menüs und Sitemaps |
GET /navigation/{handle}?locale=de |
ein Menü als verschachtelter Baum |
GET /content/{typ}?locale=de |
Liste veröffentlichter Einträge eines Typs (Filter, Sortierung, Seiten) |
GET /content/{typ}/{slug}?locale=de |
ein Eintrag |
GET /search?q=…&locale=de |
Volltextsuche über veröffentlichte Einträge |
GET /sitemap?locale=de |
alle Seitenpfade und Eintrags-Slugs mit Zeitstempeln |
GET /form/{slug} |
Formulardefinition mit Validierungsregeln und Captcha-Site-Key |
POST /../forms/{id}/submissions |
Formular absenden (siehe Formulare) |
GET /consent, GET /consent/declaration |
Consentdeck-Konfiguration und Cookie-Erklärung |
GET /a11y |
Konfiguration des Barrierefreiheits-Widgets |
Alle Antworten enthalten nur veröffentlichte Inhalte, die der Website zugewiesen sind.
Listen: Filter, Sortierung, Seiten
curl "https://entrydeck.app/api/v1/delivery/content/beitrag?locale=de&page=1&limit=20&sort=publishedAt&order=desc&featured=true&filter[category]=news" \
-H "x-api-key: $ENTRYDECK_API_KEY"| Parameter | Werte |
|---|---|
page, limit |
Seite ab 1, bis 100 Einträge je Seite (Standard 20) |
sort |
createdAt, updatedAt, publishedAt, slug |
order |
asc, desc |
featured |
nur Einträge mit data.featured = true |
filter[feld]=wert |
Gleichheit auf einem Datenfeld, mehrfach kombinierbar |
expand |
relations, media oder all |
Die Antwort enthält items, total, page, limit.
expand: Relationen und Medien auflösen
Standardmäßig enthalten Relations- und Medienfelder nur IDs — das hält Antworten klein. expand=relations liefert die verknüpften Einträge, expand=media die Medienobjekte mit URL, Varianten, Abmessungen, Alternativtext und Fokuspunkt. expand=all beides. Das gilt für Seiten (Blöcke) und Einträge gleichermaßen.
const entry = await $fetch('/content/produkt/master-cms', {
baseURL: 'https://entrydeck.app/api/v1/delivery',
headers: { 'x-api-key': process.env.ENTRYDECK_API_KEY! },
query: { locale: 'de', expand: 'all' },
})
entry.data.hero.url // aufgelöstes Medium
entry.data.category.slug // aufgelöste RelationSeiten und Musterseiten
GET /page?route=/produkte/master-cms findet zuerst eine Seite mit genau diesem Pfad. Gibt es keine, werden Musterseiten wie /produkte/:slug Segment für Segment verglichen; die Werte kommen unter params zurück. Die Antwort:
{
"website": { "siteId": "…", "name": "Muster GmbH", "defaultLocale": "de" },
"page": { "id": "…", "title": "…", "fullPath": "/produkte/:slug", "template": { "componentKey": "ProductPage" }, "blocks": [ … ], "seo": { … } },
"params": { "slug": "master-cms" },
"requestedRoute": "/produkte/master-cms",
"breadcrumbs": [ { "title": "Produkte", "fullPath": "/produkte" } ]
}Das SEO-Objekt
Seiten und Einträge tragen ein fertig aufgelöstes seo-Objekt. Das Frontend muss nichts mehr zusammensetzen:
{
"title": "Master-CMS · Muster GmbH",
"description": "…",
"canonical": "https://muster.de/produkte/master-cms",
"robots": "index, follow", "noindex": false,
"keywords": ["cms", "headless"],
"image": { "url": "…", "width": 1200, "height": 630, "alt": "…" },
"ogTitle": "…", "ogDescription": "…", "ogImage": { … }, "ogType": "website",
"twitterCard": "summary_large_image",
"hreflang": [ { "locale": "de", "href": "https://muster.de/produkte/master-cms" }, { "locale": "en", "href": "https://muster.de/en/products/master-cms" } ],
"geo": { "lat": 50.63, "lng": 12.81, "place": "Zwönitz", "region": "DE-SN" },
"meta": [ { "name": "geo.position", "content": "50.63;12.81" } ],
"jsonLd": [ { "@type": "BreadcrumbList", "itemListElement": [ … ] }, { "@type": "Product", "name": "…" } ]
}Titel und Beschreibung fallen auf Seitentitel bzw. die erste Textzeile zurück; die Canonical-URL nutzt die primäre Domain der Website; hreflang enthält dieselbe Seite in allen Sprachen; jsonLd baut derselbe Generator wie die Vorschau im Admin.
Einbau in Nuxt:
useSeoMeta({ title: seo.title, description: seo.description, ogImage: seo.ogImage?.url })
useHead({
link: [{ rel: 'canonical', href: seo.canonical }, ...seo.hreflang.map(h => ({ rel: 'alternate', hreflang: h.locale, href: h.href }))],
meta: seo.meta,
script: seo.jsonLd.map(obj => ({ type: 'application/ld+json', innerHTML: JSON.stringify(obj) })),
})Caching
Antworten tragen ETag und Cache-Control. Bei If-None-Match antwortet die API mit 304. Für statische Frontends empfiehlt sich ein Build-Hook über Webhooks, damit die Seite nach jeder Veröffentlichung neu entsteht.
Fehler
| Status | Bedeutung |
|---|---|
400 |
Pflichtparameter fehlt (route, locale, q) |
401 |
Schlüssel fehlt oder ungültig |
404 |
Seite, Typ oder Eintrag nicht veröffentlicht oder nicht dieser Website zugewiesen |
429 |
Rate-Limit an Formular-Endpunkten |
Vollständiges Beispiel mit fetch
const API = 'https://entrydeck.app/api/v1/delivery'
const headers = { 'x-api-key': process.env.ENTRYDECK_API_KEY }
const site = await fetch(`${API}/site`, { headers }).then(r => r.json())
const home = await fetch(`${API}/page?route=/&locale=${site.defaultLocale}&expand=all`, { headers }).then(r => r.json())
const nav = await fetch(`${API}/navigation/main?locale=${site.defaultLocale}`, { headers }).then(r => r.json())
render({ theme: site.theme, page: home.page, nav: nav.items })