◆ Sapport для разработчиков Справочник API Каталог ошибок OpenAPI
Разделы

#Публикация статей через модули сайта

Статус: Доступно для сайтов на Bitrix (модуль sapport.connector 1.2.1) и WordPress (модуль sapport-connector 1.1.1). Пакеты для FastAPI и Nuxt в публичный доступ не выпущены. Заказ публикации сегодня выполняется в кабинете Sapport; публичного серверного API публикации нет (см. API статей, статус Планируется).

Модуль сайта — это небольшой плагин, который вы привязываете к вашему сайту. Он раз в несколько минут спрашивает у платформы, есть ли для него задания, проверяет подпись задания, применяет его к вашей CMS и сообщает итог. Страница объясняет, как устроено задание, чем платформа ограждает ваш сайт и что делать при конфликтах. Она предназначена и для владельца сайта, и для разработчика адаптера.

Доступ: в кабинете — право seo.manage для публикации, seo.view для просмотра. Платно: нет. ПДн: нет.

#Как это работает

  1. Вы привязываете сайт: в кабинете создаётся одноразовый код привязки, вы вводите его в модуле. Платформа выдаёт сайту секрет (показывается один раз).
  2. В кабинете вы выбираете статью и нажимаете «Опубликовать на сайт через модуль», указав режим: черновик или публикация.
  3. Платформа создаёт задание, подписывает его и ставит в очередь для вашего сайта.
  4. Модуль забирает задания (опрос раз в 10 минут; ежечасный heartbeat сообщает число ожидающих заданий), проверяет подпись и применяет.
  5. Модуль возвращает итог: applied с адресом страницы либо skipped, conflict, failed с кодом причины. В кабинете у статьи и у сайта виден статус, адрес страницы, идентификатор записи в вашей CMS и ошибка.

Адрес платформы (api_base) для модуля — домен ячейки привязки: RU https://formula-cream.pro, EN https://wfacademy.org, ID https://wfacademy.id. Ячейку определяет префикс кода привязки.

Полный протокол «облако — модуль» (привязка, heartbeat, опрос заданий, итог, отвязка, подпись запросов HMAC) и коды ошибок описаны в PROTOCOL.md и ERRORS.md пакета коннектора. Здесь — то, что нужно, чтобы понимать публикацию статей.

#Задание

ПолеТипОписание
job_idstring (uuid)Идентификатор задания
kind"article" | "post"Источник: статья или пост
action"upsert" | "unpublish"Создать или обновить / снять с сайта
source_idstring (uuid)Идентификатор статьи на платформе
versionintegerВерсия публикации этого источника на этом сайте
payloadobjectСодержимое (ниже)
payload_sha256stringХеш канонического JSON полезной нагрузки
kidstringИдентификатор ключа подписи
sigstringПодпись Ed25519 в base64
issued_atintegerВремя выдачи, секунды Unix
expect_cms_idstring, необязательноИдентификатор записи в CMS, которую платформа ожидает обновить; есть, только если платформа уже применяла этот источник на этом сайте

#Содержимое (payload)

ПолеТипОписание
titlestringЗаголовок
slugstringАдрес страницы (ЧПУ); применяется только при создании
htmlstringГотовый очищенный HTML статьи
excerptstringАнонс. Для статьи — её мета-описание (у статей площадки сначала анонс из блога); для поста — пустая строка
cover_urlstring | nullОбложка: абсолютный https-адрес с домена ячейки
cover_altstring | nullПодпись обложки; сегодня равна заголовку
seoobjecttitle, description, canonical (сегодня всегда null)
tagsarray of stringДо 10 тегов, каждый до 50 знаков
category_hintstring | nullПодсказка раздела
localestringЯзык статьи
publish_mode"draft" | "publish"Желаемый режим
scheduled_atinteger | nullОтложенная публикация; сегодня всегда null
recreatetrue, необязательноПересоздать запись, удалённую на сайте
{
  "job_id": "00000000-0000-4000-8000-000000000001",
  "kind": "article",
  "action": "upsert",
  "source_id": "11111111-1111-4111-8111-111111111111",
  "version": 1,
  "payload": {
    "title": "Пептиды: полный гид",
    "slug": "peptidy-polnyj-gid",
    "html": "<p>Текст статьи</p>",
    "excerpt": "",
    "cover_url": "https://formula-cream.pro/storage/v1/object/public/sapport-files/covers/a.webp",
    "cover_alt": "Пептиды: полный гид",
    "seo": { "title": "Пептиды", "description": "Описание", "canonical": null },
    "tags": ["пептиды", "уход"],
    "category_hint": "ingredients",
    "locale": "ru",
    "publish_mode": "draft",
    "scheduled_at": null
  },
  "payload_sha256": "bbaee6d585670f93302af42addc4d8c2cb70638d1571e4616576a492fe0d26d1",
  "kid": "test-1",
  "sig": "mHgK/Ud/fbDzwnjpKiSKtyi49Mzth+sOOWc+ti2oXYHzzu0CtX92SxKVVH3aNYfuiatMnakLIsODBhieLRHfBw==",
  "issued_at": 1790000000
}

Пример взят из тестовых векторов пакета (ключ test-1 — тестовый и боевыми ячейками не используется).

#Пределы

ЧтоПредел
HTML статьине более 2 000 000 байт UTF-8
Весь payload в JSONне более 3 000 000 байт
ОбложкаJPEG, PNG или WebP, до 5 МБ
Теговдо 10, до 50 знаков каждый
Возраст подписи7 суток; старше — skipped expired

Статья, превысившая предел, не превращается в задание: в кабинете вы увидите исход «слишком велика» либо «пустая».

Относительные адреса картинок и ссылок в HTML превращаются в абсолютные на домен ячейки. Модуль скачивает медиа только с адреса платформы (api_base), без переадресаций: обложка с чужого CDN завершит задание ошибкой media_foreign_origin.

#Подпись задания

Каждое задание подписано Ed25519 закрытым ключом ячейки. Это защищает ваш сайт от подмены задания по пути и от чужих заданий:

Канонический JSON: ключи объектов сортируются по кодовым единицам UTF-16 рекурсивно, без пробелов, числа только целые в пределах ±(2^53−1), вложенность не глубже 32; отклоняются дробные числа, одиночные суррогаты и повторяющиеся ключи. Тестовые векторы и реализация — в пакете коннектора (каталог tests/_vectors/).

Подпись самих запросов модуля к платформе (HMAC-SHA256 с заголовками X-Sapport-Site, X-Sapport-Ts, X-Sapport-Nonce, X-Sapport-Sig, окно ±300 секунд) — отдельный механизм привязки сайта; он описан в протоколе коннектора.

#Что делает модуль с содержимым

Поле заданияBitrixWordPress
ЗаголовокNAMEpost_title
ТекстDETAIL_TEXT (список разрешённых тегов)post_content (wp_kses_post)
АнонсPREVIEW_TEXTpost_excerpt
Адрес (slug)CODE, только при созданииpost_name, только при создании
ТегиTAGSМетки
РазделИз разрешённых разделов по подсказкеРубрика
SEOSEO-шаблоны элементаYoast или Rank Math
Черновик, публикацияACTIVEdraft, publish, future
ОбложкаКартинки элементаМиниатюра записи
Снятие с сайтаACTIVE = NСтатус draft

Модуль в любом случае чистит HTML сам — независимо от очистки на платформе.

#Потолок режима

Владелец сайта может ограничить модуль: «только черновики». Тогда задание на публикацию применится как черновик, а статья, которую человек уже опубликовал на сайте, вернёт конфликт published_awaits_approval.

#Версии

#Итог задания

Модуль возвращает один итог на задание; первый записанный итог окончателен и не перезаписывается.

ИтогПоляСмысл
appliedcms_id, urlПрименено; url есть у опубликованной записи
skippederrorПропущено (устаревшая версия, срок подписи, нечего снимать)
conflicterrorКонфликт со страницей на сайте
failederrorОшибка

Требования к полям: cms_id — ^[A-Za-z0-9_-]{1,64}$; url — только http или https; error — до 500 знаков. Временные сбои (база, сеть, потеря аренды) модуль не отправляет: задание вернётся через 15 минут.

#Коды конфликтов и пропусков

КодИтогСмыслЧто делать
stale_versionskippedВерсия не новее применённойНичего: норма при повторах
expiredskippedПодписи больше 7 сутокСоздать задание заново
deleted_on_siteskipped (при снятии) / conflict (при публикации)Запись удалили на сайтеДля публикации — «Создать заново»
not_foundskippedСнимается источник, который здесь не публиковалсяНичего
edited_on_siteconflictСтатью правили на сайте после модуляОбновить вручную или откатить правку и отправить снова
published_awaits_approvalconflictПотолок «черновик», а запись уже опубликована человекомПоднять потолок или перенести вручную
cms_id_mismatchconflictПлатформа ждёт другую записьОбратиться в поддержку Sapport
issued_in_futurefailedЧасы сайта отстают более чем на 5 минутИсправить время сервера

Полный перечень (подпись, обложка, база сайта, настройка разделов) — в ERRORS.md пакета коннектора.

#Что вы видите в кабинете

У статьи и у сайта (блок «Публикации»): заголовок, режим публикации, статус задания (в очереди, выдано, применено, пропущено, конфликт, ошибка), адрес страницы, идентификатор записи в CMS и текст ошибки. Одновременно список заданий читают сотрудники с правом seo.view, seo.manage или admin.api_keys.

#Публичного API для этого пока нет

Кабинетные маршруты публикации требуют сессии сотрудника и для внешних систем не предназначены. Серверный вызов «опубликовать» с ключом — часть будущего API статей: POST /articles/{id}/publish с target: connector.

#Открытые вопросы