Skip to content

Интеграция API

Этот раздел нужен, если вы интегрируете Verstka без Python/PHP SDK: на другом языке, в своем framework или с полностью кастомной backend-логикой.

SDK делает тот же flow автоматически: подписывает запросы, проверяет callback, скачивает ZIP, сохраняет файлы через adapter и формирует ответ Verstka. Если у вас Python или PHP backend, сначала посмотрите:

Общий flow без SDK

Если писать интеграцию напрямую через API, сайт должен пройти такой путь:

  1. В админке пользователь нажимает «Редактировать в Verstka».
  2. Backend сайта вызывает POST /integration/session/open.
  3. Verstka возвращает URL редактора.
  4. Сайт открывает этот URL в новой вкладке.
  5. После Save Verstka отправляет callback article_saved на сайт.
  6. Сайт проверяет подпись callback.
  7. Сайт скачивает ZIP с публикацией по content_url.
  8. Сайт сохраняет медиа, HTML и JSON у себя.
  9. Сайт возвращает Verstka обновленный vms_json с публичными URL файлов.

Шрифты сайта обрабатываются похожим образом, но отдельным событием site_fonts_updated.

Базовые понятия

Публичные endpoints находятся под /integration. Базовый URL production API:

text
https://api.r2.verstka.org/integration
  • api_key - публичный ключ проекта Verstka. Он идентифицирует сайт и окружение.
  • api_secret - секрет для HMAC-подписи запросов.
  • material_id - ID статьи, поста или материала в вашей CMS.
  • callback_url - публичный URL сайта, куда Verstka отправит callback после Save.
  • content_url - URL ZIP-архива, который приходит в callback.
  • vms_json - состояние редактора для повторного открытия публикации.
  • metadata - дополнительные JSON-данные сайта, которые Verstka вернет в callback.

Каждому сайту выдаются api_key и api_secret. Ключ может быть dev или prod; backend сверяет ключ с доменами, разрешенными для проекта.

Подпись запросов

Критичные запросы подписываются HMAC-SHA256:

text
signature = hex(HMAC_SHA256(api_secret, material_id + ":" + url))

Подпись передается в заголовке:

http
X-Verstka-Signature: <signature>

Какой URL использовать в подписи:

  • для POST /integration/session/open - callback_url;
  • для callback и скачивания ZIP - content_url.

1. Открыть редактор

Endpoint:

http
POST /integration/session/open

Тело запроса:

json
{
  "api_key": "verstka-api-key",
  "callback_url": "https://site.example/verstka/callback",
  "material_id": "42",
  "vms_json": {},
  "metadata": {
    "editor_user_id": "123",
    "section_id": "news"
  }
}

Запрос нужно отправить с заголовком:

http
X-Verstka-Signature: <signature>

Для этого endpoint подпись считается по material_id:callback_url.

Обязательные поля:

ПолеНазначение
api_keyИдентифицирует сайт и окружение.
callback_urlURL сайта, куда Verstka отправит callback.
material_idID материала в CMS сайта.

Опциональные поля:

ПолеНазначение
vms_jsonСохраненное состояние редактора. Передавайте его при повторном редактировании.
metadataJSON-объект с данными сайта. Verstka вернет его в callback.

Если публикация открывается впервые, vms_json можно не передавать. Если публикация уже сохранялась в Verstka, передайте последний сохраненный vms_json, иначе редактор не откроет актуальную версию.

Ответ:

json
{
  "session_id": "uuid",
  "fingerprint": "uuid",
  "url": "https://stage.verstka.org/edit/uuid",
  "resizeMode": "original"
}

url нужно открыть пользователю в новой вкладке.

Если сессия для site + material_id уже есть, backend вернет существующую сессию. Это позволяет открывать одну и ту же публикацию повторно и пользоваться откатом к предыдущим версиям внутри редактора в течение 2 недель с последнего обращения к публикации.

2. Принять callback article_saved

Когда пользователь нажимает Save, Verstka отправляет POST на callback_url, который сайт передал при открытии редактора.

Пример payload:

json
{
  "event": "article_saved",
  "material_id": "42",
  "content_url": "https://api.r2.verstka.org/integration/download/media/...",
  "metadata": {
    "editor_user_id": "123",
    "section_id": "news",
    "version_id": "uuid",
    "version_cdate": "2026-06-23T12:00:00+03:00",
    "user_email": "editor@example.com",
    "user_ip": "203.0.113.10"
  },
  "debug": true
}

Что должен сделать сайт:

  1. Прочитать заголовок X-Verstka-Signature.
  2. Проверить подпись по формуле hex(HMAC_SHA256(api_secret, material_id + ":" + content_url)).
  3. Скачать ZIP по content_url.
  4. Сохранить медиа, HTML и JSON у себя.
  5. Вернуть ответ Verstka.

Успешный ответ:

json
{
  "rc": 1,
  "rm": "Saved successfully",
  "data": {
    "vms_json": {}
  }
}

data.vms_json должен содержать обновленное состояние редактора с публичными URL файлов в assets[*].clientUrl. Verstka сохранит эти URL, чтобы при следующем открытии публикация уже работала с файлами сайта.

Если сайт отклоняет сохранение, верните rc: 0 и сообщение в rm.

3. Скачать ZIP публикации

Endpoint:

http
GET /integration/download/media/{fingerprint}/{version_id}

Этот URL приходит в callback article_saved как content_url.

К запросу нужно добавить query-параметры:

text
?api_key=<api_key>&material_id=<material_id>

И передать заголовок:

http
X-Verstka-Signature: <signature>

Подпись должна соответствовать material_id:content_url.

ZIP содержит:

ФайлНазначение
vms_html.htmlHTML, который сайт выводит на публичной странице.
vms_json.jsonСостояние редактора для следующего открытия.
vms_media/*Медиафайлы публикации.
metadata_json.jsonMetadata сессии и последней версии.

После распаковки сайт должен:

  • сохранить файлы из vms_media/* в публичное хранилище;
  • получить публичный URL для каждого файла;
  • заменить временные URL в vms_html;
  • записать публичные URL в vms_json.assets[*].clientUrl;
  • сохранить vms_html и обновленный vms_json в CMS;
  • вернуть обновленный vms_json в ответе callback.

Пример:

text
Файл в ZIP:
vms_media/hero-image.webp

Временная ссылка в HTML и JSON:
dummy-hero-image.webp

Куда сайт сохранил файл:
https://cdn.site.example/articles/42/hero-image.webp

После сохранения файла сайт заменяет временную ссылку в vms_html:

html
<!-- было -->
<img src="dummy-hero-image.webp" />

<!-- стало -->
<img src="https://cdn.site.example/articles/42/hero-image.webp" />

И записывает тот же публичный URL в vms_json:

json
{
  "assets": {
    "hero-image.webp": {
      "clientUrl": "https://cdn.site.example/articles/42/hero-image.webp"
    }
  }
}

Именно этот обновленный vms_json нужно вернуть в data.vms_json.

4. Обработать callback site_fonts_updated

Шрифты сайта обрабатываются отдельно от конкретной публикации. Если в Verstka обновился набор шрифтов, сайт получит callback site_fonts_updated.

Пример payload:

json
{
  "event": "site_fonts_updated",
  "material_id": "42",
  "content_url": "https://api.r2.verstka.org/integration/download/fonts/...",
  "metadata": {
    "editor_user_id": "123",
    "version_id": "uuid",
    "version_cdate": "2026-06-23T12:00:00+03:00",
    "user_email": "editor@example.com",
    "user_ip": "203.0.113.10"
  },
  "fonts": {}
}

Сайт проверяет подпись так же, как для article_saved, скачивает ZIP шрифтов и сохраняет файлы у себя.

Успешный ответ:

json
{
  "rc": 1,
  "rm": "Fonts saved successfully",
  "data": {
    "fonts": {}
  }
}

data.fonts может вернуть дерево шрифтов с публичными clientUrl для CSS и файлов. Verstka принимает только URL на разрешенных доменах сайта.

5. Скачать ZIP шрифтов

Endpoint:

http
GET /integration/download/fonts/{fingerprint}/{snapshot_id}

Этот URL приходит в callback site_fonts_updated как content_url. Авторизация такая же, как у media ZIP: api_key, material_id и X-Verstka-Signature.

ZIP содержит:

ФайлНазначение
vms_fonts/*Файлы шрифтов.
vms_fonts.cssCSS с @font-face.
vms_fonts.jsonДерево шрифтов с файлами, вариантами и URL.

После сохранения CSS желательно записать его URL в настройки сайта и подключать на публичных страницах, где выводятся публикации Verstka.

Metadata

metadata - это JSON-объект, который сайт может передать при POST /integration/session/open. Verstka сохраняет его в сессии, возвращает в callbacks и кладет в metadata_json.json внутри ZIP.

metadata не имеет жесткой схемы. Сайт может передавать любые JSON-ключи, которые нужны для маршрутизации, прав доступа, аудита, хранения файлов или собственной бизнес-логики. Значения должны быть JSON-сериализуемыми: строки, числа, boolean, массивы и вложенные объекты.

Примеры кастомных ключей:

КлючНазначение
editor_user_idID пользователя в CMS.
section_idРаздел, рубрика или категория публикации.
timeLimitedAuthTokenОграниченный по времени токен для дополнительной проверки прав.
customContainersКонфигурация Custom Containers, если сайт использует свои контейнеры или виджеты.

Служебные ключи:

КлючКто задаетЧто важно
versionSDK / WordPress pluginМетка клиента интеграции: Python SDK передает python_<sdk-version>, PHP SDK - php_<sdk-version>, WordPress plugin - wp_<plugin-version>.
version_idVerstka backendID версии, созданной при последнем сохранении публикации.
version_cdateVerstka backendДата создания последней версии.
user_emailVerstka backend / WordPress pluginEmail редактора в callback. Verstka обновляет значение при сохранении.
user_ipVerstka backend / WordPress pluginIP редактора в callback. Verstka обновляет значение при сохранении.
webhook_auth_user, webhook_auth_passwordSDK / WordPress plugin / сайтСлужебные ключи авторизации исходящего callback: Basic Auth или Bearer token. Не используйте эти имена для бизнес-данных сайта.

Не используйте metadata как произвольное хранилище секретов, токенов доступа, приватных ключей и персональных данных, которые не нужны callback-обработчику. Эти данные сохраняются в сессии и попадают в metadata_json.json внутри ZIP.

Callback authorization

Если callback URL сайта защищен Basic Auth или Bearer token, передайте служебные ключи в metadata при POST /integration/session/open.

Verstka сохранит их в сессии и добавит заголовок Authorization к исходящим callback article_saved и site_fonts_updated.

Условие в metadataЗаголовок
webhook_auth_user и webhook_auth_password - непустые строкиHTTP Basic Auth (Authorization: Basic ...)
Только webhook_auth_user - непустая строкаAuthorization: Bearer <token>

Если значение webhook_auth_user уже начинается с Bearer , префикс не дублируется. Backend не генерирует эти ключи сам: их задает сайт, SDK или WordPress plugin при открытии сессии.

Basic Auth:

json
{
  "metadata": {
    "webhook_auth_user": "callback-user",
    "webhook_auth_password": "callback-password"
  }
}

Bearer token:

json
{
  "metadata": {
    "webhook_auth_user": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }
}

Справочник эндпоинтов

EndpointМетодНазначение
/integration/session/openPOSTОткрывает или переиспользует сессию редактирования для пары site + material_id.
/integration/download/media/{fingerprint}/{version_id}GETОтдает ZIP сохраненной версии публикации для обработки сайтом.
/integration/download/fonts/{fingerprint}/{snapshot_id}GETОтдает ZIP шрифтов сайта после изменения набора шрифтов в Verstka.