Diil Docs
  1. Документація
  2. З чого почати

Доступ за ключем сайту

Оновлено:

Кожен запит до Content API несе ключ сайту. Він підказує нам, з якого сайту ви читаєте, — і це, власне, все, що він робить. Жодних танців з OAuth, жодного оновлення токенів, жодного підписування запитів опівночі. Один рядок в одному заголовку — і ви всередині.

Що таке ключ сайту

Ключ сайту виглядає так:

pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40
  • Префікс pk_, за яким рівно 32 малі шістнадцяткові символи: ^pk_[a-f0-9]{32}$.
  • Він належить одному сайту. Лише ключ визначає, чий вміст ви отримаєте, — параметра на кшталт «site id» в API немає ніде.
  • Він лише для читання і бачить тільки опублікований вміст.
  • У сайту може бути кілька ключів одночасно, тож ротація минає безболісно (докладніше — нижче).

pk_ — це кивок у бік «publishable keys», які ви, можливо, знаєте з платіжних сервісів: ключ, створений для того, щоб жити в публічному коді. Чому це нормально, розповімо за хвилину.

Де взяти ключ

  1. Відкрийте свій сайт у CRM

    Увійдіть у Diil і оберіть сайт, вміст якого хочете читати.
  2. Перейдіть у Налаштування → Ключі Content API

    Тут живуть усі ключі сайту.
  3. Створіть ключ

    Ви отримаєте новенький рядок pk_…. Скопіюйте його.
  4. Покладіть його у змінну оточення

    Не просто в код — ви з майбутнього, що ротуватимете ключі, будете вдячні. Шаблони для популярних фреймворків — нижче.

Як передати ключ

Покладіть ключ у заголовок запиту x-crm-key. Це стандартний спосіб, і він працює однаково з серверів і з браузерів — CORS дозволяє цей заголовок із будь-якого джерела.

curl "https://back.sitecog.com/content/v1/pages/home?lang=en" \
  -H "x-crm-key: pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"

Запасний варіант ?key=

Якщо задати заголовок ну ніяк не виходить, передайте ключ як query-параметр:

curl "https://back.sitecog.com/content/v1/pages/home?lang=en&key=pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"

Коли це нормально?

  • Швидкі перевірки — вставити URL в адресний рядок браузера й подивитися, що повертає endpoint.
  • Інструменти, що приймають лише URL — no-code інтеграція, імпортер фідів, плагін генератора статичних сайтів без налаштування заголовків.

В усіх інших випадках краще заголовок. URL мають звичку осідати в логах сервера, історії браузера й аналітиці, і хоча ключ не секрет, розкидати його всюди немає сенсу. До того ж так URL коротші, а код охайніший.

Чому ключ безпечно тримати в браузері

Коротко: бо він не вміє нічого такого, чого ваші відвідувачі не можуть зробити, просто відкривши ваш сайт. Ключ сайту публічний за задумом. Ось що він може, а що ні:

Ключ сайту…
читає опубліковані сторінки, секції, блоки й дописи блогу свого сайтутак
змінює, створює чи видаляє щосьні — API лише для читання
бачить чернетки чи неопубліковані дописи блогуні — лише опублікований вміст
читає вміст інших ваших сайтівні — один ключ, один сайт

Та сама ідея, що й у publishable key платіжного сервісу: він визначає, чиї дані показувати, але не дає над ними влади. Усе, що він може прочитати, і так опиниться на вашому публічному сайті.

Єдине, що скопійований ключ може, — витрачати вашу квоту запитів: у кожного ключа власний ліміт 600 запитів на хвилину (див. Ліміти запитів). Якщо хтось почне це робити, проведіть ротацію ключа — це займе кілька хвилин.

Ключ у змінних оточення

Ключ публічний — навіщо тоді змінні оточення? Бо ключі змінюються, і ротація ключа має бути зміною конфігурації, а не коду. До того ж більшість фреймворків вимагають префікс, перш ніж пустити змінну в код для браузера:

.envbash
# Next.js — Server Components, Route Handlers (у браузер не потрапляє)
CRM_KEY=pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40

# Next.js — Client Components (вбудовується в бандл під час збирання)
NEXT_PUBLIC_CRM_KEY=pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40

# Vite (React, Vue, Svelte…) — вбудовується під час збирання
VITE_CRM_KEY=pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40

# Nuxt — перевизначає runtimeConfig.public.crmKey
NUXT_PUBLIC_CRM_KEY=pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40
// app/page.tsx — Server Component
export default async function Home() {
  const res = await fetch('https://back.sitecog.com/content/v1/pages/home?lang=en', {
    headers: { 'x-crm-key': process.env.CRM_KEY! },
    next: { revalidate: 60 },
  });
  const page = await res.json();

  return <h1>{page.content.hero.content.hero_title.content.en}</h1>;
}

Відкликання та ротація ключів

Будь-який ключ можна відкликати в CRM у тому ж списку Налаштування → Ключі Content API. Відкликаний ключ перестає працювати: кожен запит із ним отримує 401 invalid_key. Щоб замінити ключі без жодного невдалого запиту, використовуйте їх деякий час паралельно:

  1. Створіть новий ключ

    Старий поки не чіпайте — обидва працюють пліч-о-пліч.
  2. Задеплойте з новим ключем

    Оновіть змінну оточення всюди, де використовувався старий ключ, перезберіть, якщо ваш фреймворк його вбудовує, і задеплойте.
  3. Перевірте, що сайт і далі отримує вміст

    Відкрийте кілька сторінок, загляньте в логи. Жодних 401? Чудово.
  4. Відкличте старий ключ

    Тепер можна сміливо висмикувати штепсель.

Помилки ключа

СтатусТілоЩо сталося
401{"message":"invalid_key"}Ключа немає, він некоректний (не pk_ + 32 hex) або відкликаний.
429{"message":"rate_limit_exceeded"}Забагато запитів — або забагато неправильних ключів з вашої IP за цю хвилину (див. нижче).

Блокування за неправильні ключі

Щоб підбирати ключі було безглуздо, ми рахуємо запити з неправильними ключами для кожної IP. Понад 20 запитів із неправильним ключем за хвилину з однієї IP — і ця IP отримує 429 до кінця хвилини — навіть із правильним ключем. Заголовків Retry-After немає; вікно скидається на початку наступної хвилини.

Класичний спосіб випадково на це натрапити: ви відкликали старий ключ, а якийсь сервер чи забутий cron досі ним користується. Серверний рендеринг строчить 401, і за хвилину заблоковано весь сервер — разом із новим ключем. Тож:

Не повторюйте запит після 401js
const res = await fetch(url, { headers: { 'x-crm-key': process.env.CRM_KEY } });

if (res.status === 401) {
  // Неправильний чи відкликаний ключ сам не виправиться. Повтори лише
  // спалюють ліміт на неправильні ключі й призводять до блокування цієї IP.
  throw new Error('Content API: неправильний ключ сайту, перевірте CRM_KEY');
}

if (res.status === 429) {
  // Зачекайте до наступної хвилини (близько 60 с плюс невеликий випадковий зсув).
}

Усі інші коди — на сторінці Помилки.

Питання про безпеку