API

Чтение страницы

Открывает страницу по ссылке и возвращает её текст в чистом markdown: без бокового меню, рекламных врезок, иконок и HTML. Нужен, когда агенту надо прочитать конкретную статью, страницу документации или карточку товара — а не искать информацию по теме.

POSThttps://srezai.ru/api/v1/read

Читать или увидеть

Этот эндпоинт отдаёт только текст и стоит 1 кредит за страницу. Если агенту нужно увидеть страницу — вёрстку, цвета, типографику, — берите скриншот страницы: он рендерит картинку и стоит 3 кредита.

Когда использовать#

  • Прочитать статью или страницу документации, ссылку на которую вы уже знаете (в том числе полученную из поиска).
  • Собрать контекст для RAG: чистый markdown ложится в индекс без собственного парсинга HTML и вычистки бойлерплейта.
  • Проверить факт на первоисточнике, когда сниппета поисковой выдачи недостаточно.

Если нужно найти информацию по теме, а не прочитать известную страницу — это веб-поиск: с excerpts: true он сразу вернёт текст топ-страниц под запрос одним вызовом вместо десяти отдельных чтений.

Пример запроса#

curl -X POST https://srezai.ru/api/v1/read \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer srz_live_ВАШ_КЛЮЧ" \
  -d '{ "url": "https://exa.ai/blog", "maxChars": 12000 }'

Параметры тела#

Тело запроса — JSON. Обязателен адрес страницы: либо url для одной, либо urls для батча.

urlstringrequired

Полный адрес страницы, схема http или https, порт 80 или 443. Адреса, ведущие во внутреннюю сеть (приватные IP, локальные имена), отклоняются с ошибкой 400 — см. ниже. Не нужен, если передан urls.

urlsstring[]optional

До 5 адресов вместо url: страницы читаются параллельно, ответ приходит массивом pages. См. Несколько страниц за раз.

maxCharsnumberoptional

Сколько символов текста вернуть: от 200 до 50000 (4000 по умолчанию). Для длинной документации и RAG ставьте с запасом. Значения вне диапазона подгоняются к границе.

enginestringoptional

Как забирать страницу: auto (по умолчанию), fast, dynamic, stealth — см. раздел ниже. Неизвестное значение молча трактуется как auto.

Движки и авто-эскалация#

Страницы устроены по-разному: статике и документации хватает обычного запроса, а SPA на React или Vue отдаёт пустой каркас, пока не выполнится JavaScript. Поэтому по умолчанию (engine: "auto") мы начинаем с самого быстрого способа и поднимаемся на ступень выше только если текста не оказалось.

  • autofastdynamic stealth, до первого осмысленного результата. Обычная страница обходится одной попыткой, сложная — двумя-тремя. Цена от числа попыток не зависит.
  • fast (~1–3 с) — без ожидания JavaScript: статические сайты, документация, блоги, новости.
  • dynamic (~3–8 с) — ждём затишья сети и отрисовки: для SPA и ленивой подгрузки контента.
  • stealth (~8–20 с) — максимально браузерное поведение: полная прокрутка страницы (чтобы сработала ленивая подгрузка) и закрытие куки-баннеров и модальных окон, перекрывающих текст. На страницах, которые и так отдают заглушку, auto делает последнюю попытку через второй, независимый браузерный движок.

В ответе приходит engine — ступень, на которой контент удалось взять, и meta.attempts — сколько ступеней было пройдено. Если у конкретного сайта attempts стабильно равен 2 или 3, передавайте нужный движок явно: запрос перестанет тратить время на заведомо неудачные попытки.

Несколько страниц за раз#

Вместо url можно передать urls — до 5 ссылок. Страницы читаются параллельно, поэтому пять адресов занимают примерно столько же, сколько самый медленный из них, а не сумму. Остальные параметры (maxChars, engine) применяются ко всем ссылкам батча.

json
{
  "urls": [
    "https://exa.ai/blog",
    "https://habr.com/ru/articles/1/",
    "https://example.com/404",
    "https://exa.ai/blog"
  ],
  "maxChars": 6000
}

Ответ — массив pages в порядке переданных ссылок. Успешная страница содержит те же поля, что и одиночный ответ; неудачная — только url, error и code. Одна упавшая ссылка не отменяет остальные: HTTP-статус остаётся 200.

json
{
  "pages": [
    {
      "url": "https://exa.ai/blog",
      "title": "Exa | Blog",
      "markdown": "# Exa Blog\n\nThe latest from the team…",
      "truncated": false,
      "engine": "fast",
      "meta": { "tookMs": 1840, "totalChars": 8213, "attempts": 1 }
    },
    {
      "url": "https://habr.com/ru/articles/1/",
      "title": "…",
      "markdown": "…",
      "truncated": true,
      "engine": "dynamic",
      "meta": { "tookMs": 4210, "totalChars": 19740, "attempts": 2 }
    },
    {
      "url": "https://example.com/404",
      "error": "Не удалось прочитать страницу. / Failed to read the page.",
      "code": "read_failed"
    }
  ],
  "meta": { "tookMs": 4380, "requested": 3, "succeeded": 2, "skipped": 1 }
}

Общий meta батча описывает, что вообще произошло со списком: requested — сколько ссылок пошло в работу, succeeded — сколько прочитано, skipped — сколько отброшено ещё до чтения как дубликаты. В примере выше skipped: 1 — второй раз переданный exa.ai/blog. Так по ответу видно судьбу каждой ссылки, без сверки своего списка с полученным.

  • Дубликаты в списке отбрасываются до запроса — за одну и ту же ссылку дважды платить не нужно; они попадают в meta.skipped.
  • Каждая страница тарифицируется отдельно (1 кредит) и отдельной строкой попадает в историю запросов.
  • maxChars здесь — лимит на каждую страницу. Пять страниц по 12000 символов — это 60000 символов в ответе; для батча обычно разумнее оставить значение по умолчанию.
  • Больше 5 ссылок за запрос вернут 400. Нужен объём — шлите несколько батчей с оглядкой на burst-лимит.

Ответ#

json
{
  "url": "https://exa.ai/blog",
  "title": "Exa | Blog",
  "markdown": "# Exa Blog\n\nThe latest from the team…",
  "truncated": false,
  "engine": "fast",
  "meta": {
    "tookMs": 1840,
    "totalChars": 8213,
    "attempts": 1
  }
}

Поля ответа#

urlstringoptional

Нормализованный адрес, который был прочитан.

titlestringoptional

Заголовок страницы (из <title>/метаданных), может быть пустым.

markdownstringoptional

Текст страницы, очищенный от навигации, иконок и служебной разметки, и обрезанный до maxChars.

truncatedbooleanoptional

true, если текст не поместился в maxChars — у страницы есть продолжение. Сколько всего дала страница, видно в meta.totalChars.

enginestringoptional

Ступень движка, которая дала результат: fast, dynamic или stealth.

metaobjectoptional

tookMs — общее время запроса, totalChars — объём чистого текста страницы до обрезки, attempts — сколько ступеней движка было пройдено.

Остаток лимита приходит в заголовках X-RateLimit-* — см. Лимиты и квоты. Вызов считается как один запрос к дневной квоте, наравне с поиском.

Через MCP: read_url и read_urls#

Тот же функционал доступен ИИ-агенту как встроенные инструменты MCP-сервера: read_url для одной страницы и read_urls для батча — с теми же параметрами maxChars и engine. Ответ — текстовый блок: заголовок страницы и её markdown; при обрезке добавляется явная пометка с полным объёмом текста, чтобы агент не принял начало страницы за всю страницу. В батче первая строка — итог («Обработано 2 из 3»), с отдельными строками про неудачи и про отброшенные дубликаты; дальше каждая страница идёт своим блоком с номером и адресом, а непрочитанные ссылки — блоком с кодом ошибки вида [read_failed].

Только публичные адреса

Чтение идёт с нашего сервера, поэтому запросы к внутренней сети запрещены: приватные диапазоны (10.x, 192.168.x, 127.x, 169.254.x), нестандартные порты и локальные имена отклоняются с 400 и кодом ssrf_blocked.

Только POST

Эндпоинт принимает только POST. Запрос методом GET вернёт 405 Method Not Allowed.