API и эндпоинты

Site Connector Protocol v1.0 · OpenAPI docs/openapi/site-connector-v1.yaml · Partner Admin API v1 northbound к агенту

Агент не говорит на диалектах Woo/Shopify/Bitrix. CMS-плагин или ваш бэкенд реализуют единый southbound-контракт. Ниже — версии, auth, эндпоинты с примерами запросов и ответов.

Версии

КонтрактВерсияГде смотреть
Site Connector Protocol1.0 (contractVersion)Поле в GET /health; OpenAPI info.version = "1.0"
Partner Admin APIv1Префикс пути /v1/partner/projects/:projectId/…

Breaking-изменения southbound → новая major в пути/контракте (например v2). Пока агент ждёт ровно contractVersion: "1.0". Legacy-ответ { "ok": true, "version": "1.0" } принимается как алиас.

Site Connector — базовый URL и auth

Рекомендуемый суффикс: https://your-site.example/seo-agent/v1

Авторизация сервер↔сервер (ключ не в браузер / Embed):

Authorization: Bearer <connector-key>
# или
X-Api-Key: <connector-key>
# кабинет агента также использует
x-seo-agent-key: sea_...

Опционально на мутациях: Idempotency-Key, dry-run X-Dry-Run: 1.

Ошибки (общая форма)

{
  "error": {
    "code": "FORBIDDEN_CAPABILITY | VALIDATION | NOT_FOUND | RATE_LIMIT",
    "message": "Human-readable detail"
  }
}

Обязательный минимум (L1 observe + meta)

GET/healthcontract 1.0

Жив ли bridge и какая версия контракта.

Ответ 200

{
  "ok": true,
  "contractVersion": "1.0",
  "platformVersion": "wp-plugin/1.2.0",
  "detail": "optional"
}
GET/capabilities

Объявляйте только то, что реально работает — иначе миссии уйдут в failed. L2/Tilda не должны светить write-capabilities без поддержки.

Enum: listUrls, getPage, updateSeoMeta, upsertContent, upsertFile, publish, createRedirect, sitemapRegen, rollback, healthcheck.

resourceKinds: page | post | product | category.

Ответ 200

{
  "capabilities": [
    "listUrls",
    "getPage",
    "updateSeoMeta",
    "upsertContent",
    "publish",
    "createRedirect",
    "sitemapRegen",
    "rollback",
    "healthcheck"
  ],
  "resourceKinds": ["page", "post", "product"]
}
GET/urls?cursor=&limit=100

Список индексируемых ресурсов. Пагинация через next_cursor (nullable).

Ответ 200

{
  "items": [
    {
      "id": "page_1",
      "url": "https://example.com/a",
      "kind": "page",
      "locale": "ru",
      "updatedAt": "2026-08-16T12:00:00.000Z"
    },
    {
      "id": "product:12",
      "url": "https://example.com/p/12",
      "kind": "product"
    }
  ],
  "next_cursor": null
}
GET/pages/{id} · GET/pages?url=

Карточка ресурса. Обязательны id, url, seo. commerce — только для магазинов; цены как decimal-строки «как на сайте».

Ответ 200

{
  "id": "product:12",
  "url": "https://example.com/p/12",
  "kind": "product",
  "locale": "ru",
  "seo": {
    "title": "Тормозные колодки BP-1",
    "description": "Оригинал, доставка по РФ",
    "canonical": "https://example.com/p/12",
    "robots": "index,follow",
    "h1": "Тормозные колодки"
  },
  "content": {
    "format": "html",
    "body": "<p>…</p>"
  },
  "commerce": {
    "offer": {
      "source": "connector",
      "name": "Brake pads",
      "price": "1990.00",
      "priceCurrency": "RUB",
      "availability": "InStock",
      "sku": "BP-1",
      "fetchedAt": "2026-08-16T12:00:00.000Z"
    }
  },
  "locked": false
}
PATCH/pages/{id}/seo

Live SEO-поля (title / description / canonical / robots / h1). Тело — частичный SeoMeta. Без capability updateSeoMeta проект остаётся observe-only. Контент тела страницы — через POST /contents, не сюда.

Запрос

PATCH /pages/product:12/seo
Content-Type: application/json

{
  "title": "Тормозные колодки BP-1 — купить",
  "description": "Доставка по РФ, гарантия"
}

Ответ 200

{
  "ok": true,
  "diff": {
    "before": {
      "title": "Тормозные колодки BP-1",
      "description": "Оригинал, доставка по РФ",
      "canonical": "https://example.com/p/12",
      "robots": "index,follow",
      "h1": "Тормозные колодки"
    },
    "after": {
      "title": "Тормозные колодки BP-1 — купить",
      "description": "Доставка по РФ, гарантия",
      "canonical": "https://example.com/p/12",
      "robots": "index,follow",
      "h1": "Тормозные колодки"
    }
  }
}
POST/contents

Upsert черновика/контента. L1 обязан поддерживать status: "draft". Запись цены/остатков — вне scope v1.0.

Запрос (предпочтительный)

{
  "url": "https://example.com/blog/new",
  "locale": "ru",
  "title": "Как выбрать колодки",
  "body_html": "<p>…</p>",
  "status": "draft"
}

Алиас (старые GenericHttp-клиенты)

{
  "url": "https://example.com/blog/new",
  "title": "Как выбрать колодки",
  "status": "draft",
  "content": { "format": "html", "body": "<p>…</p>" }
}

Ответ 200

{
  "ok": true,
  "id": "post:88",
  "url": "https://example.com/blog/new",
  "status": "draft"
}

SHOULD-эндпоинты (по возможности)

МетодПутьНазначение
POST/redirects{ "from", "to", "code" }
PUT/robotsтекст robots.txt
POST/sitemap/regenпересборка sitemap
POST/actions/dry-run / /actions/applygeneric dry-run / apply
POST/actions/{id}/rollbackоткат
GET/pages/{id}/previewURL превью

Partner Admin API (v1)

Northbound: ваша админка → SEO Agent. База: https://<seo-agent-host>/v1/partner/projects/{projectId}/…

Auth: заголовок x-seo-agent-key: sea_… (проектный ключ партнёра).

POST/v1/partner/projects/{projectId}/embed-session

Короткоживущий URL для iframe Центра управления (Embed Kit).

Запрос

POST /v1/partner/projects/prj_01H…/embed-session
x-seo-agent-key: sea_live_…
Content-Type: application/json

{}

Ответ 200 (поля могут дополняться; TTL из EMBED_SSO_TTL_SEC, по умолчанию ~1800 с)

{
  "url": "https://52525.ru/aita/app/embed?token=eyJ…",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
  "expiresIn": 1800
}

Остальные Partner-методы (stats, keywords, webhooks, badges) — в инженерной доке репозитория; публичный минимум для встройки — embed-session + Site Connector на стороне сайта.

Beacon collect (счётчик сайта)

Публичный эндпоинт для first-party аналитики. Ключ bea_… выпускается в кабинете (Подключение → Счётчик сайта). Не путать с Partner API sea_…. Подробнее: документация beacon.

POST/v1/collect

Приём pageview-событий со страниц сайта. CORS *, ответ 202 Accepted. Worker агрегирует в журнал для AI-советника.

POST /v1/collect
X-Seo-Beacon-Key: bea_live_…
Content-Type: application/json

{
  "projectId": "prj_…",
  "visitorId": "v_…",
  "sessionId": "s_…",
  "events": [
    {
      "name": "pageview",
      "path": "/catalog",
      "title": "Каталог",
      "referrer": "https://yandex.ru/…"
    }
  ]
}

Сниппет для сайта (без ручного вызова API): …/embed/seo-beacon.js с атрибутами data-project, data-key, data-api.

GET/projects/{projectId}/beacon

Статус счётчика и шаблон сниппета (JWT кабинета). Ключ полностью возвращается только при POST …/beacon/regenerate.

Соответствие port → HTTP

PortHTTP
healthcheckGET /health
capabilitiesGET /capabilities
listUrlsGET /urls
getPageGET /pages/{id}
updateSeoMetaPATCH /pages/{id}/seo
upsertContentPOST /contents

Типовой сценарий

  1. Поднять /health с contractVersion: "1.0" и /capabilities на staging.
  2. В кабинете: проект → Подключение → Generic HTTP (baseUrl + секрет).
  3. «Проверить связь» в UI.
  4. Ручной PATCH …/seo на одной странице → смотрите diff.
  5. Включить авто meta-теги только после проверки. CMS-гайды: коннекторы, старт, Embed Kit.