Іноді вам не потрібна ні сторінка, ні навіть секція — потрібна рівно одна річ. Телефон у шапці. Промобанер над магазином. Ціна, яку маркетинг змінює щоп’ятниці. Цей endpoint віддає один блок за його маркером — і більше нічого.
Типові кандидати:
- Телефон чи email у шапці — блок
text, що живе на службовій сторінціcommonі показується всюди. - Промобанер — блок
objectіз заголовком, зображенням і посиланням, який ви вставляєте в макет, що вже рендериться з коду. - Ціна — блок
number, який ваш checkout чи лендинг читає, не завантажуючи всю сторінку з тарифами.
Отримати один блок
/v1/blocks/:markerhttps://back.sitecog.com/content/v1/blocks/:marker
content. Та сама форма, що й у блоку всередині відповіді для сторінки чи секції, — лише без обгортки.Параметри
markerpathstringобовʼязковоphone або promo_banner. Латинські літери, цифри та підкреслення, 2–40 символів, з урахуванням регістру.sectionquerystringнеобовʼязковоЗа замовчуванням: будь-яка секція?section=header. Маркери блоків унікальні лише в межах секції, тож так ви точно вказуєте, який саме title маєте на увазі. Без нього перемагає перший збіг — найстаріший блок із таким маркером. Див. нижче.langquerystringнеобовʼязковоЗа замовчуванням: усі активні мови?lang=en, ?lang=en,de або ?lang=en&lang=de. Кожен код має бути активною мовою сайту, інакше отримаєте 400 unknown_lang. Не впливає на значення без перекладів, як-от числа чи кольори.x-crm-keyheaderstringобовʼязково?key=. Див. Ключ сайту.Параметра ?empty тут немає: блок без свого content був би порожньою коробкою. До цього endpoint параметр просто не застосовується.
Приклад запиту
curl "https://back.sitecog.com/content/v1/blocks/phone?section=header&lang=en" \
-H "x-crm-key: pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"const res = await fetch(
'https://back.sitecog.com/content/v1/blocks/phone?section=header&lang=en',
{ headers: { 'x-crm-key': 'pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40' } },
);
if (!res.ok) throw new Error(`Content API: ${res.status}`);
const block = await res.json();
console.log(block.content.en); // "+66 2 123 4567"// components/HeaderPhone.tsx — Server Component
export async function HeaderPhone({ lang }: { lang: string }) {
const res = await fetch(
`https://back.sitecog.com/content/v1/blocks/phone?section=header&lang=${lang}`,
{
headers: { 'x-crm-key': process.env.CRM_KEY! },
next: { revalidate: 60 },
},
);
if (!res.ok) return null; // шапка переживе й без телефону
const phone = await res.json();
const value: string = phone.content[lang] ?? '';
if (!value) return null;
return <a href={`tel:${value.replace(/\s+/g, '')}`}>{value}</a>;
}Приклади відповідей
Обгортка завжди однакова; залежно від типу блоку змінюється лише content.
Текстовий блок
{
"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" }
}Текст — це карта мов: по одному ключу на мову, у порядку CRM. Мови, для якої значення взагалі не зберігали, у карті просто немає; та, що є, але порожня, приходить як "". Запасної мови на сервері немає, тож обирайте резервну мову самі — див. хелпер у розділі Поради.
Блок-об’єкт
{
"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
}
}Об’єкт — це набір полів із ключами-маркерами полів, і кожне поле підпорядковується тим самим правилам, що й окремий блок: текстові поля — карти мов, посилання — { url, target, title }, зображення — { file } (або карта за мовами), числа, дати й булеві значення приходять як збережені. Повертаються лише значення — опис полів лишається в CRM.
І ціна
{
"id": 140,
"marker": "price",
"name": "Base plan price",
"type": "number",
"multilang": false,
"updatedAt": "2026-09-26T16:20:00.000Z",
"content": 149
}Числа, кольори, дати, діапазони дат і булеві значення повертаються як сире збережене значення (або null, якщо порожньо) — без карти мов, тож ?lang їх не зачіпає. Усі форми перелічено на сторінці Типи блоків.
Поля відповіді
idnumbermarkerstringnamestringtypestringtext, html, image, video, link, number, color, date, date_range, boolean, object, array. Перевіряйте його, перш ніж читати content, якщо той самий компонент рендерить різні блоки.multilangbooleantrue, якщо в кожної мови свій файл, і тоді content — це карта URL за мовами замість одного file.updatedAtstring (ISO 8601)contentзалежить від type | nulltext і html, { file } для одного зображення чи відео, { url, target, title } для посилання, об’єкт полів для object, масив таких об’єктів для array, сире значення (або null) для чисел, кольорів, дат і булевих значень. Подробиці: Типи блоків.Маркери унікальні в межах секції — використовуйте ?section
Маркери блоків мають бути унікальними лише всередині своєї секції. Саме тому редактори можуть повторно використовувати зрозумілі назви: у секції hero є title, у секції faq є title, і нікому не доводиться вигадувати title_2_final.
Зворотний бік: /v1/blocks/title сам по собі неоднозначний. Без ?section API повертає перший збіг — найстаріший блок із таким маркером, — який може бути тим, що ви мали на увазі, а може й ні, і може змінитися, якщо хтось перестворить блок. Додайте секцію — і відповідь буде точною:
# Неоднозначно: той "title", який створили першим
curl "https://back.sitecog.com/content/v1/blocks/title" -H "x-crm-key: pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"
# Точно: title секції FAQ
curl "https://back.sitecog.com/content/v1/blocks/title?section=faq" -H "x-crm-key: pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"Не завантажуйте блоки по одному
const title = await getBlock('title', 'promo');
const text = await getBlock('text', 'promo');
const image = await getBlock('image', 'promo');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;Endpoint для одного блоку сяє, коли вам справді потрібне одне значення в місці, яке більше ніяк не пов’язане з тією сторінкою, — телефон у глобальній шапці, банер у макеті, ціна у віджеті оформлення замовлення.
Помилки
| Статус | Тіло | Що сталося |
|---|---|---|
| 400 | {"message":"invalid_marker"} | У маркері є символи поза A–Z a–z 0–9 _ або неправильна довжина. |
| 400 | {"message":"invalid_lang", …} | Код у lang має неправильний формат. |
| 400 | {"message":"unknown_lang", …} | Мова з lang не активна на сайті. У тілі — список доступних. |
| 401 | {"message":"invalid_key"} | Ключа немає, він некоректний або відкликаний. |
| 404 | {"message":"block_not_found"} | Блоку з таким маркером немає — або немає в секції, яку ви вказали в ?section. |
| 429 | {"message":"rate_limit_exceeded"} | Забагато запитів за цю хвилину. Див. Ліміти запитів. |
Повний список із рішеннями — на сторінці Помилки.
Поради з передової
// запитана мова → мова за замовчуванням → перше непорожнє значення
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"