SEO
Здесь все эндпоинты SEO сайта: проверка по чеклисту, обход страниц, ссылки, статус в Google, SEO-настройки, карточка приложения, карта сайта, robots.txt, llms.txt, IndexNow, позиции в выдаче и платная отправка на индексацию; как этим пользоваться, рассказано на странице SEO.
Во всех примерах API — https://onpress.pro/api/v2, SITE — id сайта (SITE_ID), OP_TOKEN — токен op_XXXX, example.com — домен сайта. Все пути на странице — от $API/site/$SITE. Права на всех эндпоинтах страницы — администратор сайта. Как выбирается сайт и в какой форме приходят отказы — Доступ и токен.
POST /seo/audit
Проверяет весь чеклист раздела SEO на сервере и сохраняет итог: SEO-настройки и настройки сайта, тему, языки и главные, набор author, счётчики и консоли, файлы robots.txt и llms.txt, визиты ботов и обход страниц. Длится столько же, сколько обход страниц: от секунд до минуты; второй POST, пока идёт первый, получает его результат. Источник, который не ответил, переводит свои пункты в unknown и называется в errors, остальные пункты считаются. Например, проверить сайт:
curl -s -X POST "$API/site/$SITE/seo/audit" -H "Authorization: Bearer $OP_TOKEN"
{
"success": true,
"site_id": "x9HTLHECq",
"checked": true,
"format": 1,
"checked_at": "2026-09-29T09:25:16.998Z",
"took_ms": 1202,
"site_url": "https://example.com",
"totals": { "counted": 38, "ok": 19, "todo": 16, "warn": 3, "na": 1, "unknown": 0 },
"sitemap": { "url": "https://example.com/sitemap_index.xml", "consoles": { "gsc": { "state": "not_connected" }, "ywm": { "state": "not_connected" } }, "error": null },
"files": { "robots": { "state": "ok", "http": 200, "url": "https://example.com/robots.txt" }, "llms": { "state": "none", "http": 404, "url": "https://example.com/llms.txt" } },
"bots": { "…": "…" },
"errors": [],
"checks": [
{
"id": "identity",
"group": "Basics",
"status": "ok",
"title": { "key": "seo.checks.identity.title" },
"why": { "key": "seo.checks.identity.why" },
"summary": "Example",
"fields": [ { "label": { "key": "seo.checks.identity.fields.title" }, "value": "Example" } ],
"fix": { "title": "…", "command": "curl -X PATCH …" }
}
]
}
| Поле ответа | Описание |
|---|---|
checked_at, took_ms | когда прошла проверка и сколько длилась |
totals | counted, ok, todo, warn, na, unknown; na и unknown в counted не входят |
sitemap | адрес карты сайта и что о ней знают Search Console и Вебмастер — в форме GET /sitemap |
files | живые robots.txt и llms.txt: robots.state — ok, warn (закрывает весь сайт Disallow: /, так бывает у закрытого сайта) или fail (не отдаётся, http); llms.state — ok, none (404, файл не собран) или fail |
bots | когда поисковые и ИИ-боты последний раз заходили за robots.txt и картой сайта |
errors | источники, которые не ответили |
checks | пункты чеклиста, см. пункты проверки |
Пункт: id, group (Basics, Indexing, Languages, Markup, Speed, Pages — в консоли «Контент»), status — ok, todo (сделать), warn (требует внимания), na (неприменимо), unknown (источник не ответил); summary, fields, note, rows — строки таблицы пункта, pages — страницы с нарушением; fix — готовая команда curl с этим сайтом; builtin: true — то, что платформа делает сама. Тексты — не фразы, а ключи словаря консоли: {"key", "params"}, {"list": […]}, {"join": […], "sep"}, {"age": iso}; простая строка — значение как есть.
Своих отказов у эндпоинта нет: сломанный источник не останавливает проверку, а попадает в errors.
GET /seo/audit
Отдаёт сохранённый итог без новой проверки — раздел SEO консоли при открытии делает ровно этот вызов. Например, прочитать последний итог:
curl -s "$API/site/$SITE/seo/audit" -H "Authorization: Bearer $OP_TOKEN"
Ответ — в форме POST /seo/audit и ещё два поля, прочитанные вживую: running: true, пока идёт проверка, и access — состояние «сайт открыт / закрыт» (closed, supported, reason, url, retry_after; null, если прочитать не удалось). До первой проверки — checked: false, checked_at: null, checks: [].
Пункты проверки
Своего хранилища у чеклиста нет: всё, что он показывает, лежит в настройках сайта, SEO-настройках, теме и страницах и правится там же. Пункты canonical, redirects, not-found и карта сайта собраны в один tech-basics, Метрика, GA4, Search Console и Вебмастер — в counters, проверки H1 и уровней — в headings. Пункты группы Languages есть только на многоязычном сайте; на одноязычном homes стоит последним пунктом «Основы».
| Пункт | Группа | Что проверяет | Чем чинить | |||
|---|---|---|---|---|---|---|
identity | Basics | название сайта | PUT /data/settings/name | |||
site-icon | Basics | иконка сайта: favicon и логотип организации в разметке | PUT /data/settings/icon | |||
homes | Basics | у каждого языка опубликованная главная | PUT /data/site.front_page, перевод главной | |||
counters | Indexing | Метрика, GA4, Search Console, Вебмастер; статус — худший из четырёх | [`PUT /data/settings/{metrika\ | ga\ | gsc\ | webmaster}`](#data) |
tech-basics | Indexing | карта сайта XML, canonical на саму страницу, 301 после переноса, 404 с noindex | карта — PATCH /seo sitemap.enabled; остальное платформа делает сама | |||
auto-sitemap-hreflang, auto-hreflang, auto-x-default | Languages | карта с альтернативами языков, hreflang с обратными ссылками, x-default на основной язык | делает платформа | |||
schema-website | Markup | WebSite на главной: name, url, description | описание — PATCH /data/site.settings | |||
schema-organization | Markup | Organization на главной: name, url, logo, желательно sameAs | PATCH /data/site.organization, PATCH /data/site.socials | |||
schema-page | Markup | WebPage главной и Article первой статьи | свойство seo_description, набор author | |||
schema-author | Markup | Person автора статьи и ProfilePage | PUT /data/author | |||
schema-breadcrumbs | Markup | BreadcrumbList с name у каждого звена | вложенность страниц: свойство url с родителем | |||
schema-howto | Markup | HowTo с шагами по порядку | фрейм howto или текст страницы | |||
schema-faq | Markup | FAQPage, один узел на страницу | блок вопросов на странице | |||
schema-app | Markup | SoftwareApplication: name и offers или aggregateRating | PATCH /seo/app | |||
schema-og | Markup | og:title, og:description, og:url, og:type, og:image, twitter:card | PATCH /seo social | |||
auto-webp | Speed | картинки отдаются в WebP | делает платформа | |||
auto-lcp-preload | Speed | preload и fetchpriority="high" у картинки первого экрана | делает платформа | |||
auto-web-vitals | Speed | LCP, INP, CLS домена из Chrome UX Report | — | |||
page-cache | Speed | страницы отдаются из кэша | делает платформа | |||
keywords | Pages | ключ страницы стоит в <title> и meta description | свойства seo_title, seo_description | |||
pages-meta | Pages | у страниц есть <title> и meta description | seo_title, seo_description | |||
pages-length | Pages | title не длиннее 65 знаков, описание — 165 | seo_title, seo_description | |||
headings | Pages | ровно один H1 и уровни без пропусков | тело страницы | |||
pages-noindex | Pages | какие страницы закрыты noindex | свойство noindex | |||
images-alt | Pages | у картинок тела есть alt |  в теле страницы | |||
contacts | Pages | политика, условия, контакты и контакты в подвале по каждому языку | публикация страниц, набор footer |
Страницы чинит публикация Markdown с нужными свойствами или текстом — POST /pages/markdown или точечно PATCH /pages/{ref}/markdown. Готовые команды по каждой странице — в fix пункта, до 25 страниц; сайт в них назван в пути, /site/{site_id}/…, а настройки сайта правятся через данные — site.settings, site.organization, site.socials. Например, вписать ключ в title и описание страницы 6949:
curl -s -X POST "$API/site/$SITE/pages/markdown" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"markdown": "---\nid: 6949\nfocus_keyword: \"чат бот\"\nseo_title: \"Чат бот онлайн без регистрации\"\nseo_description: \"Бесплатный чат бот: …\"\n---\n\n<тело из выгрузки без изменений>"}'
homes. Строка на язык: lang, is_default, id, title, url, status, reason. Строка в порядке, когда по / сайт показывает страницу, у языка она есть среди переводов главной, опубликована, у неё есть фрейм и её адрес отвечает 200 без редиректа этой самой страницей. Иначе reason: posts (вместо страницы — лента записей), noPage (главной на языке нет), notPage, notPublished, noFrame, wrongPage (по адресу другая страница), redirect, closed (сайт закрыт), unreachable, http. Нет главной языка — POST /pages/markdown с translation_of: <id главной> и lang или привязка готовой страницы POST /pages/{ref}/translations/{lang}; нет фрейма — PATCH /pages/{ref} с frame; по адресу другая страница или редирект — POST /cache/flush.
counters. «Метрика» в порядке, когда у сайта есть номер счётчика, «Google Analytics» — measurement ID, «Search Console» и «Вебмастер» — когда права подтверждены (verified: true). Строка в консоли ведёт в «Аналитика → Счётчики».
tech-basics. В rows — строка на каждую часть, status ok или warn; сломано хоть что-то — весь пункт не ok. У строки карты — url индекса, count адресов (сумма <url> по дочерним картам живого индекса) и bots — когда боты последний раз забирали карту. Подтверждение остальных частей — signals.canonical, signals.redirects и signals.not_found обхода. На сайте публичны только страницы: архивов авторов, дат, вложений, рубрик и меток, их лент и типа записей post нет (он остаётся только там, где уже есть опубликованные записи) — такие адреса отвечают 404 и в карту сайта не попадают.
keywords. Проверяются опубликованные страницы обхода, у которых задан ключ — свойство focus_keyword; несколько ключей — через запятую, точку с запятой или с новой строки. Title и Description сверяются с отданной разметкой: фразой целиком по границам слов, без учёта регистра и диакритики (ё = е), кавычки, тире и знаки препинания отбрасываются; в китайском, японском, тайском и бирманском — вхождением без границ слов. Статус: все страницы с ключом в порядке — ok, есть нарушения — todo, ключ не задан ни у одной — na. Строка: id, title, lang, url, keywords, title_ok, description_ok (null, когда страница не открылась, причина в reason), missing, seen (title, description), status; нарушения идут первыми.
headings. В полях — «Ровно один H1: N из N» и «Уровни без пропусков: N из N», в pages — страницы с нарушениями, статус — худший из двух. problems[].kind: no_h1, many_h1 (count, text второго), jump — скачок уровня (from, to, text), рядом outline — лестница заголовков. Навигация, подвал и боковая колонка не учитываются; H1 — первая строка # … в теле или заголовок, который печатает фрейм.
images-alt. Картинки тела каждой открытой страницы обхода, без шапки, меню, подвала и боковой колонки. Нет атрибута alt — нарушение; alt="" засчитывается только декоративной картинке (role="presentation" или aria-hidden="true"). В rows — src, file, alt (null — атрибута нет, "" — пустой), page. Alt вписывается в тело страницы:  становится <img alt="alt">.
contacts. По каждому языку опубликованы политика конфиденциальности, условия использования и страница контактов, а в подвале главной — почта или телефон (mailto:, tel:) и ссылки на оба документа. Документ находится по слагу страницы языка: privacy, privacy-policy, polite, politika…, политика…; terms, terms-of-use, oferta, оферта; contacts, contact, kontakty, контакты. Строка: lang, is_default, privacy, terms, contacts ({id, title, url} или null), footer_contact, footer_legal, status, reason. Подвал из набора footer правится PUT /data/footer с тем же lang; набора нет — 404 source_not_found, подвал тогда задан фреймом.
Schema-разметка. Пункты schema-* показывают не настройки, а то, что сайт отдаёт: узлы JSON-LD и теги Open Graph, снятые с живых страниц без кук. Страницы-образцы: главная, первая статья (Article, BlogPosting, NewsArticle), страница с вопросами, страница автора (ProfilePage), страница с крошками и одна внутренняя. Статус: узел есть и обязательные поля заполнены — ok; обязательное поле пустое или ссылка {"@id": …} ведёт на объект, которого нет на странице, — warn; узла нет, хотя он нужен, — todo; к сайту не относится — na; образец не открылся — unknown. В rows — строка на образец: page (home, article, faq, profile, breadcrumbs, app, inner), label, id, lang, url, status, title — тип узла, language (json или markup), code — узел как есть или мета-теги строками (null — узла нет), missing, recommended, refs, note. Код режется на 24 КБ.
Отдельные узлы. Organization строит кто-то один: пока в site.organization пусто name, узел выводит SEO-граф из раздела organization /seo с sameAs из social.profiles; как только name заполнено, сайт выводит узел из site.organization (логотип — иконка сайта, sameAs — site.socials), поле «Источник» говорит, какой действует. Person тема собирает из набора author только на страницах, чей фрейм объявил набор: набор есть, а Person не выводит ни одна страница — todo. BreadcrumbList строится по вложенности страниц, первое звено — главная языка; плоский сайт — na. HowTo печатает фрейм howto в теле страницы; без него платформа собирает узел из трех и больше подзаголовков «Шаг 1…» или нумерованного списка от трех пунктов под H2/H3 со словом инструкции, а шаги фрейма steps важнее текста. Два FAQPage или два HowTo на странице — warn.
Скорость. auto-webp — warn, если есть картинки не в WebP, в pages до 50 страниц (note — сколько картинок не в WebP), всего — pages_total. auto-web-vitals — по порогам CrUX по p75 (телефоны, если есть): все «хорошо» — ok, есть «нужно улучшить» — warn, есть «плохо» — todo (LCP хорошо ≤ 2,5 с, плохо > 4 с), данных нет — na. page-cache — главная и две страницы обхода по два захода без кук, второй обязан прийти из кэша; в rows — адрес, status, ttfb_ms.
GET /seo/pages
Обходит опубликованные страницы по HTTP и читает ту разметку, которую сервер отдаёт на самом деле: до 2000 страниц, 8 одновременно, 15 с на страницу. Пункты pages-*, headings, images-alt и keywords проверки считаются по этому же обходу. Например, проверить русские страницы:
curl -s "$API/site/$SITE/seo/pages?lang=ru" -H "Authorization: Bearer $OP_TOKEN"
{
"success": true,
"site_id": "x9HTLHECq",
"lang": "ru",
"checked_at": "2026-10-28T06:37:00.882Z",
"took_ms": 2808,
"totals": { "pages": 35, "crawled": 35, "checked": 30, "skipped_noindex": 5, "unreachable": 0 },
"meta": { "count": 0, "pages": [] },
"lengths": { "count": 22, "title_max": 65, "description_max": 165, "pages": [ { "id": 6231, "url": "/ru/docs/", "long": ["title"], "title_text": "…" } ] },
"headings": { "count": 3, "pages": [ { "id": 6234, "url": "/ru/docs/install/", "problems": [ { "kind": "many_h1", "count": 2, "text": "Установка" } ], "outline": ["…"] } ] },
"noindex": { "count": 5, "pages": [ { "id": 6240, "url": "/ru/errors/", "status": 404 } ] },
"unreachable": [],
"signals": { "pages": 30, "canonical": { "…": "…" }, "schema": { "…": "…" }, "images": { "…": "…" }, "preload": { "…": "…" }, "hreflang": { "…": "…" }, "og": { "…": "…" }, "redirects": { "…": "…" }, "not_found": { "…": "…" } },
"summary": { "…": "…" },
"pages": [ "…" ]
}
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
lang | string | all | язык страниц |
meta.pages[] — страницы с пустым <title> или meta description (missing, title_text, description_text). lengths.pages[] — title длиннее title_max или описание длиннее description_max (long, тексты и длины). headings.pages[] — нарушения заголовков. noindex.pages[] — страницы, которые отдаются с noindex, с кодом ответа; на заголовки они не проверяются. unreachable — открытые страницы, ответившие не 2xx (reason: http_error, timeout, unreachable, not_html). signals — то, что платформа делает сама: canonical (with, self, other, missing), redirects, not_found, schema, images (img, webp, without_webp), preload, hreflang (missing_return), home.x_default, og; списки режутся до 50 адресов. Больше 2000 страниц — в totals появляется truncated_at.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
unknown_language | 422 | такого языка на сайте нет; языки — в languages | возьмите слаг из ответа |
no_public_pages | 409 | ни у одной опубликованной страницы нет адреса | опубликуйте страницы |
POST /seo/links/check, GET /seo/links
POST ставит фоновую проверку мёртвых ссылок и ссылок на страницу другого языка и сразу отвечает 202 с status: "running" и started_at; GET отдаёт ход или итог. Каждая ссылка из текста с анкором и состоянием цели — ссылки страниц. Например, запустить проверку и прочитать итог:
curl -s -X POST "$API/site/$SITE/seo/links/check" -H "Authorization: Bearer $OP_TOKEN"
curl -s "$API/site/$SITE/seo/links" -H "Authorization: Bearer $OP_TOKEN"
Ответ GET: status — none (проверки не было), running, done, failed, interrupted; started_at, finished_at; в итоге — dead, wrong_lang, unconfirmed и totals. Причина мёртвой ссылки — http_404, http_410, http_5xx, dns, soft_404; неподтверждённой — timeout, tls, redirect_loop или код ответа, который закрывает страницу от роботов.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
check_running | 409 | на сайте уже идёт проверка | дождитесь итога в GET /seo/links |
checks_busy | 429 | сервер проверяет ссылки других сайтов | повторите через несколько минут |
GET /seo/link-graph
Строит граф внутренних ссылок по телам опубликованных страниц: входящие и исходящие ссылки, сироты и вес страницы. Граф кэшируется и пересчитывается сам, когда меняются страницы. Например, граф русских страниц:
curl -s "$API/site/$SITE/seo/link-graph?lang=ru" -H "Authorization: Bearer $OP_TOKEN"
{
"success": true,
"site_id": "x9HTLHECq",
"lang": "ru",
"scope": "body",
"cached": false,
"built_at": "2026-10-28T06:37:00.882Z",
"weight": { "method": "…", "iterations": 20, "damping": 0.85, "scale": "…" },
"summary": { "pages": 120, "orphans": 4, "avg_inbound": 3.2, "site_pages": 120, "site_edges": 410, "site_unresolved_links": 2 },
"pages": [ { "id": 6231, "url": "/ru/docs/", "lang": "ru", "inbound": 12, "inbound_links": 15, "outbound": 8, "outbound_links": 9, "orphan": false, "front": false, "weight": 4.1 } ]
}
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
lang | string | all | язык страниц |
fresh | 1 | — | пересчитать мимо кэша |
| Код | Статус | Когда | Что делать |
|---|---|---|---|
unknown_language | 422 | такого языка на сайте нет | возьмите слаг из languages |
polylang_inactive | 409 | lang передан сайту с одним языком | уберите lang |
too_many_pages | 413 | опубликовано больше 5000 страниц | — |
GET /seo/index-status, POST /seo/index-status
Отдаёт вердикт Search Console URL Inspection по странице: GET — по одной, POST — до 100 разом. Результат держится сутки. Например, статус страницы 5776:
curl -s "$API/site/$SITE/seo/index-status?ref=5776" -H "Authorization: Bearer $OP_TOKEN"
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
ref | string | — | GET: id, слаг или путь страницы, обязательно |
refs | array | — | POST: до 100 id, слагов или путей, обязательно |
refresh | bool | false | спросить Google заново; не чаще раза в час на страницу |
lang | string | — | язык, если слаг есть в нескольких языках |
Ответ: property — ресурс Search Console, quota — остаток квоты, page (у POST — pages и summary: total, live, cached, deferred, failed). У страницы — verdict, coverage_state, indexing_state, robots_txt_state, page_fetch_state, last_crawl_time, google_canonical, checked_at, source (live, cache, none). Квота — 1900 проверок в сутки на ресурс; что не влезло в квоту, в POST приходит с deferred, а не отказом всего пакета.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
ref_required, refs_required | 400 | нет ref или пустой refs | передайте страницу |
too_many_refs | 400 | больше 100 страниц | разбейте на части |
invalid_ref | 400 | элемент refs не число и не строка | исправьте список |
unknown_field | 400 | в теле POST поле кроме refs, refresh, lang | уберите поле |
page_not_found | 404 | страницы нет | проверьте ref |
not_published | 409 | страница не опубликована | опубликуйте её |
gsc_not_connected | 409 | Search Console не подключена | PUT /data/settings/gsc |
gsc_quota_exhausted | 429 | квота на сутки кончилась; Retry-After | повторите после срока |
gsc_busy | 503 | Google не ответил в срок | повторите запрос |
GET /seo, PATCH /seo
GET отдаёт SEO-настройки сайта: разделитель и шаблоны заголовков, метаописания, флаги noindex, хлебные крошки, организацию для SEO-графа, Open Graph, карту сайта; PATCH правит любые разделы — шлите только меняемые. Постраничные title, description и noindex здесь не живут: они в свойствах страницы. Например, включить карту сайта:
curl -s -X PATCH "$API/site/$SITE/seo" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"sitemap": {"enabled": true}}'
{
"success": true,
"site_id": "x9HTLHECq",
"changed": ["sitemap.enabled"],
"seo": { "separator": "sc-dash", "separator_char": "-", "sitemap": { "enabled": true, "entries_per_page": 1000, "author": false, "index_url": "https://example.com/sitemap_index.xml", "…": "…" }, "robots_url": "https://example.com/robots.txt", "…": "…" },
"cache": { "…": "…" }
}
| Раздел | Ключи |
|---|---|
separator | строка — ключ разделителя: sc-dash, sc-pipe, sc-middot… |
titles | шаблоны: home, page, post, 404, author, archive, search |
metadesc | home, page, post, author, archive |
noindex | archive, author, author_noposts (bool), post_types, taxonomies — карты {имя: да или нет} |
attachments | redirect_to_parent (bool) |
breadcrumbs | enabled, bold_last (bool), separator, home, prefix |
organization | type (company, person), name, alternate_name, logo (id картинки), person_user_id, person_name, person_logo (id); при чтении — logo_id, logo_url, person_logo_id |
social | open_graph, twitter (bool), twitter_card (summary, summary_large_image), default_image (id картинки), profiles — facebook, twitter (без @), instagram, linkedin, youtube, wikipedia, mastodon, pinterest, other (массив адресов); при чтении — default_image_id |
sitemap | enabled, author (bool; не действует — архивов авторов нет), entries_per_page (1–10 000); при чтении ещё post_types, taxonomies, governed_by, index_url |
index_now | enabled, key; при чтении ещё supported. Отправка IndexNow идёт через POST /indexnow, этот раздел её не включает |
При чтении рядом ещё separator_char и robots_url. Ответ записи — changed (изменённые ключи), seo после записи и cache. Состав карты сайта задают noindex.post_types и noindex.taxonomies, в карте только страницы. Свою организацию лучше задавать в данных — PATCH /data/site.organization: пока там пусто name, узел Organization строится из раздела organization этого эндпоинта.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
nothing_to_change | 400 | пустое тело | пришлите раздел |
unknown_field | 400 | незнакомый раздел или ключ, в том числе незнакомая соцсеть или тип записей; допустимые — в message | уберите поле |
invalid_{раздел}, invalid_{ключ} | 400 | раздел не объект или значение не той формы: строка, целое число, да/нет | исправьте значение |
invalid_separator | 400 | не ключ вида sc-dash | возьмите ключ из чтения |
invalid_organization_type | 400 | type не company и не person | исправьте тип |
invalid_logo, invalid_default_image | 400 | картинки с таким id на сайте нет | возьмите id из GET /media |
invalid_person_user | 400 | пользователя person_user_id нет | проверьте id |
invalid_twitter_card | 400 | не summary и не summary_large_image | исправьте значение |
invalid_profiles | 400 | social.profiles не объект или other не массив | исправьте профили |
invalid_entries_per_page | 400 | не от 1 до 10 000 | исправьте число |
sitemap_composition_readonly | 400 | прислан sitemap.post_types или sitemap.taxonomies | состав карты задают noindex.post_types и noindex.taxonomies |
invalid_index_now_key | 400 | index_now.key не 8–128 знаков a-f0-9 и не "auto" | исправьте ключ |
index_now_key_missing | 400 | index_now.enabled: true без ключа | пришлите key |
index_now_unsupported | 409 | index_now.enabled: true | отправляйте адреса через POST /indexnow |
yoast_missing | 409 | SEO-настройки на сайте недоступны | — |
GET /seo/app, PATCH /seo/app
Карточка приложения — узел SoftwareApplication на главной. Тема выводит узел, когда карточка включена и заполнены name, rating_value и rating_count; картинка узла — иконка сайта. PATCH принимает любое подмножество полей, null или "" очищают поле. Например, заполнить карточку:
curl -s -X PATCH "$API/site/$SITE/seo/app" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"name": "Example", "category": "WebApplication", "operating_systems": ["Chrome", "Windows"], "price": 0, "currency": "USD", "rating_value": 4.8, "rating_count": 127}'
{
"success": true,
"site_id": "x9HTLHECq",
"changed": ["name", "category", "operating_systems", "price", "rating_value", "rating_count"],
"app": {
"enabled": true,
"name": "Example",
"description": "",
"category": "WebApplication",
"operating_systems": ["Chrome", "Windows"],
"price": 0,
"currency": "USD",
"rating_value": 4.8,
"rating_count": 127,
"image": "https://example.com/…/icon-512.png",
"missing": [],
"output": true,
"choices": {
"category": { "BrowserApplication": "Browser Application", "BusinessApplication": "Business Application", "EducationalApplication": "Educational Application", "UtilitiesApplication": "Utilities Application", "WebApplication": "Web Application" },
"operating_systems": { "Chrome": "Google Chrome", "Windows": "Windows", "…": "…" },
"currency": { "USD": "USD", "EUR": "EUR", "GBP": "GBP", "RUB": "RUB" }
}
},
"cache": { "…": "…" }
}
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
enabled | bool | true | выводить узел; выключенный не выводится при любых полях |
name | string | — | название приложения, обязательно для вывода |
description | string | — | описание |
category | string | BrowserApplication | applicationCategory, одно из choices.category |
operating_systems | string[] | [] | платформы из choices.operating_systems: Chrome, Firefox, Edge, Safari, Opera, Brave, Windows, macOS, Linux, Android, iOS; выходят строкой через запятую |
price | number | — | цена, 0 и больше; 0 — бесплатно |
currency | string | USD | валюта из choices.currency |
rating_value | number | — | оценка от 1 до 5, обязательна для вывода |
rating_count | integer | — | число оценок, от 1, обязательно для вывода |
GET отдаёт app в той же форме без changed и cache. missing — каких из трёх обязательных полей не хватает, output — выйдет ли узел на главной, choices — допустимые значения, их задаёт тема сайта. changed называет только реально изменившиеся поля; после записи кэш страниц сбрасывается, узел виден на главной сразу.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
nothing_to_change | 400 | в теле ни одного поля | пришлите хотя бы одно |
unknown_field | 400 | поле вне списка | уберите поле |
invalid_enabled | 400 | не да/нет | пришлите true или false |
invalid_name, invalid_description | 400 | не строка | пришлите строку |
invalid_category, invalid_currency | 400 | значение вне choices | возьмите значение из choices |
invalid_operating_systems | 400 | не массив строк или платформа вне choices | возьмите ключи из choices.operating_systems |
invalid_price, invalid_rating_value, invalid_rating_count | 400 | число вне диапазона | исправьте число |
theme_fields_missing | 409 | тема сайта не знает настроек приложения | — |
GET /sitemap, POST /sitemap/submit
GET отдаёт, что Search Console и Вебмастер знают о карте сайта sitemap_index.xml; POST отправляет карту в подключённые консоли. Отправляет сам сайт через подключённую аналитику. Например, отправить карту в обе консоли:
curl -s -X POST "$API/site/$SITE/sitemap/submit" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"service": "all"}'
{
"success": true,
"site_id": "x9HTLHECq",
"service": "all",
"sitemap": "https://example.com/sitemap_index.xml",
"gsc": { "state": "submitted", "sitemap": "https://example.com/sitemap_index.xml" },
"ywm": { "state": "already", "already": true, "sitemap": "https://example.com/sitemap_index.xml", "sitemap_id": "d1a3d870-ab57-32f5-bc04-fec6d92f3bb2" }
}
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
service | string | all | gsc, ywm или all |
sitemap_url | string | карта сайта | абсолютный адрес карты |
Ответ по каждому сервису, поле state. Google при чтении: submitted (last_submitted, last_downloaded, is_pending, errors, warnings) или not_submitted (known — какие карты Google знает); при отправке — submitted, Google перечитает карту. Яндекс при чтении: added (sitemap_id, added_date) или not_added (known); при отправке — added или already: отдельного «перечитай» у Вебмастера нет, добавленные карты он обходит сам. Отказ сервиса — тоже state: not_connected (не подключён), not_verified (сайт не подтверждён, 401/403), api_error (code, message — как ответил сервис). Итог проверки несёт то же состояние в sitemap.consoles.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
invalid_service | 400 | service не gsc, ywm или all | исправьте значение |
invalid_sitemap_url | 400 | не абсолютный адрес http(s) | пришлите полный адрес |
GET /sitemap/urls
Отдаёт все адреса, которые сайт отдаёт поисковикам в карте: индекс sitemap_index.xml и каждую дочернюю карту из него. Список читается с самого сайта в момент запроса и совпадает с XML строка в строку, в том же порядке. Например, прочитать карту:
curl -s "$API/site/$SITE/sitemap/urls" -H "Authorization: Bearer $OP_TOKEN"
{
"success": true,
"site_id": "x9HTLHECq",
"sitemap": "https://example.com/sitemap_index.xml",
"total": 73,
"sitemaps": [
{ "url": "https://example.com/page-sitemap.xml", "path": "/page-sitemap.xml", "lastmod": "2026-10-03T10:30:00+00:00", "status": 200, "count": 73 }
],
"urls": [
{ "loc": "https://example.com/", "images": 0, "lastmod": "2026-09-12T17:48:01+00:00", "sitemap": "/page-sitemap.xml" },
{ "loc": "https://example.com/primery/", "images": 2, "lastmod": "2026-09-12T18:04:47+00:00", "sitemap": "/page-sitemap.xml" }
],
"took_ms": 516
}
total — сколько адресов в картах; у дочерней карты, которая не ответила, — error и count: 0; images — сколько картинок у адреса в карте.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
sitemap_unavailable | 502 | индекс карты не ответил; sitemap, status, при обрыве — reason | проверьте карту в GET /seo и повторите |
site_home_missing | 409 | у сайта нет адреса | — |
GET /robots, PUT /robots, DELETE /robots
GET отдаёт robots.txt, который сайт отдаёт сейчас, PUT записывает свой текст, DELETE возвращает общий шаблон сети: закрыты служебные разделы, ленты, поиск, /page/, плюс Sitemap: своей карты. Свой текст отдаётся как есть, строка Sitemap: дописывается, только если её в тексте нет. Например, закрыть раздел /private/:
curl -s -X PUT "$API/site/$SITE/robots" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"content": "User-agent: *\nDisallow: /private/\n"}'
{
"success": true,
"site_id": "x9HTLHECq",
"content": "User-agent: *\nDisallow: /private/\n\nSitemap: https://example.com/sitemap_index.xml\n",
"custom": true,
"default_content": "User-agent: *\n…",
"url": "https://example.com/robots.txt",
"site_closed": false,
"changed": true,
"warnings": []
}
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
content | string | — | PUT: текст файла до 64 КБ, обязательно |
Строка — пустая, # комментарий или Директива: значение. Незнакомая директива, правило до первого User-agent и Sitemap не абсолютным адресом запись не останавливают — они в warnings (line, text, message). У закрытого сайта robots.txt отдаёт User-agent: * / Disallow: / без Sitemap: (site_closed: true), свой текст сохраняется и возвращается при открытии.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
invalid_robots | 400 | строка не той формы; errors (line, text, message) и warnings | исправьте строки |
invalid_content | 400 | не строка или управляющие символы | пришлите текст |
empty_content | 400 | пустой текст | вернуть шаблон — DELETE /robots |
too_large | 413 | больше 64 КБ; limit | сократите текст |
GET /llms, PUT /llms, DELETE /llms
GET отдаёт llms.txt сайта, PUT записывает свой текст, DELETE снимает текст — /llms.txt снова отвечает 404. Своего умолчания нет: без текста файл отвечает 404, собрать его по страницам — POST /llms/build. Например, записать свой текст:
curl -s -X PUT "$API/site/$SITE/llms" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"content": "# Example\n\n## Pages\n\n- [Тарифы](https://example.com/pricing.md): цены и планы.\n"}'
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
content | string | — | PUT: текст файла до 64 КБ, обязательно |
Ответ: content, exists, auto (текст собран сборкой и пересобирается сам), url, site_closed; у записи — ещё changed и warnings (первая строка не # Название — предупреждение). Свой текст, сохранённый PUT, автоматическим не бывает и сам не меняется; вернуть автоматику — снова вызвать сборку. У закрытого сайта /llms.txt отвечает 404, что бы ни было сохранено.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
invalid_content | 400 | не строка или управляющие символы | пришлите текст |
empty_content | 400 | пустой текст | снять текст — DELETE /llms |
too_large | 413 | больше 64 КБ; limit | сократите текст |
POST /llms/build
Собирает llms.txt в формате llmstxt.org по опубликованным страницам всех языков и сохраняет; GET /llms/build или {"dry_run": true} показывают результат без записи. Каждая ссылка ведёт на markdown-копию страницы — адрес с .md. Собрать разом llms.txt и все markdown-копии — POST /markdown/build. Например, собрать и сохранить:
curl -s -X POST "$API/site/$SITE/llms/build" -H "Authorization: Bearer $OP_TOKEN"
{ "success": true, "site_id": "x9HTLHECq", "content": "# Example\n\n## Pages\n\n- [Тарифы](https://example.com/pricing.md): …", "pages": 60, "bytes": 18140, "saved": true, "dry_run": false, "url": "https://example.com/llms.txt" }
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
dry_run | bool | false | показать текст без записи |
Не попадают страницы с noindex, без фрейма, под паролем, служебная 404 и страницы с неопубликованным родителем. Разделы: сначала страницы без раздела, потом по разделу на каждую корневую страницу с детьми, в конце записи. До 600 ссылок, из них записей до 100; если текст не укладывается в 64 КБ, сначала укорачиваются описания, потом хвосты разделов. Собранный текст помечается auto: true и пересобирается сам после каждой публикации, правки, снятия с публикации, переноса и удаления страницы. Флаг «не индексировать сайт» сборку не останавливает.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
too_large | 413 | собранный текст не уложился в 64 КБ | закройте лишние страницы noindex |
GET /indexnow, POST /indexnow
POST бесплатно отправляет адреса сайта в IndexNow, оттуда их получают Bing, Яндекс, Seznam, Naver и другие участники протокола; GET отдаёт ключ, файл подтверждения на домене и журнал последних отправок. Ключ один на сеть, файл https://<домен>/<ключ>.txt сайт отдаёт сам и перед отправкой проверяет. Автоотправки при публикации нет. Например, отправить две страницы:
curl -s -X POST "$API/site/$SITE/indexnow" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"urls": ["https://example.com/", "/pricing/"]}'
{
"success": true,
"site_id": "x9HTLHECq",
"host": "example.com",
"mode": "urls",
"dry_run": false,
"count": 2,
"sent": 2,
"rejected": [],
"batches": [ { "count": 2, "status": 200, "ok": true, "took_ms": 412 } ],
"key_location": "https://example.com/01a6….txt"
}
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
urls | array | — | полные адреса или пути сайта (/about/), до 50 000; нужен urls или all |
all | bool | false | все опубликованные страницы всех языков, кроме закрытых noindex и паролем (skipped_hidden — сколько пропущено) |
dry_run | bool | false | проверить адреса и ключ без отправки |
Адрес чужого хоста, в том числе www-варианта, не уходит, а возвращается в rejected с причиной (foreign_host, invalid_url, invalid_scheme, not_a_string). Адреса уходят пачками по 10 000. GET отдаёт host, endpoint, key (configured, source, location, served; файл не отдаётся — status, error) и log — последние 50 отправок.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
urls_required | 400 | нет ни urls, ни all | передайте одно из двух |
conflicting_fields | 400 | переданы и urls, и all | оставьте одно |
invalid_urls | 400 | urls не массив | пришлите массив |
no_urls | 400 | ни одного адреса этого сайта; host, rejected | проверьте домен в адресах |
too_many_urls | 413 | больше 50 000 адресов | разбейте на части |
indexnow_not_configured | 409 | у сети нет ключа IndexNow | — |
indexnow_key_file_missing | 409 | файл ключа не отдаётся с домена | проверьте key в GET /indexnow |
indexnow_bad_request, indexnow_key_rejected, indexnow_url_rejected, indexnow_quota, indexnow_network | 502 | IndexNow отказал или не ответил; batches | повторите позже |
Данные сайта для SEO
Название, иконка, описание, главная, счётчики, организация, соцсети, автор и подвал — это данные сайта, и пишутся они через /data; поля и отказы — на странице Настройки сайта. Например, заполнить описание сайта, которое идёт в узел WebSite:
curl -s -X PATCH "$API/site/$SITE/data/site.settings" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"description": "Бесплатный ИИ-чат без регистрации"}'
| Что | Эндпоинт | Пункт проверки | Подробно | |||
|---|---|---|---|---|---|---|
| название сайта | PUT /data/settings/name | identity | поля настроек | |||
| иконка: favicon и логотип в разметке | PUT /data/settings/icon | site-icon | поля настроек | |||
| сайт открыт или закрыт | PUT /data/settings/closed | access в GET /seo/audit | поля настроек | |||
описание и видимость поисковикам blog_public | PATCH /data/site.settings | schema-website | site.settings | |||
| главная сайта и языков | PUT /data/site.front_page | homes | главная | |||
| Метрика, GA4, Search Console, Вебмастер | `PUT /data/settings/{metrika\ | ga\ | gsc\ | webmaster}` | counters | счётчики |
| организация | PATCH /data/site.organization | schema-organization | организация | |||
соцсети: sameAs и twitter:site | PATCH /data/site.socials | schema-organization, schema-og | соцсети | |||
| автор статей | PUT /data/author | schema-author | справочник данных | |||
| контакты и документы в подвале | PUT /data/footer с lang | contacts | справочник данных |
Закрытый сайт (closed: true) отвечает посетителям 503 с X-Robots-Tag: noindex, robots.txt отдаёт Disallow: /, карты сайта отвечают 503, llms.txt — 404. Трафик по страницам из Search Console и GA4 — GET /pages/{ref}/traffic, рекомендации по странице — поле advice того же ответа.
GET /serp/settings, PUT /serp/settings
Позиции сайта в выдаче Google и Яндекса по запросам снимает SerpApi; на этих эндпоинтах стоит страница «Позиции» раздела SEO консоли. GET отдаёт способ съёма, плановую проверку, свой ключ, цену, лимиты и расход, PUT меняет способ и плановую проверку. Способ, свой ключ и суточные счётчики принадлежат владельцу токена и общие для всех его сайтов; запросы и история позиций принадлежат сайту. Например, прочитать настройки:
curl -s "$API/site/$SITE/serp/settings" -H "Authorization: Bearer $OP_TOKEN"
{
"success": true,
"mode": "credits",
"auto": false,
"key": null,
"platform": { "configured": true },
"credits": { "action": "serp_position", "price": 1, "available": 20, "balance": 20, "topup_path": "/settings/credits" },
"limits": { "max_queries_per_site": 50, "max_checks_per_day": 50, "manual_cooldown_minutes": 60, "manual_checks_per_hour": 10, "min_interval_days": 7, "platform_max_depth": 30, "own_max_depth": 100, "concurrency": 2, "queue_max": 20 },
"budget": { "mode": "credits", "auto": false, "queries_total": 0, "planned_checks_month": 0, "planned_checks_month_site": 0, "checks_today": 0, "manual_last_hour": 0, "price": 1, "planned_credits_month": 0, "credits_available": 20, "credits_known": true, "allowance_today": 50 }
}
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
mode | string | credits | credits — ключ платформы, 1 кредит за снятую позицию; own — свой ключ SerpApi, платформа ничего не списывает |
auto | bool | false | плановая проверка раз в сутки; смена mode без auto переключает и её: own включает, credits выключает |
refresh | 1 | — | GET: перечитать остаток поисков своего ключа, поиск на это не тратится |
Способы. За кредиты кредит сначала резервируется, списывается после сохранения позиции, в том числе когда сайт не нашёлся в пределах глубины, и возвращается, если съём не удался. Один поиск — страница из десяти результатов; съём останавливается, как только нашёлся адрес сайта или его поддомена, поэтому позиция в топ-10 стоит один поиск, а запрос глубиной 30 — до трёх. Позиция за пределами глубины сохраняется как position: null. Плановая проверка снимает запросы, у которых подошёл срок по interval_days: сначала ни разу не снятые, потом взятые из ключей страниц, потом самые давние; своим ключом она тратит не больше равной доли остатка до сброса тарифа и оставляет 10 поисков на ручные проверки.
| Лимит | Предел |
|---|---|
| запросов на сайт | 50 |
| снятых позиций в сутки на пользователя | 50 — плановые и ручные вместе, сутки по UTC |
| как часто снимается запрос | interval_days от 7 до 90 |
| ручная проверка одного запроса | раз в 60 минут |
| ручных проверок на пользователя | 10 в час, по одной за раз |
| глубина | за кредиты — до 30, свой ключ — до 100 |
| одновременных съёмов на сервере | 2, ещё 20 ждут в очереди |
platform.configured — есть ли на сервере ключ платформы; credits — цена позиции, баланс и страница пополнения. budget: queries_total (запросов на всех сайтах пользователя), planned_checks_month и planned_checks_month_site, checks_today, manual_last_hour, allowance_today; за кредиты — price, planned_credits_month, credits_available, credits_known; своим ключом — searches_total, searches_left, searches_used, days_left, reserve, per_day, spent_today, planned_searches_month, planned_searches_until_reset, fits и max_queries_weekly.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
invalid_mode | 422 | не credits и не own | исправьте значение |
invalid_auto | 422 | не bool | пришлите true или false |
own_key_required | 409 | own без привязанного ключа | привяжите ключ PUT /serp/key |
PUT /serp/key, DELETE /serp/key
PUT привязывает свой ключ SerpApi — один на пользователя для всех сайтов, новый заменяет прежний; DELETE отвязывает: способ возвращается на credits, плановая проверка своим ключом выключается, история позиций остаётся. При привязке ключ проверяется бесплатным запросом сведений об аккаунте SerpApi. Например, привязать ключ:
curl -s -X PUT "$API/site/$SITE/serp/key" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"api_key": "ВАШ_КЛЮЧ_SERPAPI"}'
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
api_key | string | — | приватный ключ SerpApi, от 32 до 128 латинских букв и цифр, обязательно |
Ответ — как у GET /serp/settings. Ключ хранится зашифрованным и обратно не отдаётся: key — mask (•••• и последние четыре знака), status (ok, exhausted — поиски кончились, invalid — SerpApi ключ не принимает), status_message, plan, searches_total, searches_left, searches_used, hourly_limit, renewal_date, refreshed_at.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
invalid_api_key | 422 | ключ не той формы или SerpApi его отверг | проверьте ключ в кабинете SerpApi |
serpapi_unavailable | 502 | SerpApi не ответил на проверку | повторите запрос |
key_not_found | 404 | DELETE: отвязывать нечего | — |
serp_not_configured | 503 | на сервере не настроено хранение ключей | — |
GET /serp/queries, POST /serp/queries
GET отдаёт запросы сайта с последней позицией, изменением и историей, POST добавляет запрос. Например, следить за запросом на русском:
curl -s -X POST "$API/site/$SITE/serp/queries" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"query": "чат бот онлайн", "lang": "ru"}'
{
"success": true,
"query": { "id": 23, "query": "чат бот онлайн", "engine": "google", "gl": "ru", "hl": "ru", "device": "desktop", "lang": "ru", "page_id": null, "source": "manual", "depth": 30, "interval_days": 7, "last_checked_at": null, "last_error": "", "checked": false, "position": null, "url": null, "previous_position": null, "delta": null, "history": [], "expected_searches_per_month": 12.9 }
}
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
query | string | — | текст от 2 до 400 знаков, обязательно |
lang | string | — | язык страницы; из него берутся страна и язык выдачи: ru → ru/ru, en → us/en; без него — us/en |
gl, hl | string | из lang | страна (две буквы) и язык выдачи |
engine | string | google | google или yandex |
device | string | desktop | desktop или mobile |
depth | int | 30 | 10, 20, 30, 50 или 100; за кредиты — не больше 30 |
interval_days | int | 7 | от 7 до 90 |
page_id | int | — | страница сайта, к которой относится запрос |
Ответ GET: queries (сначала взятые из ключей страниц), depths — глубины, доступные в текущем способе, limits, budget. У запроса: source (page — из ключа страницы, manual — добавлен руками), checked, position и url последнего съёма, previous_position, delta (положительное — поднялся; null, если одна из позиций вне топа), history — последние 12 съёмов {at, position}, expected_searches_per_month.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
invalid_query, invalid_engine, invalid_gl, invalid_hl, invalid_depth | 422 | значение не той формы; поле — в field | исправьте поле |
depth_not_allowed | 422 | глубже 30 за кредиты; max | уменьшите глубину или привяжите свой ключ |
invalid_interval | 422 | не целое от 7 до 90; min | исправьте интервал |
query_exists | 409 | такой запрос с тем же поисковиком, страной, языком и устройством уже есть; id | — |
too_many_queries | 409 | на сайте уже 50 запросов; limit | снимите ненужный |
DELETE /serp/queries/{id}
Снимает запрос вместе с историей позиций и отвечает {"success": true, "id": 23}. Например, снять запрос 23:
curl -s -X DELETE "$API/site/$SITE/serp/queries/23" -H "Authorization: Bearer $OP_TOKEN"
| Код | Статус | Когда | Что делать |
|---|---|---|---|
query_not_found | 404 | запроса нет на этом сайте | возьмите id из GET /serp/queries |
POST /serp/queries/sync
Берёт первый ключ каждой опубликованной страницы (свойство focus_keyword) и заводит запрос на языке страницы. Запросы, чей ключ со страницы пропал, выключаются, история остаётся; сверх 50 запросов на сайт не добавляет. Например, сверить запросы с ключами страниц:
curl -s -X POST "$API/site/$SITE/serp/queries/sync" -H "Authorization: Bearer $OP_TOKEN"
Ответ: pages_with_keyword, added, kept, disabled, skipped_over_limit, limit. Своих отказов нет.
GET /serp/queries/{id}/positions
Отдаёт query и positions от старых к новым: at, position (null — вне топа), url — найденный адрес сайта, searches — сколько поисков ушло. Например, сто последних съёмов запроса 23:
curl -s "$API/site/$SITE/serp/queries/23/positions?limit=100" -H "Authorization: Bearer $OP_TOKEN"
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
limit | int | 100 | сколько съёмов, не больше 500 |
| Код | Статус | Когда | Что делать |
|---|---|---|---|
query_not_found | 404 | запроса нет на этом сайте | возьмите id из GET /serp/queries |
POST /serp/queries/{id}/check
Снимает позицию сразу; платит тот, кто вызвал: кредитом или поиском своего ключа. Ответ: searches, credits (1 за кредиты, 0 своим ключом), mode и query с новой позицией. Например, снять позицию запроса 23:
curl -s -X POST "$API/site/$SITE/serp/queries/23/check" -H "Authorization: Bearer $OP_TOKEN"
При любом отказе ничего не снято и не списано; причина последнего отказа, кроме лимитов и нехватки кредитов, остаётся в last_error запроса.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
insufficient_credits | 402 | не хватает кредитов; required, available, topup_path | пополните баланс |
check_cooldown | 429 | запрос проверяли руками меньше 60 минут назад; retry_after_sec, cooldown_minutes | подождите |
manual_hourly_limit | 429 | 10 ручных проверок за час; retry_after_sec | подождите |
daily_limit_reached | 429 | 50 позиций за сутки; limit, used | дождитесь 00:00 UTC |
queue_full | 429 | очередь сервера полна; retry_after_sec | повторите через минуту |
check_in_progress | 409 | идёт другая ваша проверка | дождитесь её |
no_own_key | 409 | способ own без ключа | привяжите ключ |
invalid_api_key | 409 | привязанный ключ перестал работать | привяжите рабочий |
no_searches_left | 409 | поиски кончились, в том числе посреди съёма — тогда результат не сохраняется | дождитесь сброса тарифа |
serpapi_failed | 502 | SerpApi не справился; kind: throttled, network, failed | повторите позже |
platform_key_missing | 503 | на сервере не настроен ключ платформы | снимайте своим ключом |
credits_unavailable | 503 | кредиты недоступны | повторите позже |
query_not_found | 404 | запроса нет на этом сайте | — |
GET /indexing/account, DELETE /indexing/account
Платная отправка страниц в поиск: одна страница — 2 кредита, для всех пользователей одинаково. Страница уходит в Google и Яндекс, а тем же вызовом — в IndexNow для Bing и других поисковиков. В консоли это кнопка «Отправить на индексацию» в строке раздела «Страницы», журнал — «Инструменты → Индексация». Кредиты списываются с того, кто отправляет, журнал общий для сайта. GET /indexing/account отдаёт цену, баланс и суточные пределы. Например:
curl -s "$API/site/$SITE/indexing/account" -H "Authorization: Bearer $OP_TOKEN"
{
"success": true,
"linked": false,
"bot_url": "https://t.me/Link_indexing_bot?start=…",
"platform": { "enabled": true, "price_per_page": 2, "unit": "credits", "credits": { "balance": 20, "held": 0, "available": 20 }, "top_up_path": "/settings/credits", "daily_limit": { "user": 500, "site": 1000 } }
}
platform: enabled — отправка доступна, price_per_page, credits (balance, held — в резерве, available), top_up_path, daily_limit — страниц в сутки на владельца и на сайт. linked — привязан ли свой ключ сервиса; DELETE его отвязывает (removed). PUT /indexing/account со своим ключом отвечает 410 own_key_disabled: отправка идет только за кредиты.
GET /indexing/pages
Отдаёт опубликованные страницы, свежие правки сверху, и состояние их отправки. Например, первые 50 русских:
curl -s "$API/site/$SITE/indexing/pages?lang=ru&per_page=50" -H "Authorization: Bearer $OP_TOKEN"
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
lang | string | все | язык |
search | string | — | строка поиска по страницам |
page | int | 1 | страница списка |
per_page | int | 50 | до 100 |
У страницы: id, title, url, lang, modified, noindex (закрыта от индексации или паролем), state — new (ни разу не отправлялась), changed (правилась после отправки), sent; engines — когда уходила в каждый поисковик; suggested — новая или изменённая и открытая. Рядом total, page, per_page, total_pages.
POST /indexing/estimate
Считает сумму и ничего не отправляет. Например, оценить две страницы, из которых одна чужая:
curl -s -X POST "$API/site/$SITE/indexing/estimate" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"urls": ["https://example.com/", "https://example.org/x/"]}'
{
"success": true,
"site_id": "x9HTLHECq",
"host": "example.com",
"mode": "platform",
"pages": 1,
"links": 1,
"estimated_cost": 2,
"unit": "credits",
"price_per_page": 2,
"already_sent": [],
"rejected": [ { "url": "https://example.org/x/", "reason": "foreign_host" } ],
"credits_available": 20,
"enough": true,
"top_up_path": "/settings/credits"
}
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
urls | array | — | полные адреса страниц сайта, до 2000, обязательно |
force | bool | false | отправить и страницы, ушедшие за последние 7 дней |
engines | array | ["google", "yandex"] | поисковики: google, yandex, bing; цена от их числа не зависит |
Чужие адреса возвращаются в rejected с причиной (foreign_host, invalid_url, invalid_scheme, not_a_string). Страница, уже отправленная за 7 дней, попадает в already_sent (url, engine, at). estimated_cost — pages × price_per_page. Индексацию поисковики не гарантируют.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
urls_required | 400 | нет urls или пустой список | передайте адреса |
no_urls | 400 | ни одного адреса этого сайта; host, rejected | проверьте домен |
engines_required, invalid_engine | 400 | пустой или незнакомый engines | google, yandex, bing |
platform_only | 400 | передан mode, отличный от platform | уберите mode |
platform_normal_only, invalid_se_type | 400 | передан se_type или priority | уберите поля |
too_many_urls | 413 | больше 2000 адресов | разбейте на части |
credits_unavailable | 503 | кредиты недоступны | повторите позже |
POST /indexing/submit
Отправляет страницы: тело как у оценки плюс confirm: true и expected_cost — сумма из оценки. Сервер считает сумму заново и отправляет, только если подтверждённая не меньше; сумма резервируется перед отправкой, а списывается только за страницы, которые ушли. Например, отправить главную:
curl -s -X POST "$API/site/$SITE/indexing/submit" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"urls": ["https://example.com/"], "confirm": true, "expected_cost": 2}'
{ "success": true, "site_id": "x9HTLHECq", "id": "8f0c…", "mode": "platform", "pages": 1, "charged": 2, "unit": "credits", "already_sent": [], "rejected": [] }
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
urls, force, engines | — | — | как у оценки |
confirm | bool | — | подтверждение платного действия, обязательно |
expected_cost | number | — | сумма из оценки в кредитах, обязательно |
idempotency_key | string | — | защищает от двойной отправки при повторе запроса |
Ответ: id — номер отправки в журнале, pages — сколько страниц ушло, charged — сколько списано. Порядок проверок: подтверждение, сумма, суточный предел, баланс — при любом отказе ничего не отправлено и не списано, кроме send_failed.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
confirmation_required | 409 | нет confirm; в теле estimate | подтвердите сумму |
cost_changed | 409 | expected_cost меньше суммы; в теле estimate | подтвердите новую сумму |
nothing_to_send | 409 | всё уже отправлено за 7 дней; already_sent | передайте force: true |
submit_in_progress | 409 | идёт другая ваша отправка | дождитесь её |
duplicate_submission | 409 | idempotency_key уже использован — ничего не отправлено | — |
insufficient_credits | 402 | не хватает кредитов; required, available, top_up_path, estimate | пополните баланс |
daily_limit | 429 | суточный предел; limit, used, left | отправьте завтра |
send_failed | 502 | отправка сорвалась на середине: ушедшие страницы списаны, pages и charged говорят сколько | повторите остальные |
platform_unavailable | 503 | отправка сейчас недоступна | повторите позже |
| отказы оценки | — | см. POST /indexing/estimate | — |
GET /indexing/submissions, POST /indexing/submissions/refresh
GET отдаёт журнал отправок сайта, новые сверху; POST …/refresh сразу обновляет незавершённые отправки и отвечает {"checked": 0, "updated": 0}. Например, журнал с обновлением состояний:
curl -s "$API/site/$SITE/indexing/submissions?refresh=1" -H "Authorization: Bearer $OP_TOKEN"
{
"success": true,
"site_id": "x9HTLHECq",
"total": 1,
"page": 1,
"per_page": 50,
"total_pages": 1,
"summary_30d": { "sends": 1, "pages": 1, "done": 1, "charged": 2 },
"items": [ { "id": "8f0c…", "url": "https://example.com/", "pages": 1, "status": "done", "charged": 2, "created_at": "2026-10-06T09:06:09Z", "updated_at": "2026-10-06T12:00:00Z" } ]
}
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
page | int | 1 | страница журнала |
per_page | int | 50 | до 200 |
status | string | — | sent (отправлено), active (в работе), done (готово), failed (ошибка) |
url | string | — | отправки этой страницы |
search | string | — | часть адреса |
refresh | 1 | — | сначала обновить незавершённые отправки, итог — в refreshed |
Строка: id, url (первая страница отправки), pages, status, charged (null — отправка не за кредиты), created_at, updated_at; summary_30d — за последние 30 дней.
| Код | Статус | Когда | Что делать |
|---|---|---|---|
invalid_status | 400 | status вне списка | исправьте значение |