• Быстрый старт
    • Доступ и токен
  • СУЩНОСТИ
    • Страницы
      • Markdown
      • Аналитика страниц
    • Фреймы
      • Блоки
      • Бинды data-op-bind
      • Повторитель onpress/repeat
      • Сборка и копии
      • Фреймы в Markdown
      • Фреймы с данными
      • Готовые фреймы
    • Данные
    • Медиа
  • УСТРОЙСТВО САЙТА
    • Сайты
    • Настройки сайта
    • Меню
    • Языки и переводы
    • Стили и оформление
  • УПРАВЛЕНИЕ
    • Домены
    • Соцсети и контакты
    • SEO
    • Аналитика
    • Кэш
    • Дашборд и вход
    • Пользователи и профиль
    • Сайдбар документации
    • Ошибки и проблемы
  • КЕЙСЫ
    • Создание сайтов
    • Работа с контентом
    • Фреймы и данные
    • Настройка сайта
    • Перевод страницы
  • ПРИЛОЖЕНИЯ
    • Приложения
      • Закрытый доступ
      • Данные приложения
      • Внешние данные
      • Демо
    • Быстрый старт
    • Доступ и токен
  • СУЩНОСТИ
    • Страницы
    • Фреймы
    • Данные
    • Медиа
  • УСТРОЙСТВО САЙТА
    • Сайты
    • Настройки сайта
    • Меню
    • Языки и переводы
    • Стили и оформление
  • УПРАВЛЕНИЕ
    • Домены
    • Соцсети и контакты
    • SEO
    • Аналитика
    • Кэш
    • Дашборд и вход
    • Пользователи и профиль
    • Сайдбар документации
    • Ошибки и проблемы
    • Редиректы
    • Кредиты и автоматизация
    • Входящие
    • Кросспостинг
OnPress OnPress
  • Документация
  • Контакты
Войти
Обзор Справочник API
    • Быстрый старт
    • Доступ и токен
  • СУЩНОСТИ
    • Страницы
      • Markdown
      • Аналитика страниц
    • Фреймы
      • Блоки
      • Бинды data-op-bind
      • Повторитель onpress/repeat
      • Сборка и копии
      • Фреймы в Markdown
      • Фреймы с данными
      • Готовые фреймы
    • Данные
    • Медиа
  • УСТРОЙСТВО САЙТА
    • Сайты
    • Настройки сайта
    • Меню
    • Языки и переводы
    • Стили и оформление
  • УПРАВЛЕНИЕ
    • Домены
    • Соцсети и контакты
    • SEO
    • Аналитика
    • Кэш
    • Дашборд и вход
    • Пользователи и профиль
    • Сайдбар документации
    • Ошибки и проблемы
  • КЕЙСЫ
    • Создание сайтов
    • Работа с контентом
    • Фреймы и данные
    • Настройка сайта
    • Перевод страницы
  • ПРИЛОЖЕНИЯ
    • Приложения
      • Закрытый доступ
      • Данные приложения
      • Внешние данные
      • Демо
    • Быстрый старт
    • Доступ и токен
  • СУЩНОСТИ
    • Страницы
    • Фреймы
    • Данные
    • Медиа
  • УСТРОЙСТВО САЙТА
    • Сайты
    • Настройки сайта
    • Меню
    • Языки и переводы
    • Стили и оформление
  • УПРАВЛЕНИЕ
    • Домены
    • Соцсети и контакты
    • SEO
    • Аналитика
    • Кэш
    • Дашборд и вход
    • Пользователи и профиль
    • Сайдбар документации
    • Ошибки и проблемы
    • Редиректы
    • Кредиты и автоматизация
    • Входящие
    • Кросспостинг
Сущности
Markdown
Открыть в ИИ
  • Открыть в ChatGPT
  • Открыть в Claude
  • Открыть в Gemini
  • Открыть в Perplexity
  • Открыть в Grok
  • Открыть в DeepSeek

Страницы

Эндпоинты страниц с параметрами, ответами и кодами отказов; как устроены страницы, написано на странице «Страницы», свойства страницы — на странице «Markdown».

info

Во всех примерах API — https://onpress.pro/api/v2, SITE — id сайта (SITE_ID), OP_TOKEN — токен op_XXXX.

Все эндпоинты — под $API/site/$SITE, право — администратор сайта. {ref} — id страницы, слаг или путь с ~ вместо / (ru~o-nas); голый слаг на многоязычном сайте ищется в языке из lang, без него — в основном языке. Любая запись страницы — публикация, точечная правка, правка полей, удаление — сама сбрасывает кэш этой страницы по её адресу и по прежнему, если адрес сменился, и отвечает полем cache: {"status": "flushed", "urls": [...]}, у черновика без адреса — nothing. Отказ приходит в форме {"success": false, "error": "<код>", "message": "…"} с дополнительными полями из таблицы отказов.

POST /pages/markdown

Создаёт страницу из markdown или обновляет существующую: эндпоинт ищет страницу по id в свойствах, а без него — по полному пути из url и языку. Все свойства страницы, включая url, name, lang и status, эндпоинт читает только из блока свойств в начале markdown, рядом с markdown в теле запроса стоят лишь поля из таблицы ниже. Чтобы не затереть чужую правку, передайте if_modified — версию modified, которую вы читали. Например, опубликовать страницу из файла page.md:

ПолеТипПо умолчаниюОписание
markdownstring—обязательно; весь документ со свойствами
if_modifiedstring—modified из GET /pages/{ref} или GET /pages/{ref}/markdown; страница с тех пор менялась — 409 page_changed, запись не идёт
framestring—фрейм страницы, слаг или id; перекрывает свойство frame
blocksarray—дополнительные блоки после тела: core/*, onpress/*, {"type": "raw", "content": "…"}
faq_autodetectboolfalseсобрать раздел FAQ в блок onpress/faq-items
faq_markersarray—заголовки раздела FAQ для faq_autodetect
curl -s -X POST "$API/site/$SITE/pages/markdown" \
  -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
  -d '{"markdown": "---\nname: \"Первая страница\"\nurl: \"/start/\"\nimage: 5829\n---\n\nТекст страницы."}'
{
  "success": true,
  "updated": false,
  "id": 6446,
  "status": "publish",
  "lang": "ru",
  "parent": 0,
  "url": "/start/",
  "link": "https://example.com/ru/start/",
  "visible": true,
  "translations": { "ru": 6446 },
  "printed": { "how": "on_request", "url": "/start/", "link": "https://example.com/ru/start/", "frame": { "id": "a2dc0bc0d2da6961", "slug": "start", "renders_on_request": true } },
  "lang_changed": { "changed": true, "from": null, "to": "ru" },
  "warnings": [],
  "edit_url": "https://onpress.pro/dashboard/pages?site=SITE_ID&page=6446",
  "view_url": "https://example.com/ru/start/",
  "preview_url": null,
  "scheduled": null,
  "cache": { "status": "flushed", "urls": ["https://example.com/ru/start/"] },
  "meta": { "name": "Первая страница", "slug": "start", "…": "…" },
  "blocks": [ { "blockName": "core/paragraph", "attrs": {}, "innerHTML": "…" } ]
}
ПолеКогда естьСмысл
updatedвсегдаtrue — обновлена существующая
id, status, lang, parentвсегдазаписанная страница
url, linkвсегдапуть в дереве и полный адрес (null у неопубликованной)
visibleвсегдавидит ли посетитель: опубликованы она и все предки
translationsвсегдагруппа переводов {язык: id}
translation_groupс translation_of{origin, term_id, created, changed, unlinked}
frameво входе был frame{id, slug, meta_key} или {cleared: true}
printedвсегда{how, url, link, frame, published_by}; how — static, on_request, not_published, theme
slug_changedслаг занят{requested, applied, reason}
lang_changedязык страницы сменился{changed, from, to}
data_keysв свойствах были свои ключимассив своих ключей, которые запись сохранила в данные страницы (page.data.*), в той форме, в какой их прислали; без keyword и ключей с _
data_keys_noteвместе с data_keysстрока для агента: эти ключи сохранены как данные страницы, а не как ее свойства, и если вы имели в виду свойство, проверьте его имя. Это не предупреждение и не попадает в warnings
date, date_gmtвсегдадата публикации: время сайта и тот же момент в UTC (ISO 8601)
scheduledвсегдаnull или у future — {at, date, event}: момент выхода в UTC, он же по времени сайта и подтвердил ли сайт событие публикации
redirects_created, auto_redirectsу опубликованной страницы сменился адресзаведённые автоправила [{id, from, to}] и сводка {moves, created, updated, enabled}
edit_url, view_url, preview_urlвсегдакарточка страницы в консоли, адрес страницы, адрес предпросмотра (null у опубликованной)
cacheвсегдасброс кэша страницы
warningsвсегдапредупреждения
meta, blocksвсегдаразобранные свойства и блоки, в которые превратилось тело

Превью страницы задает свойство image: номер вложения этого сайта или адрес картинки. Адрес своей картинки узнаётся без скачивания, чужая картинка заливается в медиатеку, повтор того же адреса берёт то же вложение. image: "" снимает превью, нет ключа — превью не трогается. Превью — это og:image страницы, обложка в блоке onpress/featured-image и картинка в карточках дочерних страниц.

Пошаговая инструкция — фрейм howto в теле страницы: он выводит шаги и печатает разметку HowTo в своей верстке.

Адрес страницы задает url: сегменты до последнего называют родителей, последний сегмент становится слагом самой страницы, и url: "/demo/game/" публикует страницу по адресу /demo/game/ при любом name. Явное свойство slug главнее последнего сегмента url, а без slug и url эндпоинт собирает слаг из name. Если страницы по адресу из url нет, а под тем же родителем в том же языке есть страница со слагом из name, эндпоинт обновляет ее на месте и в warnings пишет, как перенести ее на адрес из url: добавьте в свойства id этой страницы и slug. Страницу без адреса эндпоинт не записывает и отвечает 400 page_address_empty.

Редиректов у страниц нет. Старый адрес и переезд раздела заводятся правилом сайта — Редиректы; ключ redirect в свойствах публикация не записывает и дает предупреждение. Сменили у опубликованной страницы slug или родителя — правило 301 со старого адреса заводится само, для неё и для каждого опубликованного потомка. Пробного прогона у публикации нет: посмотреть результат до выхода можно, опубликовав страницу со status: draft.

КодHTTPКогдаЧто делать
markdown_required400нет markdown или не строкапришлите документ строкой
blocks_invalid400blocks не массив—
dry_run_not_supported400передан dry_runопубликуйте черновиком: status: draft
page_property_in_body400свойство страницы (url, name, lang, status, seo_title и другие) пришло полем тела рядом с markdown; fieldsперенесите его в свойства в начале markdown
unknown_body_field400в теле поле, которого нет в таблице выше; fields, acceptedуберите поле
url_invalid400последний сегмент url не дает адреса, например /docs/!!!/; segmentлатиница, цифры и -: /docs/game/
page_address_empty400у страницы не выходит адреса: нет ни slug, ни url, ни nameзадайте url или slug в свойствах
invalid_status400статус вне publish, draft, pending, private, future—
invalid_date400date — не дата; field, value"2026-10-05 09:00" или ISO 8601
frame_single400во frame списокодин слаг или id
image_invalid400image не номер и не адрес картинки; field—
block_unsupported400тип блока в blocks вне разрешённых—
image_not_found404вложения с таким номером нетзагрузите картинку POST /media
frame_not_found404фрейма нет на сайтепроверьте слаг в GET /frames
page_changed409страница новее if_modified; modified — текущая версияперечитайте страницу и повторите
page_not_matched409if_modified передан, а страницы для обновления нетуберите if_modified или укажите id
ambiguous_page409слаг у нескольких страниц; matchesукажите id или полный url
lang_mismatch409id — страница другого языкапоправьте lang или id
domain_mismatch409свойство domain — другой сайтуберите domain
translation_group_conflict, front_page_group_conflict409найденная страница состоит в другой группе переводоввыведите её из группы DELETE /pages/{ref}/translations
translation_link_failed422 или 409translation_of не сработал; reasonпроверьте оригинал и язык
image_not_image422вложение не картинка—
parent_not_found422сегмент url — не страница; segment. Родителей API не создаетопубликуйте сначала родителя
absolute_url_in_path422схема или домен в urlтолько путь: /docs/start/
unknown_language422языка lang нет на сайте; languagesдобавьте язык PATCH /data/site.languages
page_vanished500страница исчезла во время записиповторите запрос
image_upload_failed502картинка по адресу не скачалась или не залиласьпроверьте адрес
post_type_not_supported501свойство type не page—
acf_block_unsupported501в blocks блок стороннего конструкторазамените его блоком core/* или onpress/*

Отложенная публикация

Страница выходит в назначенное время сама: дата впереди и статус future (или publish — с датой впереди он тоже становится future). В пределах минуты после даты страница публикуется так же, как при обычном сохранении: появляется по адресу, в лентах и списках дочерних страниц, в карте сайта, в markdown-копии и llms.txt. Перенос даты переносит выход, сохранение со status: draft снимает планирование. Запланировать можно одну страницу — свойство date, серию — POST /pages/series, перевод — полем publish_at в POST /pages/import. Например:

---
name: "Анонс релиза"
url: "/news/release/"
status: "future"
date: "2026-10-05 09:00"
---

Запланированная страница находится по слагу как любая другая, повторная публикация обновит её, а не создаст дубль; в списке страниц она видна со status=future, а что назначено — в поле scheduled ответа.

PATCH /pages/{ref}/markdown

Меняет кусок текста страницы, не пересылая её целиком. Правки применяются по очереди к свежей выгрузке на сервере и записываются одной записью, как у POST /pages/markdown; одна не прошла — не записывается ничего. Правки одной страницы идут по очереди, а если страницу изменили другим эндпоинтом между чтением и записью, правка повторяется на новом тексте. Например, заменить фразу и добавить раздел:

ПолеТипПо умолчаниюОписание
patcharray—обязательно; список правок, у каждой action; одну правку можно прислать прямо в теле
langstring—язык страницы для поиска по слагу; можно в строке запроса
if_modifiedstring—версия, которую вы читали; страница новее — 409 page_changed, без повтора
dry_runboolfalseвернуть итоговый документ полем markdown, ничего не записывая
actionПоляЧто делает
replacefind, with, countзаменяет точный текст find в теле на with ("" — удалить); count — сколько вхождений ждём: 1 по умолчанию, число или "all"
replace_sectionheading, markdownзаменяет раздел — от заголовка до следующего заголовка того же или более высокого уровня; заголовок пишется в markdown
insert_after_sectionheading, markdownвставляет markdown после раздела с подразделами
insert_before_sectionheading, markdownвставляет markdown перед заголовком раздела
remove_sectionheadingубирает раздел с подразделами
set_frontmatterfieldsставит свойства страницы: {"seo_title": "…"}; null убирает ключ; id и data здесь не меняются

Раздел ищется по тексту заголовка: "## Зачем они нужны" — на этом уровне, "Зачем они нужны" — на любом; заголовки в блоках кода не считаются. Разделов с таким заголовком несколько — назовите уровень или выберите нужный полем "occurrence": 2.

curl -s -X PATCH "$API/site/$SITE/pages/proba-api/markdown" \
  -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
  -d '{"patch": [{"action": "replace", "find": "Старое слово.", "with": "Новое слово."}, {"action": "insert_after_section", "heading": "## Раздел", "markdown": "## Второй раздел\n\nЕщё текст."}]}'
{
  "success": true,
  "id": 6484,
  "lang": "ru",
  "applied": [
    { "action": "replace", "replaced": 1 },
    { "action": "insert_after_section", "heading": "## Раздел", "line": 5, "lines": 3 }
  ],
  "changed": true,
  "written": true,
  "previous_modified": "2026-10-27 11:25:00",
  "modified": "2026-10-27 11:25:05",
  "status": "publish",
  "url": "/proba-api/",
  "warnings": [],
  "cache": { "status": "flushed", "urls": ["https://example.com/proba-api/"] },
  "rebaked": { "status": "nothing", "reason": "only the body changed: …" }
}

applied — по записи на правку: replaced у замены, heading, line и lines у разделов, set и removed у свойств. modified — версия после записи, её передают следующей правкой как if_modified. changed: false — правки не меняют текст, запись не идёт. data_keys и data_keys_note приходят, как в POST /pages/markdown, когда запись сохранила свои ключи страницы. rebaked — пересборка фреймов, которые выводят заголовки, адреса и выдержки страниц: она идёт, только если менялись свойства.

КодHTTPКогдаЧто делать
nothing_to_update400нет patch; actionsпришлите список правок
bad_patch_op400правка без нужного поля или с неизвестным action; indexпроверьте правку по таблице действий
frontmatter_field_locked400set_frontmatter меняет id или datadata — через PATCH /pages/{ref}
text_not_found404find нет в теле; in_frontmatter: true, если текст в свойствахперечитайте текст или используйте set_frontmatter
section_not_found404раздела нет; headings — заголовки страницывозьмите заголовок из headings
text_count_mismatch409вхождений не столько, сколько ждали; found, expectedудлините find или передайте count
section_ambiguous409разделов с таким заголовком несколько; matchesназовите уровень или occurrence
page_changed409страница новее if_modifiedперечитайте и повторите
page_not_found404страницы нетпроверьте {ref}
page_language_mismatch409id или путь называют страницу другого языка; actual_langпоправьте lang

PUT /data/pages.content

Тело страницы — это ещё и системные данные pages.content: читаются GET /data/pages.content?page={ref} и пишутся PUT /data/pages.content той же записью, что у POST /pages/markdown. Чтение отдаёт один элемент {id, lang, modified, frame, markdown, body}, и этот ответ можно прислать обратно как есть. Если в markdown только текст без свойств, эндпоинт берет свойства из текущей выгрузки страницы и меняет только тело. Например, заменить текст страницы proba-api:

ПолеТипПо умолчаниюОписание
pagenumber, string—обязательно; id, слаг или путь страницы
markdownstring—обязательно; документ со свойствами или только текст
if_modifiedstring—modified из чтения; страница новее — 409 page_changed
lang, frame, faq_autodetect——как у POST /pages/markdown
dry_runboolfalseразобрать документ и сверить версию без записи
curl -s -X PUT "$API/site/$SITE/data/pages.content" \
  -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
  -d '{"page": "proba-api", "markdown": "Новый текст страницы.", "if_modified": "2026-10-27 11:25:05"}'

Ответ — ответ POST /pages/markdown плюс mode (document или body), modified — версия после записи и rebaked. С dry_run — {dry_run: true, applied: false, id, lang, mode, modified, markdown}.

КодHTTPКогдаЧто делать
invalid_page400нет pageназовите страницу
markdown_required400нет markdown—
page_not_matched409id в свойствах не совпадает с pageуберите id из свойств
page_changed409страница новее if_modifiedперечитайте и повторите
page_not_found404страницы нет—

Остальные отказы — как у POST /pages/markdown. Новая страница этим путём не создаётся, удаляется страница DELETE /pages/{ref}.

POST /pages/series

Публикует несколько страниц одним вызовом с выходом по одной: первая — в publish_at, каждая следующая — через interval. Каждая страница пишется так же, как POST /pages/markdown, серия только назначает даты. Например, две страницы с шагом две минуты:

ПолеТипПо умолчаниюОписание
pagesarray—обязательно; от 1 до 50 страниц: {"markdown": "…", "frame": "…", "blocks": [...]} или строка markdown
publish_atstring, number—дата первой страницы: время сайта "2026-10-05 09:00", ISO 8601 с Z или смещением, unix-секунды
intervalstring, number—шаг: секунды (3600) или "90s", "15m", "1h", "1d", "1h30m"; от 60 секунд до 30 дней. Без publish_at первая страница выходит сразу
dry_runboolfalseпроверить и показать даты без записи
curl -s -X POST "$API/site/$SITE/pages/series" \
  -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
  -d '{"publish_at": "2026-10-02T19:07:00Z", "interval": "2m", "pages": ["---\nname: Серия 1\nurl: /docs/series-1/\n---\nТекст", "---\nname: Серия 2\nurl: /docs/series-2/\n---\nТекст"]}'
{
  "success": true,
  "applied": true,
  "site_id": "SITE_ID",
  "now": "2026-10-02T19:04:55Z",
  "schedule": { "publish_at": "2026-10-02T19:07:00Z", "interval_seconds": 120, "last_at": "2026-10-02T19:09:00Z", "timezone": "UTC-5" },
  "items": [
    { "index": 0, "result": "written", "id": 7064, "updated": false, "title": "Серия 1", "status": "future", "date": "2026-10-02 14:07:00", "date_gmt": "2026-10-02T19:07:00Z", "scheduled": { "at": "2026-10-02T19:07:00Z", "date": "2026-10-02 14:07:00", "event": true }, "url": "/docs/series-1/", "link": null, "warnings": ["…"] },
    { "index": 1, "result": "written", "id": 7065, "status": "future", "date_gmt": "2026-10-02T19:09:00Z", "…": "…" }
  ],
  "warnings": []
}

Страница номер N (с нуля) получает publish_at + N × interval и статус future; прошедшая дата публикует страницу сразу, эндпоинт заменяет status и date из свойств с предупреждением. Без publish_at и interval эндпоинт пишет страницы так, как задают их свойства. Сначала проверяется вся серия, ошибка хоть в одной странице — 422 series_invalid без записи. Если запись всё же упала посреди серии, ответ — success: false, error: "series_partial", failed; записанные до неё остаются, остальные — not_written. items[].result — written, failed или not_written; schedule — null без расписания.

КодHTTPКогдаЧто делать
pages_required400нет pages или список пуст—
invalid_date400publish_at не дата—
invalid_interval400 или 422interval не шаг (400) или вне 60 с … 30 дней (422; seconds, min, max)—
series_too_large413больше 50 страницразбейте серию
series_invalid422ошибки в страницах: errors: [{index, code, message}], в том числе duplicate_slugисправьте страницы, ничего не записано

POST /pages/import

Записывает перевод страницы одним запросом: тело — ответ GET /pages/{ref}/export, переведённый на целевой язык. Страница пишется как POST /pages/markdown и сразу встаёт в группу переводов оригинала, каждый набор из datasets и shared — как PUT /data/{name} с lang, меню — как PUT /data/menu.{область} (пункт-страница указывает на перевод этой страницы, если он есть). Сначала проверяется всё, и при любой ошибке не пишется ничего. Набор, оставшийся на языке оригинала, не записывается (untouched). Например, перевод на английский:

ПолеТипПо умолчаниюОписание
markdownstring—переведённый документ; в свойствах translation_of оригинала и целевой lang, без id; null — только данные
langstring—целевой язык; по умолчанию lang из свойств
datasets, sharedobject—разделы выгрузки с переведёнными items; до 80 наборов вместе
pageobject—раздел page выгрузки; из него берётся оригинал, если в свойствах нет translation_of
publish_atstring—запланировать выход перевода, как у серии
if_modifiedstring—версия уже существующего перевода
dry_runboolfalseпроверить и показать план без записи
curl -s -X POST "$API/site/$SITE/pages/import" \
  -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
  -d '{"lang": "en", "markdown": "---\ntranslation_of: 7036\nlang: en\nname: \"Home\"\nslug: \"home\"\n---\n\nText.", "datasets": {"home_stats": {"items": [{"value": "1.2M+", "label": "drafts written last year"}]}}}'

Ответ — lang, source ({id, lang} оригинала), results — по записи на страницу, набор и меню со status (written, unchanged, untouched, failed, not_written, в пробном прогоне — would_write), page — ответ записи страницы, rebaked и warnings. Если запись упала после чистой проверки, ответ — success: false, error: "import_partial", failed; записанное до неё остаётся.

КодHTTPКогдаЧто делать
import_body_required400тело не объектпришлите выгрузку
markdown_invalid400markdown не строка и не null—
lang_required400целевой язык не названдобавьте lang в тело или в свойства
unknown_language422языка нет на сайте; languagesдобавьте язык PATCH /data/site.languages
polylang_missing409у сайта нет языковдобавьте язык
import_same_language409оригинал уже на целевом языкеправьте его POST /pages/markdown
import_too_large413больше 80 наборовразбейте импорт
import_invalid422ошибки в записях: errors: [{target, code, message}] — translation_of_required, source_page_not_found, id_in_translation, lang_mismatch, page_changed, page_not_matched, duplicate_entry и ошибки наборовисправьте записи, ничего не записано

GET /pages

Возвращает список страниц сайта по страницам выдачи. Например, страницы верхнего уровня на английском:

ПараметрТипПо умолчаниюОписание
langstringвсе языкислаг языка или all; ответ всегда называет язык в lang
statusstringpublish,draft,pending,private,futureстатусы через запятую или any (с корзиной)
parentstring—id, слаг или путь родителя; 0 — верхний уровень; any — без фильтра
framestring—слаг или id фрейма; none — страницы без фрейма
slugstring—точный слаг
searchstring—подстрока заголовка или слага; по тексту ищет GET /pages/search
pagenumber1страница выдачи
per_pagenumber50до 200
orderbystringmenu_ordermenu_order, title, date, modified, id, slug
orderstringascasc, desc
curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/pages?lang=en&parent=0&per_page=1"
{
  "success": true,
  "site_id": "SITE_ID",
  "lang": "en",
  "lang_filtered": true,
  "languages": ["en", "ru"],
  "default_lang": "en",
  "statuses": ["publish", "draft", "pending", "private", "future"],
  "filters": { "parent": 0 },
  "total": 34,
  "page": 1,
  "per_page": 1,
  "total_pages": 34,
  "orderby": "menu_order",
  "order": "asc",
  "items": [
    {
      "id": 6183, "title": "Documentation", "slug": "docs", "status": "publish", "lang": "en",
      "url": "/docs/", "link": "https://example.com/docs/", "parent": 0, "menu_order": 0,
      "children_count": 17, "is_front": false, "date": "2026-09-12 12:48:11", "modified": "2026-09-21 16:20:24",
      "frame": { "id": "af33214f168f8efd", "slug": "docs", "meta_key": "_onpress_frame" },
      "topic": [], "seo": { "title": "…", "description": "…", "keyword": "" }, "target": "", "anchor": "",
      "static": { "published": false, "url": null, "app_key": "page-6183" }
    }
  ]
}

Счётчик страниц выдачи — total_pages. url — с префиксом языка, даты — время сайта в виде ГГГГ-ММ-ДД ЧЧ:ММ:СС, modified — версия для if_modified. static — есть ли статическая копия страницы.

КодHTTPКогдаЧто делать
unknown_language422языка нет; languages—
unknown_status, unknown_orderby422значение вне списка—
frame_not_found404фрейма из frame нет—
page_not_found, ambiguous_page404, 409родитель из parent не найден или неоднозначенназовите родителя id или путём
polylang_inactive409lang на сайте без языковуберите lang

GET /pages/search

Ищет слово, ссылку или шаблон в тексте всех страниц сайта. Ищется тот же markdown, что отдаёт GET /pages/{ref}/markdown: номер строки в ответе совпадает с номером строки выгрузки, и найденное место правят PATCH /pages/{ref}/markdown. Например, где в доках упоминается menu.header:

ПараметрТипПо умолчаниюОписание
qstring—обязательно; что искать, до 500 символов
regexbool01 — q это регулярное выражение JavaScript, применяется к каждой строке отдельно
casebool01 — с учётом регистра
instringbodybody — текст после свойств, title — заголовок, frontmatter — все строки свойств страницы, seo — seo_title, seo_description, focus_keyword, all — всё; можно через запятую
langstringвсе языкислаг языка
pathstring—префикс адреса страницы с префиксом языка: /docs/v2/
statusstringpublishстатусы через запятую или any
limitnumber20страниц в ответе, до 100
offsetnumber0сколько страниц пропустить
contextnumber60символов по обе стороны от вхождения, до 300
max_matchesnumber20вхождений на страницу, до 500; count считает все
curl -s -G "$API/site/$SITE/pages/search" -H "Authorization: Bearer $OP_TOKEN" \
  --data-urlencode "q=menu.header" --data-urlencode "path=/docs/v2/" --data-urlencode "limit=1" --data-urlencode "max_matches=1"
{
  "success": true,
  "site_id": "ef7QmgyEc",
  "q": "menu.header",
  "regex": false,
  "case": false,
  "in": ["body"],
  "lang": "all",
  "path": "/docs/v2/",
  "statuses": ["publish"],
  "scanned": 115,
  "total": 9,
  "total_matches": 24,
  "limit": 1,
  "offset": 0,
  "took_ms": 100,
  "exported": { "cached": 115, "converted": 0 },
  "items": [
    {
      "id": 6261, "title": "Данные", "url": "/docs/v2/ru/guides/data/", "link": "https://onpress.pro/docs/v2/ru/guides/data/",
      "lang": "ru", "status": "publish", "count": 8, "truncated": true,
      "matches": [ { "in": "body", "line": 20, "column": 215, "match": "menu.header", "text": "…только имя: `menu.header`, `site.languages`…", "section": "Данные" } ]
    }
  ]
}

scanned — сколько страниц просмотрено, total — сколько с вхождениями, total_matches — вхождений всего; страницы идут по убыванию count, затем по url. У вхождения: in, line (с 1, у title — null), column, match, text — строка, обрезанная до context символов, section — ближайший заголовок выше. exported — сколько выгрузок взято из памяти сервиса и сколько сделано заново; страница, которую не удалось выгрузить, попадает в errors. Страницу со слагом search этим адресом не прочитать — запрашивайте её по id или пути.

КодHTTPКогдаЧто делать
q_required, q_too_long400нет q или длиннее 500 символов—
regex_invalid400выражение не разбирается—
regex_timeout422выражение выполнялось дольше 2 супростите его или сузьте path
unknown_field, unknown_language, unknown_status422значение вне списка—
too_many_pages422под поиск попало больше 3000 страницсузьте path, lang или status

GET /pages/{ref}

Возвращает одну страницу: паспорт, свойства, фрейм, группу переводов, мету и тело в markdown. Например, русская страница proba-api без тела:

ПараметрТипПо умолчаниюОписание
langstring—в каком языке искать слаг и с чем сверить язык
markdownbooltruefalse — не выгружать тело
asstring—translation_source — свойства выгрузки с translation_of вместо id и без status
curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/pages/proba-api?lang=ru&markdown=false"

Ответ — lang, languages, default_lang, объект page и рядом markdown. В page — поля элемента списка, в том числе modified, и ещё:

Поле pageСмысл
excerptвыдержка
thumbnailпревью {id, url, width, height, alt} или null
pathпуть без префикса языка
parentsцепочка родителей от корня [{id, title, slug, status}]
translationsгруппа переводов
frontmatterсвойства страницы в том виде, в каком их пишет публикация
metaзначимая мета страницы
edit_url, view_url, preview_urlадреса в консоли и на сайте

Если выгрузка тела не удалась, страница всё равно возвращается: markdown: null и markdown_error: {code, message}.

КодHTTPКогдаЧто делать
page_not_found404страницы нетпроверьте {ref}
not_a_page404id называет не страницу—
ambiguous_page409слаг у нескольких страниц; candidatesназовите страницу id или путём
page_language_mismatch409страница на другом языке; actual_langпоправьте lang
unknown_language422языка нет на сайте—
polylang_inactive409lang на сайте без языковуберите lang

GET /pages/{ref}/markdown

Возвращает только тело — ровно в том формате, который принимает публикация. Параметры lang и as — как у GET /pages/{ref}. Вызовы фреймов выгружаются короткой формой <!-- frame/<имя> {параметры} --> … <!-- /frame -->, какой бы формой их ни записали. Повторная публикация выгрузки тело не меняет. Например:

curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/pages/ru~proba-api/markdown"
{
  "success": true,
  "site_id": "SITE_ID",
  "lang": "ru",
  "id": 6431,
  "modified": "2026-10-27 11:25:05",
  "frame": { "id": "e627bf4dbefcc374", "slug": "docs-proba", "meta_key": "_onpress_frame" },
  "markdown": "---\nid: 6431\nname: \"Проба API по-русски\"\nslug: \"proba-api\"\nstatus: \"publish\"\nurl: \"/proba-api/\"\nlang: \"ru\"\nframe: \"docs-proba\"\n---\n\nРусский текст.",
  "meta": { "id": 6431, "name": "Проба API по-русски", "slug": "proba-api", "…": "…" }
}

modified — версия страницы на момент выгрузки: передайте её в if_modified при записи, второй запрос за версией не нужен. Ключевой запрос страницы стоит в свойстве focus_keyword, закрытая от поисковиков страница получает строку noindex: true. Отказы — как у GET /pages/{ref}, плюс 501 exporter_missing (на сайте нет выгрузчика) и export_failed.

GET /pages/{ref}/export

Отдаёт одним ответом всё, что нужно для перевода страницы: паспорт, тело в markdown, наборы данных, которые читают фрейм страницы и вложенные фреймы, и отдельно — общее для сайта: шапку, подвал, меню. Ответ можно целиком отдать нейросети с заданием «переведи на язык X» и залить результат POST /pages/import; инструкция — в поле howto самого ответа. Например:

curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/pages/home/export?lang=en"
{
  "success": true,
  "kind": "onpress-page-export",
  "version": 1,
  "site_id": "SITE_ID",
  "howto": "Translate this page from \"en\" into the target language and return a result in the same shape.\n…",
  "page": { "id": 7036, "slug": "home", "lang": "en", "title": "Home", "status": "publish", "url": "/home/", "frame": { "id": "4de31ed24a7771c3", "slug": "home" }, "seo": { "title": "", "description": "", "keyword": "" }, "excerpt": "", "frontmatter": { "…": "…" } },
  "translations": { "en": 7036 },
  "languages": ["en", "ru"],
  "markdown": "---\ntranslation_of: 7036\nname: \"Home\"\nslug: \"home\"\n…\n---\n\n…",
  "frames": [ { "slug": "home", "id": "4de31ed24a7771c3", "shared": false }, { "slug": "site__header", "id": "…", "shared": true } ],
  "datasets": { "home_stats": { "origin": "site", "lang": "en", "variants": [null], "total": 3, "items": [ { "value": "1.2M+", "label": "drafts written last year" } ] } },
  "shared": { "note": "Common to the whole site (header, footer, menus), not to this page: translate once per language.", "sources": { "menu.header": { "origin": "system", "lang": "en", "total": 3, "items": [ "…" ] } } },
  "computed_sources": []
}
ПолеСмысл
kind, versiononpress-page-export и 1 — признак выгрузки страницы
howtoзадание для нейросети на английском: что переводить, что не трогать (id, slug, url, ключи, ссылки, код) и как залить результат
pageпаспорт: id, slug, lang, title, status, url, link, parent, parents, frame, seo, excerpt, frontmatter
markdownтело в виде ?as=translation_source: translation_of вместо id, без status
framesфреймы страницы, сначала собственный; shared: true — фрейм шапки или подвала
datasetsнаборы страницы на её языке: origin, lang, variants (языки, на которых набор хранится; null — общий список), total, items, lang_fallback
shared{note, sources} — общие для сайта источники menu.*, site.*, наборы шапки и подвала; переводятся один раз на язык
computed_sourcespages.* и breadcrumbs — собираются из заголовков страниц, отдельно не переводятся
unresolved_sources, missing_framesтолько если есть: источники и вложенные фреймы, которых на сайте нет

Текст, вписанный прямо в разметку фрейма, а не лежащий в наборе, в выгрузку не попадает — его переводят правкой фрейма. Отказы — как у GET /pages/{ref}.

GET /pages/{ref}/related

Возвращает кандидатов для внутренних ссылок со страницы: опубликованные страницы её языка, своя тема (topic) впереди. Сама страница, её переводы, главные, служебные и закрытые от индексации страницы в выдачу не попадают. Например, 5 кандидатов:

ПараметрТипПо умолчаниюОписание
langstring—язык, в котором искать слаг страницы
limitnumber20до 50
topicstring—темы через запятую вместо тем страницы
excludestring—id или адреса через запятую, которые не предлагать
curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/pages/6285/related?limit=5"

Ответ — page (id, title, url, topic, keyword), lang, topic, total и items: у кандидата id, title, url, path, topic, keyword, description, same_topic, score и reason — почему он выше соседа.

КодHTTPКогдаЧто делать
page_not_found404страницы нет—
page_has_no_language409у страницы нет языкапроставьте его POST /pages/language
page_language_mismatch409страница на другом языкепоправьте lang

PATCH /pages/{ref}

Меняет поля страницы, не трогая тело: выдержку, фрейм, превью, пошаговую разметку и свои поля. Пробного прогона нет. Например, задать выдержку и снять фрейм:

ПолеТипПо умолчаниюОписание
excerptstring—новая выдержка; "" или null очищают
framestring—слаг или id фрейма; null, false, "", "none" снимают
thumbnailnumber, string—превью: номер вложения или адрес картинки (чужая заливается в медиатеку), {"id": …} или {"url": …}; null, 0, "" снимают. То же, что свойство image
dataobject—свои поля, которые фрейм читает токеном page.data.<ключ>: {"ключ": "значение"}; "" или null снимают
if_modifiedstring—версия, которую вы читали; страница новее — 409 page_changed
langstring—язык для поиска слага; можно в строке запроса
republishbooltruefalse — не пересобирать статическую копию
curl -s -X PATCH "$API/site/$SITE/pages/ru~proba-api" \
  -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
  -d '{"excerpt": "Выдержка ru", "frame": null}'
{
  "success": true,
  "site_id": "SITE_ID",
  "lang": "ru",
  "page": { "id": 6431, "title": "Проба API по-русски", "slug": "proba-api", "status": "publish", "lang": "ru", "url": "/ru/proba-api/", "excerpt": "Выдержка ru", "frame": null, "…": "…" },
  "changed": ["excerpt", "frame"],
  "excerpt": { "from": "", "to": "Выдержка ru" },
  "frame": { "from": { "id": "e627bf4dbefcc374", "slug": "docs-proba", "meta_key": "_onpress_frame" }, "to": null },
  "static": { "published": false, "url": "", "reason": "no_frame", "was_published": false, "removed": false, "changed": false },
  "republish": { "status": "ok", "…": "…" },
  "cache": { "status": "flushed", "urls": ["https://example.com/ru/proba-api/"] }
}

changed — что реально изменилось; ничего — перепубликации нет (republish.status: "skipped", reason: "nothing_changed"). static.reason — renders_on_request, no_frame, not_public, bad_path или пусто, если копия на месте; republish.status — ok, skipped, unavailable, failed, неудача не отменяет правку. У превью в ответе page.thumbnail и thumbnail: {from, to}, эндпоинт отвечает, когда og:image на странице уже новый. Свои поля приходят как data: {ключ: {from, to}}; ключи с подчеркиванием и свойства со своей обработкой (title, slug, frame, excerpt, image) сюда не принимаются, значение — строка, число или булево. Какие ключи читает фрейм страницы — GET /pages/{ref}/data-fields.

КодHTTPКогдаЧто делать
nothing_to_update400нет ни одного поля; fields—
dry_run_not_supported400передан dry_runпрочитайте страницу GET /pages/{ref}
redirect_field_removed400прислано redirectзаведите правило: Редиректы
data_invalid, data_key_invalid, data_key_reserved, data_value_invalid400data не объект, ключ не по правилам или занят, значение — список или объект; key—
excerpt_invalid, frame_single400значение не того вида—
image_invalid400превью не номер и не адрес; field: "thumbnail"—
image_not_found404вложения нет—
image_not_image422вложение не картинка—
image_upload_failed502картинка по адресу не залилась—
frame_not_found404фрейма нет—
page_changed409страница новее if_modifiedперечитайте и повторите
page_not_found, ambiguous_page, page_language_mismatch404, 409как у GET /pages/{ref}—
unknown_language422языка нет на сайте—

GET /pages/{ref}/data-fields

Возвращает, что фрейм страницы вместе с вложенными фреймами берёт из данных именно для этой страницы, какого типа каждое поле и куда записать правку; на этом построен блок «Данные страницы» в консоли. Данные вызовов фреймов в теле страницы сюда не входят — они в markdown. Например:

curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/pages/maya-collins/data-fields"
{
  "success": true,
  "page_id": 7151,
  "lang": "en",
  "frame": { "id": "3c91ed8471c4f391", "slug": "author__page" },
  "frames": [{ "id": "3c91ed8471c4f391", "slug": "author__page" }, { "…": "…" }],
  "page_data": [
    { "key": "cta", "value": "0", "type": "string", "in_frontmatter": true, "written": "cta", "role": "selector", "uses": [{ "frame": "site__cta", "as": "match" }], "write": { "method": "PATCH", "path": "/pages/7151", "body": { "data": { "cta": "<value>" } } } }
  ],
  "items": [
    {
      "dataset": "author", "lang": null, "index": 0, "total": 1, "ref": { "slug": "default" }, "found": true,
      "fields": [ { "key": "role", "value": "Head of Product, Acme", "type": "string", "used": true, "uses": [{ "frame": "author__page", "as": "text" }] } ],
      "write": { "method": "PATCH", "path": "/data/author", "body": { "patch": [{ "action": "merge", "match": { "slug": "default" }, "fields": {} }] } }
    }
  ],
  "shared": [ { "source": "menu.header", "origin": "system", "contextual": false, "frames": ["site__header"] } ]
}
РазделЧто этоЧем писать
page_dataсвои поля страницы: токены page.data.<ключ>PATCH /pages/{ref} с {"data": {…}}
itemsэлемент набора, который страница выбирает повторителем с match по полю-идентификатору (slug, id, key, page, url, path, name)PATCH /data/{набор} с merge
sharedданные, общие для сайта, и списки страницPUT или PATCH /data/{имя}

У поля type — тип редактора: string, url, text, image, number, boolean, list, object; used и uses — выводит ли поле фрейм и где. Поле, по которому страница выбирает элемент, приходит с readonly: true. Нет элемента для страницы — found: false, missing_note и write: null; добавьте его PATCH /data/{набор} с append.

КодHTTPКогдаЧто делать
page_not_found, ambiguous_page, page_language_mismatch404, 409как у GET /pages/{ref}—
unknown_language422языка нет на сайте—
internal_unavailable502сайт не ответил на разборповторите запрос

DELETE /pages/{ref}

Кладёт страницу в корзину, а с force удаляет безвозвратно; снимает статическую копию и сбрасывает кэш. У опубликованной страницы адрес её и опубликованных потомков уводится правилом 301 на ближайшего опубликованного родителя или главную языка — поля redirects_created и auto_redirects. Например, посмотреть план удаления страницы с детьми:

Поле или параметрТипПо умолчаниюОписание
forceboolfalseудалить безвозвратно вместо корзины
with_childrenboolfalseудалить всё поддерево снизу вверх
langstring—язык для сверки
dry_runboolfalseпоказать план без удаления
curl -s -X DELETE "$API/site/$SITE/pages/6428?with_children=1&dry_run=1" -H "Authorization: Bearer $OP_TOKEN"
{
  "success": true,
  "site_id": "SITE_ID",
  "lang": "en",
  "dry_run": true,
  "mode": "trash",
  "page": { "id": 6428, "title": "Проба API", "slug": "proba-api", "lang": "en" },
  "targets": [
    { "id": 6429, "title": "Дочерняя проба", "status": "draft", "url": "/?page_id=6429", "…": "…" },
    { "id": 6428, "title": "Проба API", "status": "publish", "url": "/proba-api/", "translations": { "ru": 6431 }, "…": "…" }
  ],
  "translations": { "en": 6428, "ru": 6431 }
}

Настоящий вызов отвечает mode (trash или delete), page со status_before, removed — по записи на страницу (removed, static, translations_unlinked, translations_kept), translations: {before, after}, cache и restore — как найти страницу в корзине (null после force). Отказ удаления одной страницы поддерева приходит в её записи (removed: false, error: "delete_failed").

КодHTTPКогдаЧто делать
page_has_children409у страницы есть дети; childrenпередайте with_children: true
front_page_delete409главная, страница записей или главная языкасначала назначьте другую главную PUT /data/site.front_page
page_has_no_language409передан lang, а у страницы языка нетуберите lang
page_not_found, ambiguous_page, page_language_mismatch404, 409как у GET /pages/{ref}—
unknown_language422языка нет на сайте—
internal_unavailable502сайт не ответилповторите запрос

POST /pages/language

Проставляет страницам язык: названным в pages или всем страницам без языка. Всё идёт одной транзакцией, правило редиректа смена языка не заводит. Например, найти страницы без языка:

ПолеТипПо умолчаниюОписание
langstringосновной языккакой язык поставить
pagesarray—id, слаги или пути страниц
missingboolfalsetrue — взять все страницы без языка
statusesstringpublishстатусы для missing через запятую
dry_runboolfalseпоказать и не писать
curl -s -X POST "$API/site/$SITE/pages/language" \
  -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
  -d '{"missing": true, "dry_run": true}'
{ "success": true, "site_id": "SITE_ID", "lang": "en", "dry_run": true, "total": 0, "changed": 0, "pages": [] }

Каждая страница в pages — {id, title, url, lang: {from, to}, changed}.

КодHTTPКогдаЧто делать
nothing_to_update400нет ни pages, ни missing—
polylang_inactive409у сайта нет языковдобавьте язык PATCH /data/site.languages
unknown_language422языка нет; languages—
page_not_found404страницы из pages нет—

POST /sections/{section}

Заводит корень раздела — страницу /news/, /changelog/ или /docs/ с фреймом и наборами ленты, как на демо-сайте. Недостающие фреймы ставятся на сайт из библиотеки вместе с вложенными, пустые наборы ленты заводятся, если их нет; страница публикуется сразу. Записи раздела — её дочерние страницы. Например, раздел новостей:

{section}Фрейм страницыТело страницыЕщё ставится
newslanding--newsшапка news__masthead, лента news__feedфреймы news__post, news__category; наборы news_posts, news_cats, news_more, news_more_cat, pager
changeloglanding--changelogшапка changelog__hero, лента changelog__feedфрейм changelog__post; наборы changelog на языке страницы и pager
docsdocsпустое—
ПолеТипПо умолчаниюОписание
langstringосновной языкязык страницы; заголовок — «Новости», «Чейнджлог», «Документация» для ru, иначе News, Changelog, Documentation
curl -s -X POST "$API/site/$SITE/sections/news" \
  -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' -d '{}'
{
  "success": true,
  "section": "news",
  "lang": "en",
  "page": { "id": 7210, "title": "News", "slug": "news", "url": "/news/", "link": "https://example.com/news/", "frame": "landing--news" },
  "frames_installed": [ { "slug": "landing--news", "status": "installed", "bake": "ok" }, { "slug": "news__masthead", "status": "installed", "bake": "ok" } ],
  "datasets_created": ["news_posts", "news_cats", "news_more", "news_more_cat", "pager"]
}

frames_installed — какие фреймы встали на сайт (уже стоявшие не перечисляются), datasets_created — какие наборы заведены, набор на языке — с суффиксом (changelog__en).

КодHTTPКогдаЧто делать
invalid_section400{section} не news, changelog или docs; allowed—
invalid_lang400у сайта нет такого языка; languages—
section_exists409корень раздела на этом языке уже есть; pageправьте его POST /pages/markdown
system_frame_not_found404нужного фрейма нет в библиотеке—
system_frame_missing409версия фрейма в библиотеке без разметкиповторите позже

Ссылки страниц

Какие ссылки стоят в тексте страниц, куда ведут и с каким анкором — для проверки перелинковки. Ссылки берутся только из тела страницы: текст, markdown внутри вызовов фреймов и данные блоков; шапка, подвал, меню, крошки и оглавление не учитываются. Ссылки собираются по запросу и хранятся: чтение отдаёт последнюю сборку. Страница, записанная или удалённая через API, пересобирается сама через пару секунд; правка мимо API, новые редиректы, правка фреймов или наборов карточек видны в ответе как stale: true до следующей сборки.

POST /links/build

Разбирает все страницы сайта, кроме корзины, и сохраняет результат; сайт в пару сотен страниц собирается примерно за секунду. Например:

curl -s -X POST -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/links/build"
{ "success": true, "site_id": "SITE_ID", "building": false, "joined": false, "built": true, "built_at": "2026-10-05T13:29:53.199Z", "duration_ms": 210, "pages": 102, "links": 460, "probed": 0 }

У сайта идёт одна сборка за раз: повторный запрос ждёт текущую и отвечает её итогом с joined: true, а если сборку ведёт другой экземпляр сервиса — сразу 202 с building: true. links — сколько ссылок записано, probed — сколько внутренних адресов пришлось проверить запросом к сайту.

КодHTTPКогдаЧто делать
too_many_pages413больше 5000 опубликованных страниц—
links_build_failed500сборка упала, прежняя осталасьповторите запрос

GET /links

Возвращает страницы сайта из последней сборки пачками, у каждой — её ссылки по порядку в тексте. Например, первая страница с внутренними ссылками:

ПараметрТипПо умолчаниюОписание
langstringвсе языкислаг языка или all
offsetnumber0сдвиг по списку страниц
limitnumber100до 500 страниц
kindstring—internal или external
statusstring—через запятую: ok, broken, redirect, unknown
nofollowbool—1 — только ссылки с rel="nofollow"
qstring—подстрока анкора, адреса или конечного адреса редиректа
cardsbool1учитывать карточки страниц из блоков фреймов; 0 — без них
curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/links?kind=internal&limit=1"
{
  "success": true,
  "site_id": "SITE_ID",
  "built": true,
  "built_at": "2026-10-05T13:29:53.199Z",
  "stale": false,
  "changes": { "pages": 0, "rules": false, "cards": 0, "site": false },
  "building": false,
  "lang": "all",
  "scope": "body",
  "external_check": null,
  "summary": { "pages": 62, "links": 231, "internal": 231, "external": 0, "cards": 0, "broken": 0, "redirect": 0, "nofollow": 0 },
  "total": 28,
  "offset": 0,
  "limit": 1,
  "pages": [
    {
      "id": 6183, "title": "Documentation", "url": "/docs/", "lang": "en", "parent": 0, "status": "publish", "front": false,
      "counts": { "internal": 27, "external": 0, "cards": 0, "broken": 0, "redirect": 0, "nofollow": 0, "inbound": 0, "inbound_pages": 0 },
      "links": [
        { "n": 1, "anchor": "Quickstart", "before": "set once in the ", "after": ". Start here", "href": "/docs/bystryy-start/", "url": "https://example.com/docs/bystryy-start/", "kind": "internal", "domain": null, "page": { "id": 6188, "title": "Quickstart", "url": "/docs/bystryy-start/" }, "status": "ok", "final": null, "nofollow": false, "rel": [], "new_tab": false, "image": false, "source": "body", "frame": null }
      ]
    }
  ]
}
Поле ссылкиСмысл
n, anchorномер по порядку и текст ссылки; у ссылки-картинки — её alt и image: true
before, afterшесть слов до и после анкора без разметки; склеивайте before + anchor + after как есть
href, urlадрес как в тексте и полный адрес
kind, domaininternal — свой сайт; external — чужой, domain без www.
pageстраница сайта, на которую ведёт ссылка, или null
statusok; broken — 404 или 410 (code); redirect — конечный адрес в final: {url, page}; unknown; у внешних без проверки — null
nofollow, rel, new_tabатрибуты ссылки
source, framebody — текст; frame — данные блока фрейма (field — поле адреса); cards — карточка страницы

counts — числа по странице, inbound и inbound_pages — сколько ссылок и со скольких опубликованных страниц ведёт сюда; summary — те же числа по всем страницам до фильтров; external_check — когда прошла проверка ссылок сайта, по которой отмечены битые внешние. С фильтрами kind, status, nofollow, q в ответе остаются только подходящие страницы и ссылки. Якоря на своей странице, mailto: и tel: ссылками не считаются.

КодHTTPКогдаЧто делать
invalid_kind, invalid_status400значение вне списка—
unknown_language422языка нет—
polylang_inactive409lang на сайте без языков—

GET /pages/{ref}/links

Возвращает исходящие ссылки страницы и входящие на неё из последней сборки. Параметры lang, kind, status, nofollow, q, cards — как у GET /links; к входящим применяются все, кроме kind. Например:

curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/pages/6188/links"

Ответ — page (id, title, url, lang, parent, status, front), counts, links — исходящие в той же форме, что в списке, и inbound — входящие с полем from: {id, title, url, lang}, плюс состояние сборки (built, built_at, stale, changes, building). Страница появилась после сборки — page_built: false и пустые списки.

КодHTTPКогдаЧто делать
page_not_found, ambiguous_page, page_language_mismatch404, 409как у GET /pages/{ref}—
invalid_kind, invalid_status400значение вне списка—
unknown_language422языка нет—

Трафик страниц

Сколько поиска и посетителей приносит каждая страница за последние 12 месяцев: показы и клики в Google из Search Console и посетители из Google Analytics 4 — все и из поиска, по странице входа. Цифры обновляются раз в сутки ночью, если источник подключён у сайта в разделе «Аналитика». Трафик старых адресов с редиректом засчитывается странице, адреса сводятся к пути без протокола, www, параметров и якоря.

GET /traffic

Возвращает опубликованные страницы с трафиком за год пачками. Например, первая страница по показам:

ПараметрТипПо умолчаниюОписание
sortstringgsc_impressionsgsc_impressions, gsc_clicks, ga_visits, ga_organic, ga_avg_time, ga_bounce_rate, advice, url, title
orderstringdesc у чисел, asc у url и titleasc или desc
advicestring—any или через запятую stale, no_impressions, not_crawled, low_ctr, engagement
no_impressionsbool—1 — только страницы без показов за год
langstringвсе языкислаг языка или all
statusstringpublishall — все, кроме корзины
qstring—подстрока заголовка или адреса
offsetnumber0сдвиг
limitnumber100до 500
curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/traffic?limit=1"
{
  "success": true,
  "site_id": "SITE_ID",
  "period": { "days": 365, "from": "2025-10-28", "to": "2026-10-27" },
  "updated_at": "2026-10-27T03:30:09.000Z",
  "gsc": { "connected": true, "status": "ok", "state": "fresh", "updated_at": "2026-10-27T03:30:09.000Z", "error": null },
  "ga": { "connected": true, "status": "ok", "state": "fresh", "updated_at": "2026-10-27T03:30:09.000Z", "error": null },
  "unmatched": { "gsc_clicks": 0, "gsc_impressions": 331, "ga_visits": 69, "ga_organic": 4 },
  "redirect_paths": 118,
  "summary": { "pages": 207, "gsc_clicks": 4911, "gsc_impressions": 115871, "ga_visits": 36277, "ga_organic": 6469, "no_impressions": 50 },
  "total": 206,
  "offset": 0,
  "limit": 1,
  "pages": [
    {
      "id": 7901, "title": "Z.ai (нейросеть GLM): что это и как пользоваться", "url": "/z-ai/", "lang": "ru", "status": "publish", "front": false,
      "gsc_clicks": 119, "gsc_impressions": 17979, "ga_visits": 232, "ga_organic": 135, "ga_organic_7d": 4,
      "ga_sessions": 262, "ga_engaged_sessions": 142, "ga_engagement_seconds": 13270, "ga_avg_time": 50.6, "ga_bounce_rate": 0.458,
      "trend": { "gsc_impressions": -0.19, "gsc_clicks": -0.059, "ga_visits": -0.222, "ga_organic": -0.179, "ga_avg_time": null, "ga_bounce_rate": null }
    }
  ]
}
ПолеСмысл
gsc_impressions, gsc_clicksпоказы и клики в Google за год; null — Search Console не подключена или данных ещё нет
ga_visits, ga_organicпользователи, начавшие визит на странице: все и из поиска; null — Google Analytics не подключён
ga_organic_7dпользователи из поиска за последние 7 полных дней
ga_sessions, ga_engaged_sessions, ga_engagement_secondsсуммы за год по визитам, начавшимся на странице
ga_avg_time, ga_bounce_rateсреднее время вовлечения на сеанс в секундах и доля отказов от 0 до 1
trendизменение последних 7 полных дней к 7 перед ними, долей; null — мало данных; окна — в trend_windows
gsc, ga, sourcesсостояние источника: connected, status (ok, pending, error, denied, off), state, updated_at, error
unmatchedтрафик адресов, которых нет среди страниц и редиректов
redirect_pathsсколько старых адресов из редиректов учтено
summaryитог по всем страницам до no_impressions и q
adviceрекомендации по странице, см. ниже
КодHTTPКогдаЧто делать
invalid_sort, invalid_order, invalid_status, invalid_advice400значение вне списка—
unknown_language422языка нет—
polylang_inactive409lang на сайте без языков—

Рекомендации

У каждой страницы в ответе GET /traffic есть поле advice — что с ней сделать по уже собранным данным. Новых запросов к Google эндпоинт не делает. У черновиков advice — null.

kindКогда срабатываетВажностьЧто сделать
staleстраница старше 90 дней, за 90 дней ни одного показа; заменяет no_impressionscriticalпереработать или удалить с редиректом 301
no_impressionsни одного показа за год, страница старше 14 днейhighподобрать ключ, раскрыть тему, добавить ссылки, проверить индексацию
not_crawledGooglebot не заходил 30 дней или ни разуhighотправить на индексацию
low_ctrпоказов от 100, CTR ниже 1%mediumпереписать title и description
engagementотказы выше 25% или время меньше 30 с при сеансах от 10mediumответить на запрос в первом абзаце, добавить конкретику
"advice": {
  "items": [
    { "kind": "stale", "severity": "critical", "impressions_90d": 0, "days": 90, "age_days": 214, "path": "/google/nano-banana-2/", "done": null, "returned": false }
  ],
  "skipped": [],
  "score": 4
}

score — сумма важности (critical 4, high 3, medium 2), skipped — правила, которые не проверялись, и почему: gsc_unavailable, ga_unavailable, too_new, history_short, crawl_unavailable, crawl_window_short, few_sessions, service_page. В summary.advice — сколько страниц с рекомендациями, пороги — в advice_thresholds.

PUT /pages/{ref}/advice/{kind}

Отмечает рекомендацию страницы выполненной, DELETE по тому же адресу снимает отметку. Отметки общие для всех пользователей сайта, в списке у рекомендации появляется done: {at, user_id}. Если отметке больше 30 дней, а рекомендация всё ещё срабатывает, отметка перестаёт действовать: done: null, returned: true, прежняя — в done_before. Например:

curl -s -X PUT -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/pages/z-ai/advice/low_ctr"
{ "success": true, "site_id": "SITE_ID", "page_id": 5776, "kind": "low_ctr", "done": { "at": "2026-10-06T09:02:49.000Z", "user_id": 1 } }
КодHTTPКогдаЧто делать
invalid_advice400неизвестный kind—
page_not_found, ambiguous_page404, 409как у GET /pages/{ref}—

GET /pages/{ref}/traffic

Возвращает трафик одной страницы по периодам — для графиков. Последние 30 дней хранятся по дням, всё старше — по ISO-неделям; свежие дни Search Console дорастают ещё 2–3 ночи. Например, по дням:

ПараметрТипПо умолчаниюОписание
granularitystringdayday — последние 30 дней; week — недели от первой с данными; month — месяцы из тех же недель
metricsstringвсечерез запятую: gsc_impressions, gsc_clicks, ga_users, ga_organic_users, ga_sessions, ga_engaged_sessions, ga_engagement_seconds, ga_avg_time, ga_bounce_rate
curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/pages/z-ai/traffic?granularity=day"
{
  "success": true,
  "site_id": "SITE_ID",
  "page": { "id": 7901, "title": "Z.ai (нейросеть GLM): что это и как пользоваться", "status": "publish" },
  "granularity": "day",
  "metrics": ["gsc_impressions", "gsc_clicks", "ga_users", "…"],
  "from": "2026-09-27",
  "to": "2026-10-26",
  "points": [
    { "day": "2026-10-26", "gsc_impressions": 189, "gsc_clicks": 1, "ga_users": 1, "ga_organic_users": 0, "ga_sessions": 1, "ga_engaged_sessions": 1, "ga_engagement_seconds": 55, "ga_avg_time": 55, "ga_bounce_rate": 0 }
  ],
  "changes": [ { "date": "2026-10-26", "kind": "edit", "kinds": ["edit"], "note": null } ]
}

Точка недельного ряда — week (понедельник), месячного — month (ГГГГ-ММ); неделя относится к месяцу своего четверга. Пользователи за месяц — сумма более коротких периодов и помечены в approx. Период без трафика приходит нулями. changes — даты правок страницы: published, replaced, address (в note — откуда и куда), edit.

КодHTTPКогдаЧто делать
invalid_granularity, invalid_metrics400значение вне списка—
page_not_found, ambiguous_page404, 409как у GET /pages/{ref}—

Сохраненные представления

Свой набор колонок и фильтров раздела «Страницы» можно сохранить под именем как свое представление, в консоли или этими эндпоинтами, и открывать его адресом ?view=<id>. Сохраненные представления личные, у каждого пользователя на каждом сайте свои. Сохраненное представление состоит из базового представления раздела (traffic, seo, default и другие) и параметров адреса, то есть columns и фильтров.

POST /views

Сохраняет представление. GET /views отдаёт {"views": [...]} в порядке сохранения, PATCH /views/{id} меняет name или params, DELETE /views/{id} удаляет. Например:

ПолеТипПо умолчаниюОписание
namestring—обязательно; до 60 символов
viewstring—обязательно; базовое представление раздела
paramsobject—до 30 параметров: ключ — латиница в нижнем регистре, цифры и _, значение — строка до 2000 символов; пустые отбрасываются
curl -s -X POST "$API/site/$SITE/views" \
  -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
  -d '{"name": "Органика", "view": "traffic", "params": {"columns": "page,gscImpressions,gaOrganic", "organic7": "1-"}}'
{ "view": { "id": "v-3f9a1c2b", "name": "Органика", "view": "traffic", "params": { "columns": "page,gscImpressions,gaOrganic", "organic7": "1-" }, "created_at": "2026-10-09T08:12:40.000Z" } }
КодHTTPКогдаЧто делать
invalid_view_name, invalid_view, invalid_view_params400имя, представление или параметры не по правилам—
nothing_to_update400в PATCH нет ни name, ни params—
view_not_found404представления нет—
views_limit409у вас на сайте уже 50 сохраненных представленийудалите ненужный

Markdown-копии страниц

Каждая опубликованная страница открывается ещё и чистым текстом по своему адресу с .md вместо завершающего слеша: https://example.com/docs/start/ → https://example.com/docs/start.md, главная — /index.md, главная языка — /ru/index.md. Токен не нужен. Внутри H1, выдержка (без неё — SEO-описание) и тело в markdown, ссылки и картинки полными адресами; у страницы без тела — список дочерних страниц со ссылками на их .md. На копии ссылается llms.txt. Ответ — 200 text/plain; charset=utf-8, кэш до минуты. 404 отвечают неопубликованные страницы, страницы под паролем, закрытые от индексации (noindex), страницы без фрейма или с неопубликованным родителем и все копии закрытого сайта. Копия обновляется сама при публикации, правке, смене статуса, переносе и удалении страницы.

GET /markdown

Возвращает состояние копий сайта. Например:

curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/markdown"
{ "success": true, "site_id": "ef7QmgyEc", "host": "onpress.pro", "site_closed": false, "pages_in_manifest": 228, "files": 228, "index_url": "https://onpress.pro/index.md", "llms_auto": false }

files — сколько копий собрано, pages_in_manifest — для скольких страниц, llms_auto — llms.txt собран автоматически и пересобирается сам. Копии, которых ещё нет, собираются при первом запросе.

POST /markdown/build

Собирает копии всех публичных страниц разом и, если не передано "llms": false, llms.txt; на большом сайте ответ приходит до двух минут. Например:

ПолеТипПо умолчаниюОписание
llmsbooltrueсобрать заодно llms.txt; свой текст llms.txt не трогается
curl -s -X POST "$API/site/$SITE/markdown/build" \
  -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' -d '{}'
{ "success": true, "site_id": "SITE_ID", "pages": 72, "written": 60, "skipped": 12, "failed": 0, "removed": 0, "llms": { "rebuilt": true, "pages": 60, "bytes": 18140 }, "files": 60, "llms_auto": true }

written — собрано копий, skipped — пропущены непубличные, failed — не записались, removed — сняты копии исчезнувших страниц. llms.rebuilt: false с reason: "custom_text" — у сайта свой текст llms.txt, "nothing_to_list" — публичных страниц нет.

КодHTTPКогдаЧто делать
markdown_missing500на сайте не включена сборка копий—
Далееarrow_forward
Фреймы
На этой странице
  • POST /pages/markdown
    • Отложенная публикация
  • PATCH /pages/{ref}/markdown
    • PUT /data/pages.content
      • POST /pages/series
        • POST /pages/import
          • GET /pages
            • GET /pages/search
              • GET /pages/{ref}
                • GET /pages/{ref}/markdown
                  • GET /pages/{ref}/export
                    • GET /pages/{ref}/related
                      • PATCH /pages/{ref}
                        • GET /pages/{ref}/data-fields
                          • DELETE /pages/{ref}
                            • POST /pages/language
                              • POST /sections/{section}
                                • Ссылки страниц
                                  • POST /links/build
                                    • GET /links
                                      • GET /pages/{ref}/links
                                    • Трафик страниц
                                      • GET /traffic
                                        • Рекомендации
                                          • PUT /pages/{ref}/advice/{kind}
                                            • GET /pages/{ref}/traffic
                                          • Сохраненные представления
                                            • POST /views
                                          • Markdown-копии страниц
                                            • GET /markdown
                                              • POST /markdown/build
                                            1. Главная
                                            2. Docs
                                            3. Документация OnPress v2
                                            4. Справочник API
                                            5. Страницы
                                            OnPress
                                            OnPress
                                            ИП Зуев И.В. ИНН: 360408359441
                                            info@onpress.pro
                                            © 2026
                                            политика конфиденциальности публичная оферта
                                            • visa
                                            • mastercard
                                            • sber
                                            • tpay