Diil Docs
  1. Doku
  2. API-Referenz

GET /v1/blocks/:marker — ein Block

Aktualisiert:

Manchmal brauchst du keine Seite und nicht mal eine Section — sondern genau ein Ding. Die Telefonnummer im Header. Das Promo-Banner über dem Shop. Den Preis, den das Marketing jeden Freitag ändert. Dieser Endpoint gibt dir einen einzelnen Block anhand seines Markers, und sonst nichts.

Typische Kandidaten:

  • Eine Telefonnummer oder E-Mail im Header — ein text-Block, der auf der Service-Seite common wohnt und überall auftaucht.
  • Ein Promo-Banner — ein object-Block mit Titel, Bild und Link, eingesetzt in ein Layout, das du ohnehin aus dem Code renderst.
  • Ein Preis — ein number-Block, den dein Checkout oder deine Landingpage liest, ohne die ganze Preisseite zu laden.

Einen Block abrufen

GET/v1/blocks/:marker

https://back.sitecog.com/content/v1/blocks/:marker

Ein Block mit seinem Wert in content. Dieselbe Form wie ein Block in der Response einer Seite oder Section — nur ohne die Verpackung drumherum.

Parameter

markerpathstringPflicht
Der Block-Marker aus dem CRM, z. B. phone oder promo_banner. Lateinische Buchstaben, Ziffern und Unterstriche, 2–40 Zeichen, Groß- und Kleinschreibung zählt.
sectionquerystringoptionalStandard: beliebige Section
Marker der Section, zu der der Block gehört, z. B. ?section=header. Block-Marker sind nur innerhalb einer Section eindeutig — so sagst du genau, welchen title du meinst. Ohne ihn gewinnt der erste Treffer: der älteste Block mit diesem Marker. Siehe unten.
langquerystringoptionalStandard: alle aktiven Sprachen
Übersetzungen auf diese Sprachen beschränken: ?lang=en, ?lang=en,de oder ?lang=en&lang=de. Jeder Code muss eine aktive Sprache der Website sein, sonst bekommst du 400 unknown_lang. Wirkt sich nicht auf Werte ohne Übersetzungen aus, etwa Zahlen oder Farben.
x-crm-keyheaderstringPflicht
Dein Site-Key. Geht auch als ?key=, falls Header keine Option sind. Siehe Site-Keys.

Ein ?empty gibt es hier nicht: Ein Block ohne seinen content wäre eine leere Schachtel. Der Parameter passt zu diesem Endpoint einfach nicht.

Beispiel-Request

curl "https://back.sitecog.com/content/v1/blocks/phone?section=header&lang=en" \
  -H "x-crm-key: pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"

Beispiel-Responses

Die Hülle ist immer gleich; nur content ändert sich je nach Block-Typ.

Ein Text-Block

200 OK — GET /v1/blocks/phone?section=headerjson
{
  "id": 88,
  "marker": "phone",
  "name": "Phone in header",
  "type": "text",
  "multilang": true,
  "updatedAt": "2026-09-12T07:45:10.000Z",
  "content": { "en": "+66 2 123 4567", "de": "+66 2 123 4567" }
}

Text ist eine Sprach-Map: ein Key pro Sprache, in CRM-Reihenfolge. Eine Sprache ganz ohne gespeicherten Wert fehlt in der Map einfach; eine, die existiert, aber leer ist, kommt als "". Einen serverseitigen Fallback gibt es nicht, also such dir selbst eine Ersatzsprache aus — siehe den Helper unter Tipps.

Ein Object-Block

200 OK — GET /v1/blocks/promo_banner?section=promojson
{
  "id": 131,
  "marker": "promo_banner",
  "name": "Promo banner",
  "type": "object",
  "multilang": false,
  "updatedAt": "2026-09-28T10:05:00.000Z",
  "content": {
    "title": { "en": "Autumn sale: 20% off", "de": "Herbst-Sale: 20 % Rabatt" },
    "image": { "file": "https://cdn.example.com/storage/your-site/autumn.jpg" },
    "link": {
      "url": "https://example.com/sale",
      "target": "_self",
      "title": { "en": "Shop now", "de": "Jetzt kaufen" }
    },
    "ends": "2026-10-15",
    "active": true
  }
}

Ein Objekt ist eine Menge von Feldern mit dem Feld-Marker als Key, und jedes Feld folgt denselben Regeln wie ein eigenständiger Block: Textfelder sind Sprach-Maps, ein Link ist { url, target, title }, ein Bild ist { file } (oder eine Map pro Sprache), Zahlen, Datumswerte und Booleans kommen so, wie sie gespeichert sind. Geliefert werden nur Werte — die Felddefinitionen bleiben im CRM.

Und der Preis

200 OK — GET /v1/blocks/price?section=pricingjson
{
  "id": 140,
  "marker": "price",
  "name": "Base plan price",
  "type": "number",
  "multilang": false,
  "updatedAt": "2026-09-26T16:20:00.000Z",
  "content": 149
}

Zahlen, Farben, Datumswerte, Datumsbereiche und Booleans kommen als roher gespeicherter Wert zurück (oder null, wenn leer) — ohne Sprach-Map, also lässt ?lang sie in Ruhe. Alle Formen stehen auf der Seite Block-Typen.

Felder der Response

idnumber
Interne Block-ID. Stabil, aber nimm im Code lieber Marker — IDs unterscheiden sich zwischen Umgebungen.
markerstring
Der Block-Marker, derselbe, den du in die URL geschrieben hast.
namestring
Menschenlesbarer Name aus dem CRM („Phone in header“). Gedacht für die Redaktion — gib ihn nicht auf der Seite aus.
typestring
Einer von text, html, image, video, link, number, color, date, date_range, boolean, object, array. Prüf ihn, bevor du content liest, wenn dieselbe Komponente verschiedene Blöcke rendert.
multilangboolean
Für Bilder und Videos: true, wenn jede Sprache ihre eigene Datei hat — content ist dann eine Map von URLs pro Sprache statt eines einzelnen file.
updatedAtstring (ISO 8601)
Wann der Block zuletzt bearbeitet wurde. Praktisch für Hinweise wie „Preise aktualisiert am…“ und für Cache-Keys.
contentdepends on type | null
Der Wert selbst: eine Sprach-Map für text und html, { file } für ein einzelnes Bild oder Video, { url, target, title } für einen Link, ein Objekt aus Feldern für object, ein Array solcher Objekte für array, ein roher Wert (oder null) für Zahlen, Farben, Datumswerte und Booleans. Details: Block-Typen.

Marker sind pro Section eindeutig — nutz ?section

Block-Marker müssen nur innerhalb ihrer Section eindeutig sein. Genau deshalb kann die Redaktion vernünftige Namen wiederverwenden: Die Section hero hat einen title, die Section faq hat einen title, und niemand muss sich title_2_final ausdenken.

Die Kehrseite: /v1/blocks/title allein ist mehrdeutig. Ohne ?section liefert die API den ersten Treffer — den ältesten Block mit diesem Marker. Das kann der sein, den du meinst, oder auch nicht, und es kann sich ändern, wenn jemand einen Block neu anlegt. Gib die Section mit, und die Antwort ist exakt:

# Mehrdeutig: welcher "title" auch immer zuerst angelegt wurde
curl "https://back.sitecog.com/content/v1/blocks/title" -H "x-crm-key: pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"

# Exakt: der Titel der FAQ-Section
curl "https://back.sitecog.com/content/v1/blocks/title?section=faq" -H "x-crm-key: pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"

Blöcke nicht einzeln abrufen

Nicht so: ein Wasserfall winziger Requestsjs
const title = await getBlock('title', 'promo');
const text = await getBlock('text', 'promo');
const image = await getBlock('image', 'promo');
Sondern so: ein Request, dieselben Datenjs
const promo = await fetch('https://back.sitecog.com/content/v1/sections/promo?lang=en', {
  headers: { 'x-crm-key': 'pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40' },
}).then((r) => r.json());
const { title, text, image } = promo.content;

Der Einzelblock-Endpoint glänzt, wenn du wirklich einen Wert an einer Stelle brauchst, die sonst nichts mit dieser Seite zu tun hat — die Telefonnummer im globalen Header, ein Banner im Layout, ein Preis im Checkout-Widget.

Fehler

StatusBodyWas passiert ist
400{"message":"invalid_marker"}Der Marker enthält Zeichen außerhalb von A–Z a–z 0–9 _ oder hat die falsche Länge.
400{"message":"invalid_lang", …}Ein Code in lang ist falsch formatiert.
400{"message":"unknown_lang", …}Eine Sprache in lang ist auf der Website nicht aktiv. Der Body listet die verfügbaren auf.
401{"message":"invalid_key"}Key fehlt, ist falsch formatiert oder widerrufen.
404{"message":"block_not_found"}Kein Block mit diesem Marker — oder keiner in der Section, die du in ?section angegeben hast.
429{"message":"rate_limit_exceeded"}Zu viele Requests in dieser Minute. Siehe Rate Limits.

Die vollständige Liste samt Lösungen findest du auf der Seite Fehler.

Tipps aus der Praxis

// gewünschte Sprache → Standardsprache → erster nicht leerer Wert
export function t(map: Record<string, string> | undefined, lang: string, fallback = 'en') {
  if (!map) return '';
  return map[lang] || map[fallback] || Object.values(map).find(Boolean) || '';
}

t(phone.content, 'de'); // "+66 2 123 4567"