Каталог API по RFC 9727: публикуем /.well-known/api-catalog
Лишь у 4 из 74 API-провайдеров настоящий каталог RFC 9727. Опубликуйте /.well-known/api-catalog как application/linkset+json, свяжите OpenAPI, проверьте в curl.

Каталог API по RFC 9727 — это один JSON-файл по адресу /.well-known/api-catalog с типом application/linkset+json, который перечисляет ваши публичные API и для каждого даёт ссылку на машиночитаемое описание, чаще всего на документ OpenAPI. Инструмент или ИИ-агент, которому известен только ваш домен, может запросить этот файл, пройти по ссылке service-desc и понять, что можно вызывать, не разбирая сайт с документацией. RFC 9727 — документ Standards Track, опубликованный в июне 2025 года (IETF RFC 9727).
В стеке готовности это шаг обнаружения для API. Он стоит выше файла OpenAPI и ниже «вызываемых» карточек из статьи как сделать сайт вызываемым для агентов и использует ту же механику, что и заголовки Link и sitemap: well-known URL плюс HTTP-заголовок, который на него указывает. Публикация занимает минут пятнадцать, если ваш файл OpenAPI уже общедоступен. Именно на этом «если» тихо ломается большинство каталогов.
Ключевые выводы
- RFC 9727 регистрирует well-known URI и тип связи
api-catalog. Каталог обязан (MUST) бытьapplication/linkset+jsonи ссылаться на эндпоинты API; параметрprofileи ссылки на OpenAPI — это SHOULD и RECOMMENDED (RFC 9727).- Каталог полезен ровно настолько, насколько полезен ресурс, на который указывает его
service-desc. Если этот URL закрыт, отдаёт 404, HTML-страницу или невалидный JSON, агент ничего не узнает.- Публикующая сторона SHALL отвечать и на HEAD, и на GET по
/.well-known/api-catalog, причём ответ на HEAD несёт заголовокLink. Часть роутеров отвечает только на GET. Наш так и делал, пока я не проверил его для этой статьи.- Внедрение пока на ранней стадии. Одна независимая проверка в мае 2026 года нашла настоящий каталог у 4 из 74 API-провайдеров, а 68 вернули 200 с HTML-страницей (API Evangelist). Это выборка одного автора, а не перепись.
- Проверка
api_catalogв aiSiteReady засчитывается, только если валидный каталог ведёт к валидному документу OpenAPI или JSON Schema. Просканируйте свой домен, чтобы увидеть, на каком шаге цепочка рвётся.
Что определяет RFC 9727?
RFC 9727 определяет предсказуемое место, где можно спросить: «Какие API публикует этот хост?» Он регистрирует well-known URI api-catalog и тип связи api-catalog и требует, чтобы документ за ними был Linkset — форматом из RFC 9264. Linkset — это самостоятельный документ из типизированных ссылок, у каждой из которых есть контекст (anchor), тип связи и цель.
Где живут сами API, RFC 9727 не диктует. Расположение документа каталога выбирает публикующая сторона, а /.well-known/api-catalog — лишь удобная ссылка на него (RFC 9727, раздел 2).
Основной нормативный текст умещается в одну таблицу.
| Требование | Уровень | RFC 9727 |
|---|---|---|
Отвечать на HTTPS GET по /.well-known/api-catalog каталогом | SHALL | раздел 2 |
Отвечать на HTTPS HEAD заголовком Link с типом связи из раздела 3 | SHALL | раздел 2 |
Публиковать каталог как application/linkset+json | MUST | разделы 4.2, 6.2 |
Добавлять profile="https://www.rfc-editor.org/info/rfc9727" | SHOULD | раздел 4.2 |
| Включать гиперссылки на эндпоинты API | MUST | раздел 4.1 |
| Добавлять метаданные: политики использования, версии, ссылки на OpenAPI | RECOMMENDED | раздел 4.1 |
| Отдавать каталог только по HTTPS | SHOULD | раздел 8 |
| Ограничивать частоту запросов к каталогу | RECOMMENDED | раздел 8 |
| Проверить каталог на утечки внутренних или чувствительных данных | SHOULD | раздел 8 |
Два правила легко пропустить. Если вы уже перечисляете свои API в другом формате, но хотите занять этот URI, вы обязаны (MUST) дополнительно отдавать Linkset, а свой формат можете (MAY) возвращать через content negotiation. И каталог может ссылаться на другие каталоги через тип связи api-catalog — так большой набор API делят между доменами (разделы 4.2, 4.3 и 5.1).
Как выглядит минимальный каталог API?
Минимальный каталог — это один JSON-объект с массивом linkset, в котором одна запись про ваш API. Вот весь обмен для одного API на example.com.
GET /.well-known/api-catalog HTTP/1.1
Host: example.com
Accept: application/linkset+json
HTTP/1.1 200 OK
Content-Type: application/linkset+json; profile="https://www.rfc-editor.org/info/rfc9727"
Cache-Control: public, max-age=3600
{
"linkset": [
{
"anchor": "https://api.example.com/v1",
"service-desc": [
{
"href": "https://api.example.com/v1/openapi.json",
"type": "application/json"
}
],
"service-doc": [
{ "href": "https://api.example.com/docs", "type": "text/html" }
],
"item": [
{ "href": "https://api.example.com/v1/orders" }
]
}
]
}
Форма — это JSON-сериализация из RFC 9264: у объекта верхнего уровня единственный член linkset, и его значение — массив, даже если запись одна. У каждой записи есть необязательный anchor и по одному массиву на каждый тип связи. Каждой цели нужен href (RFC 9264, раздел 4.2). Тот же RFC рекомендует всегда указывать явный абсолютный anchor, чтобы документ оставался понятным, если его вынули из HTTP-ответа.
Всю работу делают названия связей. service-desc ведёт на машиночитаемое описание API, обычно файл OpenAPI, а service-doc — на документацию для людей. Оба типа связи, как и service-meta, пришли из RFC 8631, а item помечает цель, которая сама является API-членом каталога (RFC 9727, раздел 3.1).
| Член | Что узнаёт клиент | Правило |
|---|---|---|
linkset | Набор ссылок; всегда массив записей | Обязан (MUST) быть единственным членом верхнего уровня |
anchor | О каком ресурсе ссылки, здесь — об API | Может (MAY) отсутствовать; не следует (SHOULD NOT) делать относительным |
service-desc | Машиночитаемое описание, обычно OpenAPI | Тип связи из RFC 8631 |
service-doc | Документация для людей | Тип связи из RFC 8631 |
service-meta | Машиночитаемые метаданные: политики, метки | Тип связи из RFC 8631 |
item | API-член каталога, сам эндпоинт | RFC 9727, раздел 3.1 |
href | URL цели | Обязан (MUST) присутствовать; не следует (SHOULD NOT) делать относительным |
type | Необязательная подсказка о типе содержимого цели | Необязательный атрибут цели |
Как перечислить несколько API и выбрать нужные связи?
Добавьте по одной записи на каждый API, привяжите её к базовому URL этого API и укажите те связи, что у него есть. Полный каталог из трёх записей выглядит так. Первый API публикует всё, второй отдаёт спецификацию и в YAML, и в JSON, а третья запись указывает на каталог партнёра.
{
"linkset": [
{
"anchor": "https://api.example.com/orders/v2",
"service-desc": [
{ "href": "https://api.example.com/orders/v2/openapi.json", "type": "application/json" }
],
"service-doc": [
{ "href": "https://developer.example.com/orders", "type": "text/html" }
],
"service-meta": [
{ "href": "https://developer.example.com/orders/policies.json", "type": "application/json" }
],
"status": [
{ "href": "https://api.example.com/orders/v2/health", "type": "application/json" }
],
"item": [
{ "href": "https://api.example.com/orders/v2" }
]
},
{
"anchor": "https://api.example.com/inventory/v1",
"service-desc": [
{ "href": "https://api.example.com/inventory/v1/openapi.yaml", "type": "application/yaml" },
{ "href": "https://api.example.com/inventory/v1/openapi.json", "type": "application/json" }
],
"service-doc": [
{ "href": "https://developer.example.com/inventory", "type": "text/html" }
],
"item": [
{ "href": "https://api.example.com/inventory/v1" }
]
},
{
"anchor": "https://www.example.com/.well-known/api-catalog",
"api-catalog": [
{ "href": "https://partners.example.com/.well-known/api-catalog" }
]
}
]
}
В собственных примерах RFC 9727 показаны два основных паттерна. В одном каждая запись привязана к API и несёт service-desc, service-doc, service-meta и status. В другом anchor — это URL каталога, а каждый API — закладка item (RFC 9727, приложение A). Это иллюстрации, а не альтернативы, между которыми нужно выбирать. Я их совмещаю: записи по каждому API, привязанные к самому API, плюс ссылка item, чтобы требование «ссылки на эндпоинты API» выполнялось самым прямым способом.
status — тип связи для ресурса со статусом или состоянием сервиса (health check), он тоже из RFC 8631. А service-meta берите для всего, что машине стоит знать о сервисе помимо спецификации: политик, меток.
Как клиенты находят /.well-known/api-catalog?
Двумя способами: запрашивают /.well-known/api-catalog напрямую или читают заголовок Link с rel="api-catalog" на странице, которую вы и так отдаёте. RFC 9727 допускает тип связи в HTTP-заголовке, в содержимом или в обоих местах сразу, а целью может быть и well-known URI, и любой другой URI на выбор публикующей стороны (раздел 3). Синтаксис заголовка — обычный веб-линкинг по RFC 8288 (RFC 8288).
Именно такой заголовок сегодня отдаёт главная страница aiSiteReady — одна связь из четырёх ссылок обнаружения. Цель относительная, поэтому заголовок остаётся верным на любом домене развёртывания.
GET / HTTP/1.1
Host: www.ai-siteready.com
Accept: text/html
HTTP/2 200
content-type: text/html;charset=utf-8
link: </sitemap.xml>; rel="sitemap", </llms.txt>; rel="describedby", </site.webmanifest>; rel="manifest", </.well-known/api-catalog>; rel="api-catalog"
В примере самого RFC 9727 каталог объявлен заголовком Link и элементом a с rel="api-catalog". Наш сканер читает только HTTP-заголовок корневой страницы, а не HTML-теги, поэтому заголовок надёжнее. Синтаксис подробнее разобран в руководстве по заголовкам Link.
Как отдавать /.well-known/api-catalog?
Возвращайте JSON с правильным Content-Type и на GET, и на HEAD, только по HTTPS. Вот настоящий маршрут из Nuxt-сервера aiSiteReady (Nitro), сокращённый до важных строк. Чистый билдер собирает JSON, а обработчик выставляет три заголовка, включая Link, которого требует раздел 2. Раньше этот маршрут отвечал только на GET; к этому изъяну я вернусь ниже.
// frontend/server/routes/.well-known/api-catalog.ts (фрагмент)
export default defineReadOnlyHandler((event) => {
const config = useRuntimeConfig(event);
const siteUrl = typeof config.public.siteUrl === "string" ? config.public.siteUrl : "";
setResponseHeader(event, "Content-Type", API_CATALOG_CONTENT_TYPE);
setResponseHeader(event, "Link", buildApiCatalogLinkHeader()); // </.well-known/api-catalog>; rel="api-catalog"
setResponseHeader(event, "Cache-Control", "public, max-age=3600");
return buildApiCatalog({ siteUrl });
});
defineReadOnlyHandler — наша небольшая обёртка: она запускает один и тот же обработчик для GET и HEAD, на HEAD отдаёт пустое тело с тем Content-Length, что был бы у GET, а на остальные методы отвечает 405. Content-Type берётся из одной константы: media type linkset, charset=utf-8 и профиль RFC 9727. charset — наша привычка, а не требование, и сканер его принимает. То же самое на Express короче, и Express сам отвечает на HEAD из маршрута GET (документация Express).
app.get('/.well-known/api-catalog', (req, res) => {
res
.set('Content-Type', 'application/linkset+json; profile="https://www.rfc-editor.org/info/rfc9727"')
.set('Cache-Control', 'public, max-age=3600')
.set('Link', '</.well-known/api-catalog>; rel="api-catalog"')
.send(JSON.stringify(CATALOG, null, 2));
});
Я запустил именно этот обработчик локально: GET и HEAD вернули одинаковые заголовки. Побочный эффект: res.send() со строковым телом дописывает к Content-Type параметр charset=utf-8, который таблица ниже называет лишним. RFC не показывает полный обмен для HEAD; разумное прочтение раздела 2 — заголовок Link с rel="api-catalog", который как раз и шлёт этот обработчик. Эти детали HTTP лучше решить до релиза.
| Деталь | Что делать | Основание |
|---|---|---|
Content-Type | application/linkset+json и параметр profile | MUST и SHOULD из раздела 4.2; RFC 9264 регистрирует profile единственным необязательным параметром, так что charset не нужен (UTF-8 обязателен) |
GET | 200 и тело каталога | SHALL, раздел 2 |
HEAD | 200, те же заголовки, что у GET, и заголовок Link | SHALL, раздел 2; RFC 9110 говорит, что сервер SHOULD слать те же заголовки |
Cache-Control | Короткий публичный TTL; у нас час | RFC лишь советует кэширование и сжатие для больших каталогов |
| CORS | Серверным агентам не нужен; * разрешайте, только если каталог должен читать браузерный код | Моя рекомендация; RFC упоминает CORS только для внутренних каталогов |
| TLS | Только HTTPS | SHOULD, раздел 8 |
| Неизвестные пути | Настоящий 404, а не HTML-страница с 200 | См. ошибки ниже |
| Другие домены | Редиректить их well-known URL на канонический каталог | RECOMMENDED, раздел 5.1 |
Как каталог связан с OpenAPI, MCP Server Card и Agent Skills?
Они отвечают на разные вопросы, и ни один не заменяет другой. Каталог говорит, какие API существуют и где лежат их описания. OpenAPI описывает один HTTP API. MCP Server Card говорит, как подключиться к MCP-серверу. Навык (skill) объясняет, как хорошо пользоваться вашим продуктом.
| Слой | На какой вопрос отвечает | Где живёт | Статус на октябрь 2026 |
|---|---|---|---|
| Каталог API | Какие API публикует этот хост? | /.well-known/api-catalog | RFC 9727, июнь 2025 |
| OpenAPI | Какие операции и схемы у одного API? | Цель service-desc | Спецификация v3.2.1, 10 сентября 2026 |
| MCP Server Card | Как подключиться к этому MCP-серверу? | Любой URI на выбор публикующей стороны | Экспериментальный репозиторий |
| Agent Skills | Как агенту пользоваться этим продуктом? | /.well-known/agent-skills/index.json | Discovery RFC помечен как черновик |
OpenAPI допускает документ и в JSON, и в YAML и рекомендует называть главный документ openapi.json или openapi.yaml (OpenAPI Specification v3.2.1). Каталог на него просто ссылается.
Что до MCP: экспериментальный репозиторий Server Card в README пишет, что это прототипная работа, а не принятое или официальное расширение MCP, и что клиенты находят карточки через записи AI Catalog. RFC 9727 там не упоминается, так что не ждите, что запись в api-catalog объявит MCP-сервер (экспериментальный репозиторий server-card, AI Catalog). Публикуйте карточку отдельно: где именно, разбирает материал MCP Server Card: что это и как опубликовать.
Agent Skills — ещё один слой. Навык — это папка с файлом SKILL.md с инструкциями (спецификация Agent Skills), а веб-индекс для него пока черновик (discovery RFC от Cloudflare). Вместе они сочетаются хорошо: SKILL.md самого aiSiteReady подсказывает агентам, где лежат файл OpenAPI, интерактивная документация и каталог. Формат индекса показывает руководство по Agent Skills.
Какие ошибки ломают каталог API?
Почти все они — один и тот же сбой в разных обличьях: каталог разбирается, но никуда не ведёт или нарушает правила формы.
| Ошибка | Что происходит | Исправление |
|---|---|---|
Content-Type: application/json | Нарушает MUST; наша проверка сообщает api_catalog_not_linkset, если до валидной спецификации не дошли | Отдавайте application/linkset+json с profile |
SPA-заглушка возвращает HTML с 200 по этому пути | Парсеры спотыкаются; сканирование не видит каталога (api_catalog_missing) или сообщает api_catalog_html_response, если HTML спрятан под JSON-типом | Возвращайте 404 на неизвестные пути и исключите /.well-known/ из fallback |
Цель service-desc закрыта, отдаёт 404 или требует логин | Каталог никуда не ведёт | Опубликуйте спецификацию по публичному URL и проверьте без cookie |
| Обратный прокси не пропускает путь к спецификации | Стандартный /openapi.json FastAPI уходит на фронтенд и даёт 404 | Перенесите спецификацию под путь, который прокси пропускает |
| Объект там, где нужен массив | "service-desc": { "href": "..." } нарушает RFC 9264 | Оборачивайте цели каждой связи в массив |
Относительный href или anchor | Ссылка теряет контекст при копировании; RFC 9264: SHOULD NOT | Стройте абсолютные URL от канонического origin |
| OpenAPI только в YAML | Наша проверка читает только JSON и сообщает api_catalog_documents_invalid_json | Публикуйте ещё и openapi.json |
GET работает, HEAD даёт 404 | Нарушает SHALL из раздела 2 | Маршрутизируйте оба метода |
| В спецификации или каталоге внутренние API | RFC просит проверку перед развёртыванием | Проведите аудит; фреймворки часто выводят все маршруты |
У правила про массивы есть сноска, о которой полезно знать. В примере из RFC 9727, раздел 5.1, "api-catalog": "https://..." записано простой строкой. Поданный к RFC erratum (ID 9009, статус «Reported», не подтверждён) утверждает, что там должен быть массив с объектом ссылки, как требует RFC 9264 (RFC Editor errata). Следуйте форме из RFC 9264.
Чему меня научил собственный каталог aiSiteReady?
Каталог был самой лёгкой частью. Проверка api_catalog уже существовала, когда я выпустил собственный каталог aiSiteReady; трудным оказалось сделать достижимым файл, на который он ссылается. Билдер лежит в frontend/src/shared/lib/seo/api-catalog.ts и выдаёт одну запись с anchor /api/v1, с service-desc на /api/v1/openapi.json, service-doc на /api/v1/docs и item на /api/v1/scans.
FastAPI по умолчанию отдаёт /openapi.json и /docs. В проде наш nginx направляет на бэкенд только /api/* (и /health), а всё остальное — на фронтенд Nuxt, так что значения по умолчанию уходили на фронтенд и давали 404. Решением стало перенести их через openapi_url="/api/v1/openapi.json" и docs_url="/api/v1/docs": это меняет только адреса, а не содержимое схемы.
Менять nginx не пришлось: существующий блок location /api/ в deploy/nginx/default.conf уже пропускает оба адреса. Строку Content-Security-Policy я оставил во фрагменте, потому что она важна для страницы документации ниже.
# сокращено из deploy/nginx/default.conf
location /api/ {
add_header Content-Security-Policy "default-src 'none'; style-src 'unsafe-inline'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'" always;
proxy_pass http://fastapi_backend/api/;
}
Проверка 2 октября 2026 года: прод отдаёт каталог с application/linkset+json; charset=utf-8; profile="https://www.rfc-editor.org/info/rfc9727", а спецификация по /api/v1/openapi.json возвращает 200 как application/json. Старый корневой /openapi.json возвращает 404, как и задумано.
Проверяя собственный сайт для этой статьи, я нашёл один новый изъян, а один известный снова вернул в свой список.
Новым был HEAD. 2 октября 2026 года curl -I по /.well-known/api-catalog возвращал 404. Файл маршрута оканчивался на .get.ts, а такой маршрут Nitro привязывает к GET, и запасного пути для HEAD у его роутера нет; маршруты sitemap.xml и llms.txt без суффикса отвечали на HEAD кодом 200. Это нарушало SHALL из раздела 2, а наш сканер HEAD пока не проверяет, так что сам этого не заметил. Исправление — маршрут выше: файл без суффикса, один обработчик для GET и HEAD и заголовок Link. Остальные .well-known-документы получили то же изменение.
Известный — страница документации. /api/v1/docs возвращает 200, но страница в браузере пустая. Content-Security-Policy на ответах /api/ начинается с default-src 'none', а это блокирует CDN-скрипты, нужные Swagger UI. Наша проверка проходит, если хотя бы один связанный документ — валидный OpenAPI, поэтому на пустую страницу натыкается человек, который переходит по service-doc. Он на момент написания не исправлен.
Как проверить каталог с помощью curl?
Запросите его так, как это сделал бы агент, проверьте статус и Content-Type, затем пройдите по service-desc и убедитесь, что спецификация разбирается. Запускайте проверку по публичному домену, а не по localhost: большинство поломок живёт в слое прокси и CDN.
# GET: ждём 200 и application/linkset+json с параметром profile
curl -sS -D - -o /dev/null -H 'Accept: application/linkset+json' https://example.com/.well-known/api-catalog
# HEAD: ждём 200 и заголовок Link с rel="api-catalog"
curl -sSI https://example.com/.well-known/api-catalog
# Идём по service-desc и проверяем, что это похоже на OpenAPI
curl -sS https://example.com/.well-known/api-catalog | jq -r '.linkset[]."service-desc"[]?.href'
curl -sSL https://api.example.com/v1/openapi.json | jq '{openapi, title: .info.title, paths: (.paths | length)}'
Первая команда должна напечатать строку статуса 200 и заголовок content-type: application/linkset+json; profile="https://www.rfc-editor.org/info/rfc9727". Последняя — версию OpenAPI, название API и ненулевое число путей. Встройте те же проверки в CI, чтобы деплой не мог незаметно сломать обнаружение.
#!/usr/bin/env bash
set -euo pipefail
SITE="${1:?usage: check-catalog.sh https://example.com}"
CAT="$SITE/.well-known/api-catalog"
H="$(curl -sS -D - -o /dev/null -H 'Accept: application/linkset+json' "$CAT")"
grep -qiE '^HTTP/[0-9.]+ 200' <<<"$H" || { echo 'FAIL: GET is not 200'; exit 1; }
grep -qi '^content-type: application/linkset+json' <<<"$H" || { echo 'FAIL: Content-Type'; exit 1; }
grep -qi 'profile="https://www.rfc-editor.org/info/rfc9727"' <<<"$H" || echo 'WARN: no RFC 9727 profile'
HH="$(curl -sS -I "$CAT")"
grep -qiE '^HTTP/[0-9.]+ 200' <<<"$HH" || echo 'WARN: HEAD is not 200'
grep -qi '^link:.*rel="\?api-catalog' <<<"$HH" || echo 'WARN: HEAD has no Link rel=api-catalog'
curl -sS "$CAT" | jq -r '.linkset[]."service-desc"[]?.href' | while read -r SPEC; do
curl -sSfL "$SPEC" | jq -e '(.openapi|type=="string") and (.info|type=="object") and (.paths|type=="object" and length>0)' >/dev/null \
&& echo "OK: $SPEC" || { echo "FAIL: $SPEC is not valid OpenAPI JSON"; exit 1; }
done
Я запустил этот скрипт на aiSiteReady 2 октября 2026 года: он вывел два предупреждения про HEAD из изъяна выше, а затем OK для спецификации. На чистом сайте выводятся только строки OK.
Как сканировать /.well-known/api-catalog при каждом релизе?
Один раз сделать это руками нормально. Делать это на каждом релизе и по другим протокольным слоям — как раз работа для сканирования. Проверка api_catalog в aiSiteReady работает внутри категории Protocol/API. Она запрашивает /.well-known/api-catalog и любой заголовок Link с rel="api-catalog" на корневой странице — всё через SSRF-безопасный загрузчик, — а затем проверяет не более пяти связанных документов описания, начиная с service-desc.
Каталог считается валидным, если даёт хотя бы одну ссылку, а сканирование отдельно фиксирует, отдан ли он как application/linkset+json и несёт ли профиль RFC 9727. Описание считается валидным, если это документ OpenAPI со строкой версии, объектом info и непустым объектом paths, либо JSON Schema со структурным ключевым словом. Каждое сканирование заканчивается одним из четырёх статусов.
| Статус | Когда |
|---|---|
| PASS | Валидный каталог ведёт хотя бы к одному валидному документу OpenAPI или JSON Schema |
| PARTIAL | Каталог есть, но это не linkset или он ведёт к невалидным документам; по пути отдаётся HTML-страница под не-HTML типом содержимого; либо заголовок Link указывает на каталог, который не удаётся загрузить |
| FAIL | Ничего не найдено ни по well-known пути, ни в заголовке Link, или по пути отдаётся только страница text/html |
| UNKNOWN | Запрос заблокирован или не уложился в таймаут; 403 и 429 попадают сюда, а не в FAIL |
Сегодня формат linkset фиксируется как сигнал и не влияет на PASS: каталог в обычном JSON, который ведёт к валидному файлу OpenAPI, всё равно проходит. Не рассчитывайте на это, потому что он не соответствует стандарту. Для профиля Контентный сайт (content_site) проверка не запускается, а в профиле API/приложение (api_application) она весит в 1,75 раза больше, чем в профиле Все проверки (all). Все проверки и веса перечислены на странице методологии.
Встройте это в рутину вместе с аудитом готовности за 30 минут, а весь стек смотрите в материале что такое готовность к ИИ-агентам. Запустите бесплатное сканирование, чтобы увидеть, может ли агент пройти от вашего домена до валидного файла OpenAPI и какое исправление сделать первым, — на английском, украинском или русском.
Если коротко: опубликуйте один документ application/linkset+json по адресу /.well-known/api-catalog, свяжите файл OpenAPI каждого API через service-desc, отвечайте и на GET, и на HEAD и проверьте, что спецификация общедоступна. Каталог, который указывает в тупик, хуже, чем его отсутствие, потому что выглядит законченным.
У IMozz 20 лет в разработке ПО, а последний год он строит продукты с помощью LLM. Он развивает aiSiteReady, сканер только для чтения, который проверяет, может ли ИИ-агент прочитать и вызвать сайт. Сканер серверно рендерит собственный контент как рабочий пример.