Интеграция API
Этот раздел нужен, если вы интегрируете Verstka без Python/PHP SDK: на другом языке, в своем framework или с полностью кастомной backend-логикой.
SDK делает тот же flow автоматически: подписывает запросы, проверяет callback, скачивает ZIP, сохраняет файлы через adapter и формирует ответ Verstka. Если у вас Python или PHP backend, сначала посмотрите:
Общий flow без SDK
Если писать интеграцию напрямую через API, сайт должен пройти такой путь:
- В админке пользователь нажимает «Редактировать в Verstka».
- Backend сайта вызывает
POST /integration/session/open. - Verstka возвращает URL редактора.
- Сайт открывает этот URL в новой вкладке.
- После Save Verstka отправляет callback
article_savedна сайт. - Сайт проверяет подпись callback.
- Сайт скачивает ZIP с публикацией по
content_url. - Сайт сохраняет медиа, HTML и JSON у себя.
- Сайт возвращает Verstka обновленный
vms_jsonс публичными URL файлов.
Шрифты сайта обрабатываются похожим образом, но отдельным событием site_fonts_updated.
Базовые понятия
Публичные endpoints находятся под /integration. Базовый URL production API:
https://api.r2.verstka.org/integrationapi_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:
signature = hex(HMAC_SHA256(api_secret, material_id + ":" + url))Подпись передается в заголовке:
X-Verstka-Signature: <signature>Какой URL использовать в подписи:
- для
POST /integration/session/open-callback_url; - для callback и скачивания ZIP -
content_url.
1. Открыть редактор
Endpoint:
POST /integration/session/openТело запроса:
{
"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"
}
}Запрос нужно отправить с заголовком:
X-Verstka-Signature: <signature>Для этого endpoint подпись считается по material_id:callback_url.
Обязательные поля:
| Поле | Назначение |
|---|---|
api_key | Идентифицирует сайт и окружение. |
callback_url | URL сайта, куда Verstka отправит callback. |
material_id | ID материала в CMS сайта. |
Опциональные поля:
| Поле | Назначение |
|---|---|
vms_json | Сохраненное состояние редактора. Передавайте его при повторном редактировании. |
metadata | JSON-объект с данными сайта. Verstka вернет его в callback. |
Если публикация открывается впервые, vms_json можно не передавать. Если публикация уже сохранялась в Verstka, передайте последний сохраненный vms_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:
{
"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
}Что должен сделать сайт:
- Прочитать заголовок
X-Verstka-Signature. - Проверить подпись по формуле
hex(HMAC_SHA256(api_secret, material_id + ":" + content_url)). - Скачать ZIP по
content_url. - Сохранить медиа, HTML и JSON у себя.
- Вернуть ответ Verstka.
Успешный ответ:
{
"rc": 1,
"rm": "Saved successfully",
"data": {
"vms_json": {}
}
}data.vms_json должен содержать обновленное состояние редактора с публичными URL файлов в assets[*].clientUrl. Verstka сохранит эти URL, чтобы при следующем открытии публикация уже работала с файлами сайта.
Если сайт отклоняет сохранение, верните rc: 0 и сообщение в rm.
3. Скачать ZIP публикации
Endpoint:
GET /integration/download/media/{fingerprint}/{version_id}Этот URL приходит в callback article_saved как content_url.
К запросу нужно добавить query-параметры:
?api_key=<api_key>&material_id=<material_id>И передать заголовок:
X-Verstka-Signature: <signature>Подпись должна соответствовать material_id:content_url.
ZIP содержит:
| Файл | Назначение |
|---|---|
vms_html.html | HTML, который сайт выводит на публичной странице. |
vms_json.json | Состояние редактора для следующего открытия. |
vms_media/* | Медиафайлы публикации. |
metadata_json.json | Metadata сессии и последней версии. |
После распаковки сайт должен:
- сохранить файлы из
vms_media/*в публичное хранилище; - получить публичный URL для каждого файла;
- заменить временные URL в
vms_html; - записать публичные URL в
vms_json.assets[*].clientUrl; - сохранить
vms_htmlи обновленныйvms_jsonв CMS; - вернуть обновленный
vms_jsonв ответе callback.
Пример:
Файл в ZIP:
vms_media/hero-image.webp
Временная ссылка в HTML и JSON:
dummy-hero-image.webp
Куда сайт сохранил файл:
https://cdn.site.example/articles/42/hero-image.webpПосле сохранения файла сайт заменяет временную ссылку в vms_html:
<!-- было -->
<img src="dummy-hero-image.webp" />
<!-- стало -->
<img src="https://cdn.site.example/articles/42/hero-image.webp" />И записывает тот же публичный URL в vms_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:
{
"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 шрифтов и сохраняет файлы у себя.
Успешный ответ:
{
"rc": 1,
"rm": "Fonts saved successfully",
"data": {
"fonts": {}
}
}data.fonts может вернуть дерево шрифтов с публичными clientUrl для CSS и файлов. Verstka принимает только URL на разрешенных доменах сайта.
5. Скачать ZIP шрифтов
Endpoint:
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.css | CSS с @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_id | ID пользователя в CMS. |
section_id | Раздел, рубрика или категория публикации. |
timeLimitedAuthToken | Ограниченный по времени токен для дополнительной проверки прав. |
customContainers | Конфигурация Custom Containers, если сайт использует свои контейнеры или виджеты. |
Служебные ключи:
| Ключ | Кто задает | Что важно |
|---|---|---|
version | SDK / WordPress plugin | Метка клиента интеграции: Python SDK передает python_<sdk-version>, PHP SDK - php_<sdk-version>, WordPress plugin - wp_<plugin-version>. |
version_id | Verstka backend | ID версии, созданной при последнем сохранении публикации. |
version_cdate | Verstka backend | Дата создания последней версии. |
user_email | Verstka backend / WordPress plugin | Email редактора в callback. Verstka обновляет значение при сохранении. |
user_ip | Verstka backend / WordPress plugin | IP редактора в callback. Verstka обновляет значение при сохранении. |
webhook_auth_user, webhook_auth_password | SDK / 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:
{
"metadata": {
"webhook_auth_user": "callback-user",
"webhook_auth_password": "callback-password"
}
}Bearer token:
{
"metadata": {
"webhook_auth_user": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}Справочник эндпоинтов
| Endpoint | Метод | Назначение |
|---|---|---|
/integration/session/open | POST | Открывает или переиспользует сессию редактирования для пары site + material_id. |
/integration/download/media/{fingerprint}/{version_id} | GET | Отдает ZIP сохраненной версии публикации для обработки сайтом. |
/integration/download/fonts/{fingerprint}/{snapshot_id} | GET | Отдает ZIP шрифтов сайта после изменения набора шрифтов в Verstka. |