Diil Docs
  1. Documentación
  2. Referencia de la API

GET /v1/blocks/:marker — un bloque

Actualizado:

A veces no necesitas una página, ni siquiera una sección: necesitas exactamente una cosa. El teléfono de la cabecera. El banner de promo encima de la tienda. El precio que marketing cambia cada viernes. Este endpoint te da un único bloque por su marcador, y nada más.

Candidatos típicos:

  • Un teléfono o un email en la cabecera: un bloque text que vive en la página de servicio common y aparece en todas partes.
  • Un banner de promo: un bloque object con título, imagen y enlace, que encaja en un layout que ya renderizas desde el código.
  • Un precio: un bloque number que lee tu checkout o tu landing sin cargar toda la página de precios.

Obtener un bloque

GET/v1/blocks/:marker

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

Un bloque con su valor en content. La misma forma que un bloque dentro de la respuesta de una página o sección, solo que sin el envoltorio.

Parámetros

markerpathstringobligatorio
El marcador del bloque en el CRM, p. ej. phone o promo_banner. Letras latinas, dígitos y guiones bajos, de 2 a 40 caracteres, distingue mayúsculas.
sectionquerystringopcionalPor defecto: cualquier sección
Marcador de la sección a la que pertenece el bloque, p. ej. ?section=header. Los marcadores de bloque solo son únicos dentro de una sección, así que así dices exactamente a qué title te refieres. Sin él gana la primera coincidencia: el bloque más antiguo con ese marcador. Mira más abajo.
langquerystringopcionalPor defecto: todos los idiomas activos
Limita las traducciones a estos idiomas: ?lang=en, ?lang=en,de o ?lang=en&lang=de. Cada código tiene que ser un idioma activo del sitio; si no, recibes 400 unknown_lang. No afecta a los valores sin traducciones, como números o colores.
x-crm-keyheaderstringobligatorio
Tu clave de sitio. También se puede pasar como ?key= si las cabeceras no son una opción. Mira Claves de sitio.

Aquí no hay ?empty: un bloque sin su content sería una caja sin nada dentro. El parámetro sencillamente no aplica a este endpoint.

Ejemplo de petición

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

Ejemplos de respuesta

El envoltorio es siempre el mismo; solo content cambia según el tipo de bloque.

Un bloque de texto

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" }
}

El texto es un mapa de idiomas: una clave por idioma, en el orden del CRM. Un idioma sin ningún valor guardado directamente no aparece en el mapa; uno que existe pero está en blanco llega como "". No hay respaldo en el servidor, así que elige tú un idioma de reserva: mira el helper en Consejos.

Un bloque de tipo objeto

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

Un objeto es un conjunto de campos con el marcador del campo como clave, y cada campo sigue las mismas reglas que un bloque suelto: los campos de texto son mapas de idiomas, un enlace es { url, target, title }, una imagen es { file } (o un mapa por idioma), y los números, fechas y booleanos llegan tal como se guardaron. Solo se devuelven los valores; las definiciones de los campos se quedan en el CRM.

Y el precio

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
}

Los números, colores, fechas, rangos de fechas y booleanos llegan como el valor en bruto guardado (o null si están vacíos): sin mapa de idiomas, así que ?lang no los toca. Todas las formas están en la página Tipos de bloque.

Campos de la respuesta

idnumber
Id interno del bloque. Es estable, pero en tu código mejor usa marcadores: los ids cambian de un entorno a otro.
markerstring
El marcador del bloque, el mismo que pones en la URL.
namestring
Nombre legible del CRM («Phone in header»). Es para los editores: no lo pintes en la página.
typestring
Uno de text, html, image, video, link, number, color, date, date_range, boolean, object, array. Compruébalo antes de leer content si el mismo componente renderiza bloques distintos.
multilangboolean
Para imágenes y vídeos: true si cada idioma tiene su propio archivo, y entonces content es un mapa de URLs por idioma en lugar de un único file.
updatedAtstring (ISO 8601)
Cuándo se editó el bloque por última vez. Útil para avisos tipo «precios actualizados el…» y para claves de caché.
contentdepends on type | null
El valor en sí: un mapa de idiomas para text y html, { file } para una sola imagen o vídeo, { url, target, title } para un enlace, un objeto de campos para object, un array de esos objetos para array, un valor en bruto (o null) para números, colores, fechas y booleanos. Detalles: Tipos de bloque.

Los marcadores son únicos por sección: usa ?section

Los marcadores de bloque solo tienen que ser únicos dentro de su sección. Eso es lo que permite a los editores reutilizar nombres razonables: la sección hero tiene un title, la sección faq tiene un title, y nadie tiene que inventarse title_2_final.

La otra cara: /v1/blocks/title a secas es ambiguo. Sin ?section la API devuelve la primera coincidencia, el bloque más antiguo con ese marcador, que puede ser o no el que querías, y puede cambiar si alguien vuelve a crear un bloque. Añade la sección y la respuesta es exacta:

# Ambiguo: el "title" que se creara primero
curl "https://back.sitecog.com/content/v1/blocks/title" -H "x-crm-key: pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"

# Exacto: el title de la sección FAQ
curl "https://back.sitecog.com/content/v1/blocks/title?section=faq" -H "x-crm-key: pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"

No pidas los bloques de uno en uno

Mal: una cascada de peticiones diminutasjs
const title = await getBlock('title', 'promo');
const text = await getBlock('text', 'promo');
const image = await getBlock('image', 'promo');
Bien: una petición, los mismos datosjs
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;

El endpoint de un solo bloque brilla cuando de verdad necesitas un valor en un sitio que por lo demás no tiene nada que ver con esa página: el teléfono en una cabecera global, un banner en un layout, un precio en un widget de checkout.

Errores

EstadoCuerpoQué ha pasado
400{"message":"invalid_marker"}El marcador tiene caracteres fuera de A–Z a–z 0–9 _ o una longitud incorrecta.
400{"message":"invalid_lang", …}Un código en lang está mal formado.
400{"message":"unknown_lang", …}Un idioma en lang no está activo en el sitio. El cuerpo lista los disponibles.
401{"message":"invalid_key"}Clave ausente, mal formada o revocada.
404{"message":"block_not_found"}No hay ningún bloque con este marcador, o no lo hay en la sección que indicaste en ?section.
429{"message":"rate_limit_exceeded"}Demasiadas peticiones en este minuto. Mira Límites.

La lista completa, con soluciones, está en la página Errores.

Consejos desde las trincheras

// idioma pedido → idioma por defecto → primer valor no vacío
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"