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.

bash
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

bash
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.

ts
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 Relation

Seiten 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:

json
{
  "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:

json
{
  "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:

ts
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

js
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 })