API: руководство (версия 126)
Содержание
Обзор правил, общих для всех методов. Описание каждого метода с примерами — в справочнике «API_REFERENCE»; машиночитаемое — GET /api/v1/openapi.json; возможности для программ — GET /api/v1/capabilities (оба без ключа).
Быстрый старт
- Кабинет → «API и вебхуки» → «Ключи» → создайте ключ с правом
read. Он показывается один раз. - Проверьте доступ:
curl -H "X-Api-Key: smk_…" https://seo.example/api/v1/me. - Добавьте сайт (
write):curl -X POST -H "X-Api-Key: …" -H "Content-Type: application/json" -d '{"host":"example.com"}' https://seo.example/api/v1/sites. - Запустите проверку (
run):POST /analyze— вернётся задание (код 202), ход смотрите вGET /jobs/{id}. - Прочитайте итог:
GET /overview,GET /issues/{host},GET /plan,GET /changes/{host}.
Ключи и права
Ключей может быть несколько; у каждого:
- права:
read(чтение),run(запуск проверок — тяжёлые запросы),write(сайты, задачи, профиль, вебхуки); - срок действия (бессрочный, 30/90 дней, год) и отзыв в любой момент;
- разрешённые адреса — IPv4/IPv6 и сети (
203.0.113.0/24); пусто — любые; - свой лимит запросов в час (по умолчанию 120,
SEOMASTER_API_RATE).
Ключ показывается один раз; в базе только SHA-256. Передавайте его в X-Api-Key или Authorization: Bearer; в адресе нельзя. Для CLI и MCP-сервера заведите отдельный ключ с минимальным набором прав: так проще отозвать и видно в журнале.
Запросы и ответы
Всё в JSON (UTF-8). Тело запросов — Content-Type: application/json. Имена полей стабильны: новые поля могут добавляться, существующие не меняют смысл и тип, поэтому клиент должен игнорировать незнакомые поля. Ошибка всегда одного вида: {"error": "текст", "code": "код"} (в том числе при сбое сервера и обслуживании). Текст предназначен людям и может меняться, программе нужен code.
Каждый ответ содержит X-Request-Id (укажите его в обращении в поддержку), X-API-Version и заголовки лимита.
Ошибки
Код в поле code стабилен; HTTP-статус и признак «повторять можно» ниже.
| Код | HTTP | Повтор | Значение |
|---|---|---|---|
missing | 401 | нет | Не передан ключ. Добавьте заголовок X-Api-Key или Authorization: Bearer. |
invalid | 401 | нет | Ключ не найден. Проверьте, что он скопирован целиком. |
revoked | 401 | нет | Ключ отозван. Выпустите новый в кабинете. |
expired | 401 | нет | Срок действия ключа истёк. Выпустите новый. |
ip | 403 | нет | Запрос с адреса, которого нет в списке разрешённых для ключа. |
blocked | 403 | нет | Аккаунт недоступен. |
closed | 503 | да | Сервис закрыт на тестирование: доступ только для администратора. |
scope | 403 | нет | У ключа нет нужного права (read, run или write). |
limit | 429 | да | Исчерпан лимит запросов ключа или лимит тарифа. Повторите после паузы из заголовка Retry-After. |
not_found | 404 | нет | Сайт, задача, задание или данные не найдены (или принадлежат другому аккаунту). |
not_ready | 409 | да | Данных ещё нет: проверка не выполнялась или не завершена. Запустите проверку или дождитесь задания. |
method | 405 | нет | Для этого адреса такой HTTP-метод не поддерживается. |
bad_request | 400 | нет | Запрос составлен неверно: смотрите текст ошибки. |
bad_host | 400 | нет | Не удалось распознать домен. |
bad_status | 400 | нет | Недопустимое значение статуса. |
bad_param | 400 | нет | Один из параметров запроса имеет недопустимое значение. |
unsupported | 422 | нет | Операция для этого объекта невозможна (например, задачу этого типа нельзя перепроверить автоматически). |
idem_conflict | 422 | нет | Idempotency-Key уже использован с другим запросом. Возьмите новый ключ. |
idem_busy | 409 | да | Запрос с этим Idempotency-Key ещё выполняется. Повторите через секунду. |
tool_off | 503 | нет | Утилита отключена администратором. Выберите другую из каталога или повторите позже. |
service_off | 503 | нет | Внешний сервис, на котором работает раздел, отключён администратором для всех пользователей. Используйте другие данные или повторите позже. |
tool_failed | 422 | нет | Утилита не смогла обработать эти данные или адрес (текст ошибки — в error): исправьте ввод. |
maintenance | 503 | да | Сервис на обслуживании. Повторите позже (Retry-After). |
server | 500 | да | Внутренняя ошибка. Повторите позже и сообщите X-Request-Id, если повторяется. |
Правило для клиента: повторять только если «Повтор — да», с паузой из Retry-After (если нет — 1, 2, 4… секунд, не более 5 попыток); остальные ошибки исправляйте в запросе.
Лимиты и заголовки
X-RateLimit-Limit и X-RateLimit-Remaining — лимит ключа в час и остаток; при исчерпании — 429 limit и Retry-After. Запуск проверок дополнительно ограничен тарифом (дневное число проверок и повторных проверок задач); обход сайта через API считается как три проверки. Остаток по ключу — GET /usage.
Постраничность
Списки принимают limit (по умолчанию 50, максимум 200) и offset. Ответ содержит объект page: limit, offset, total, next_offset (null — страниц больше нет). Листайте, пока next_offset не станет null.
Условные запросы (ETag)
Ответы на GET содержат ETag. Повторите запрос с If-None-Match: <значение> — если данные не изменились, придёт 304 без тела и лимит не потратится впустую. Удобно для опроса GET /overview, GET /plan и GET /events.
Идемпотентность
Для POST, PUT, PATCH, DELETE передайте заголовок Idempotency-Key (1–64 символа: буквы, цифры, . _ : -). Повтор с тем же ключом и тем же запросом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replay: true и ничего не выполнит второй раз — безопасно при обрыве связи. Тот же ключ с другим запросом — idem_conflict; пока первый запрос выполняется — idem_busy. Ответы 5xx не запоминаются. Секрет вебхука в сохранённый ответ не попадает: при повторе вместо него пояснение, создайте секрет заново через POST /webhooks/{id}/rotate-secret.
Фоновые задания
Долгие операции (POST /analyze, POST /crawl/{host}) отвечают 202 и объектом задания. Опрашивайте GET /jobs/{id}: состояние queued, running, done или error; пока задание идёт, поле poll_after_s подсказывает паузу (3 секунды); по завершении — ссылки на результат. GET /jobs — последние задания. Задания видны только владельцу ключа.
Вебхуки
Несколько адресов на пользователя; для каждого — набор событий (events, uptime, watchdog, page, crawl, rank, security, digest), фильтр по сайтам (поддомены подходят), секрет. Через API: GET|POST /webhooks, DELETE /webhooks/{id}, POST /webhooks/{id}/rotate-secret, POST /webhooks/{id}/test, GET /webhooks/{id}/deliveries. Лимит адресов — по тарифу (webhooks), ключей — api_keys.
Тело — исходное уведомление плюс event, delivery, sent_at. Заголовки: X-SeoMaster-Event, X-SeoMaster-Delivery, X-SeoMaster-Timestamp, X-SeoMaster-Signature-V2: t=<время>,v1=<HMAC-SHA256("время.тело", секрет)>; прежний X-SeoMaster-Signature: sha256=<HMAC от тела> сохранён. Получатель проверяет подпись и отбрасывает запросы старше 5 минут.
Проверка подписи (PHP):
[$t, $v1] = array_map(fn($p) => explode('=', $p, 2)[1], explode(',', $_SERVER['HTTP_X_SEOMASTER_SIGNATURE_V2']));
$ok = abs(time() - (int)$t) < 300 && hash_equals(hash_hmac('sha256', $t . '.' . file_get_contents('php://input'), $secret), $v1);
Доставка: ответ 2xx за 8 секунд. Иначе повторы через 1 мин, 5 мин, 30 мин, 2 ч, 12 ч; после шестой неудачи доставка «потеряна» (ошибки 4xx, кроме 408/409/425/429, — после третьей), её можно отправить вручную. 15 неудач подряд отключают адрес. Адреса проверяются на SSRF при каждой отправке. Первая попытка — сразу, повторы — bin/webhooks.php (cron каждую минуту).
Версии и совместимость
Версия контракта — в info.version схемы OpenAPI, в GET /capabilities и в заголовке X-API-Version (сейчас 1.3; номер версии сервиса — отдельно, x-service-version). Внутри /api/v1 изменения только добавляющие: новые методы, поля и необязательные параметры. Несовместимые изменения выйдут под /api/v2, а /api/v1 будет работать не меньше 12 месяцев после объявления. Ошибки определяйте по code, а не по тексту.
Для CLI и MCP-сервера
API проектировалось так, чтобы командная строка и MCP-сервер были тонкой оболочкой над ним:
- единые имена: у каждого метода есть команда CLI (
x-cli, напримерseomaster site issues) и инструмент MCP (x-mcp, напримерget_top_issues); они указаны в справочнике, в OpenAPI и вGET /capabilities; - самоописание:
GET /capabilitiesбез ключа отдаёт версию, права, лимиты, соглашения, каталог ошибок, события вебхуков и список методов — CLI и MCP строят по нему справку и схемы инструментов, не храня копию; - признаки операций:
x-readonly(только чтение — MCPreadOnlyHint),x-async(возвращает задание), правоx-scope; методы удаления помечаются как разрушающие, аPUT/DELETE— идемпотентные; - безопасное выполнение: у каждого изменяющего вызова есть
Idempotency-Key; опасные правки профиля требуют явногоconfirm; долгие операции — задания с опросом; - единая форма ошибок и стабильные коды: CLI возвращает код выхода (0 — успех, 1 — ошибка запроса, 2 — ключ или права, 3 — лимит или недоступность, 4 — сеть), MCP — сообщение с
codeи признаком повтора; - настройка: адрес сервиса и ключ — переменные
SEOMASTER_URLиSEOMASTER_KEY(или файл настроек); ключ не печатается в журнал.
MCP-сервер работает с версии 126: адрес /mcp, инструменты строятся из этого же реестра методов, описание — в руководстве «MCP». CLI seomaster работает с версии 127 (bin/seomaster, руководство «CLI» — docs/CLI.md): команды строятся по GET /capabilities; имена команд и инструментов закреплены и не будут переименованы.
Что нового
- 129: вход OAuth 2.1 для MCP (
/oauth/register,/oauth/authorize,/oauth/token,/oauth/revoke, метаданные/.well-known/oauth-protected-resourceи/.well-known/oauth-authorization-server, обязательный PKCE). Токен доступа — обычный ключsmk_…с выбранными правами, работает и в REST API; контракт не менялся. - 128: контракт 1.3. Утилиты сервиса (86 штук) как методы:
GET /utilities,GET /utilities/{id},POST /utilities/{id}(командыseomaster utils …, инструменты MCPlist_utilities,get_utility,run_utility); сводкиGET /todayиGET /incidents. Коды ошибокtool_offиtool_failed. MCP: 31 готовый сценарий вместо 7. CLI: вывод блоков утилит, ввод из файла и стандартного ввода. - 127: CLI
seomaster. ВGET /capabilitiesу каждого метода добавленыparamsиbody(параметры и тело запроса); остальное без изменений. - 126: контракт 1.2. Новые методы данных:
GET /performance/{host},/queries/{host},/opportunities/{host},/positions/{host},/backlinks/{host},/effects/{host},/work/{host}. MCP-серверPOST /mcp. Прежние методы чтения вынесены из маршрута в класс (поведение не изменилось). - 125: контракт 1.1. Методы:
GET /overview,/plan,/issues/{host},/changes/{host}(новые, исправленные и вернувшиеся ошибки),/indexing/{host},/market/{host}, профиль сайта (GET|PUT|DELETE /profile/{host}),GET /explain,POST /tasks/{id}/recheck,POST /analyzeиPOST /crawl/{host}(задания),GET /jobs,POST /webhooks,DELETE /webhooks/{id},POST /webhooks/{id}/rotate-secret,GET /capabilities. Общее: каталог ошибок, постраничность,Idempotency-Key,ETag,X-API-Version, JSON-ошибки при сбое и обслуживании, имена CLI и MCP. - 117:
data_state,data_confidence,data_age,data_reasonвGET /providers. - 64–72: диагноз, динамика, трафик, конкуренты, соцсети, JS, реестр провайдеров; ключи с правами, лимит, журнал, вебхуки с подписью V2.
Ограничения
Поля plain и guide в GET /explain — на русском (подсказка hint на двух языках, параметр lang). Отчёты, история и обход по домену общие для всех пользователей и читаются любым ключом; обзор, план, индексация, рынок, профиль и задания — только владельца. GET /market/{host} требует подключённых данных Ahrefs или Semrush. POST /analyze и POST /crawl/{host} выполняются воркером (bin/worker.php) либо при обращении; ход — в GET /jobs/{id}. Перепроверка задач ограничена суточным лимитом тарифа.