Поиск Яндекса через API: умный, пакетный, Brave и Tavily
Выдача Яндекса по одному HTTP-запросу: без своего каталога в Yandex Cloud, без белых IP и VPN. Один движок
доступен в трёх видах — Brave-совместимый GET, Tavily-совместимый POST и собственный пакетный формат,
который отдаёт всё, что присылает Яндекс: абсолютную позицию, doc_id, язык документа, дату изменения.
Все запросы — с ключом в заголовке Authorization: Bearer <ключ> (см. Аутентификация).
Полная схема параметров — в интерактивном справочнике proxy.seyka.ru/api-docs.
Эндпоинты
Заголовок раздела «Эндпоинты»| Эндпоинт | Формат | Что делает |
|---|---|---|
GET /v1/search/yandex |
Brave | Один запрос, параметры в query string, листание через offset |
POST /v1/search/yandex |
Tavily | Один запрос, тело в формате Tavily |
POST /v1/search/yandex/smart |
Пакетный | 1–50 запросов, ступень подбирается сама |
POST /v1/search/yandex/sync |
Пакетный | 1–50 запросов, всё, чего нет в кэше, — синхронно |
POST /v1/search/yandex/async |
Пакетный | 1–50 запросов в отложенном режиме, ответ 202 сразу |
GET /v1/search/yandex/async/{batchId} |
Пакетный | Забрать отложенный пакет — бесплатно |
DELETE /v1/search/yandex/cache |
Пакетный | Сбросить кэш по запросам — бесплатно |
DELETE /v1/search/yandex/cache/{batchId} |
— | Сбросить всё, что положил в кэш пакет, — бесплатно |
Тот же Tavily-совместимый поиск доступен по адресам POST /v1/tavily/search и POST /search — см.
Tavily-совместимый API.
Ступени и цена
Заголовок раздела «Ступени и цена»Один и тот же запрос можно обслужить тремя способами, и цена зависит от того, какой сработал:
| Ступень | Когда отвечает |
|---|---|
cache |
Такая выдача уже лежит в кэше и не устарела |
async |
Отложенный режим Яндекса: обычно отвечает примерно за секунду |
sync |
Синхронный запрос к Яндексу: самый дорогой, зато сразу |
Ставки ступеней — на странице Цены. Как они применяются:
- Умный поиск и совместимые эндпоинты (
POST /v1/search/yandex/smart,GET /v1/search/yandex,POST /v1/search/yandex) идут по ступеням сами: сначала кэш, затем отложенный режим, и только если он не ответил примерно за 5 секунд — синхронный запрос. Оплачивается одна ступень — та, что ответила: если отложенная попытка не успела, вы платите за синхронный запрос, а не за оба. POST /v1/search/yandex/syncобходит отложенный режим: запросы, которых нет в кэше, сразу идут синхронно.POST /v1/search/yandex/asyncтолько ставит запросы в отложенный режим и отвечает сразу. Цена фиксируется в момент отправки, результаты забираются бесплатнымGET.
Во всех случаях запрос, найденный в кэше, стоит как ответ из кэша. В умном и синхронном режимах одинаковые запросы внутри одного пакета уходят в Яндекс один раз — повторы считаются попаданием в кэш; в отложенном каждый повтор отправляется и оплачивается отдельно. В синхронном и умном режимах запрос, завершившийся ошибкой, не оплачивается; в отложенном оплата фиксируется при отправке и не возвращается, если запрос потом завершится ошибкой или истечёт. Кэш общий для всех клиентов: выдачу, которую уже получил кто-то другой, вы получите по цене кэша.
Заголовки стоимости
Заголовок раздела «Заголовки стоимости»Совместимые эндпоинты (GET/POST /v1/search/yandex, POST /v1/tavily/search, POST /search) сообщают
стоимость в заголовках:
| Заголовок | Пример | Значение |
|---|---|---|
X-Cost-Cents |
целое число | Сколько списано за запрос, в копейках |
X-Search-Source |
sync |
Самая дорогая ступень, которая участвовала: cache, async или sync |
X-Search-Rungs |
cache=1,sync=1 |
Из чего сложилась сумма, от дешёвой ступени к дорогой |
X-Search-Rungs нужен потому, что Яндекс отдаёт выдачу страницами по 100 результатов, и каждая страница —
отдельный оплачиваемый поиск. Запрос на 200 результатов, где первая сотня нашлась в кэше, а вторую
пришлось запросить синхронно, покажет X-Search-Source: sync и X-Search-Rungs: cache=1,sync=1.
Пакетные эндпоинты кладут ту же разбивку в тело ответа, в блок billing: cost_cents — итог в копейках,
breakdown — строки по ступеням (source, count, unit_cents, cost_cents), от дешёвой к дорогой.
Brave-совместимый GET
Заголовок раздела «Brave-совместимый GET»GET /v1/search/yandex принимает параметры Brave Search API
в query string и отвечает в его формате.
| Параметр | По умолчанию | Описание |
|---|---|---|
q |
— | Поисковый запрос, обязательный |
count |
10 |
Сколько результатов вернуть, 1–200. Больше 100 — это две страницы Яндекса и две оплаченные выборки |
offset |
0 |
Сдвиг в результатах (не в страницах), 0–100000 |
region |
— | Код региона Яндекса: 225 — Россия, 213 — Москва, 2 — Санкт-Петербург. Без него или 0 — регион по IP |
freshness |
— | Ограничение по времени: pd — сутки, pw — неделя, pm — месяц, py — год |
safesearch |
moderate |
off, moderate или strict |
country |
ru |
Метка страны в ответе; на поиск не влияет |
search_lang |
ru |
Подставляется в поле language результатов; на поиск не влияет |
ui_lang |
ru |
Принимается для совместимости, не используется |
curl "https://proxy.seyka.ru/v1/search/yandex?q=погода+москва&count=10®ion=213" \ -H "Authorization: Bearer $SEYKA_API_KEY"{ "type": "search", "query": { "original": "погода москва", "altered": "погода москва", "language": "ru", "country": "ru" }, "web": { "type": "search", "family_friendly": true, "results": [ { "title": "Погода в Москве на сегодня", "url": "https://example.ru/weather/moscow", "description": "Прогноз погоды в Москве…", "language": "ru", "family_friendly": true, "meta_url": { "…": "…" }, "extra_snippets": ["…"] } ] }}Ответ — только поля схемы Brave: позиции, doc_id, язык документа и остальные данные Яндекса в него не
попадают. Если они нужны, используйте пакетный формат.
Tavily-совместимый POST
Заголовок раздела «Tavily-совместимый POST»POST /v1/search/yandex принимает тело Tavily Search и отвечает в его формате.
| Поле | Описание |
|---|---|
query |
Поисковый запрос, обязательное |
max_results |
Сколько результатов вернуть, по умолчанию 10, не больше 200 |
region |
Код региона Яндекса, как в GET |
include_domains / exclude_domains |
Оставить или убрать домены (включая поддомены) |
search_depth |
Принимается для совместимости, ни на что не влияет |
Остальные поля Tavily (topic, include_answer, freshness и т. п.) принимаются и игнорируются — запрос не
ломается, но и эффекта нет. Ограничение по времени есть только в GET и пакетном формате.
curl -X POST "https://proxy.seyka.ru/v1/search/yandex" \ -H "Authorization: Bearer $SEYKA_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "лучшие рестораны москвы", "max_results": 5, "region": 213}'{ "query": "лучшие рестораны москвы", "results": [ { "title": "Лучшие рестораны Москвы — рейтинг", "url": "https://example.ru/restaurants", "content": "Рейтинг ресторанов Москвы по отзывам посетителей…", "score": 1 } ]}score выводится из порядка результатов (1.0 у первого, дальше по убыванию), а не из оценки релевантности:
Яндекс её не отдаёт.
Пакетный поиск
Заголовок раздела «Пакетный поиск»POST /v1/search/yandex/smart, POST /v1/search/yandex/sync и POST /v1/search/yandex/async принимают
одно и то же тело: от 1 до 50 запросов, общие параметры выносятся в defaults, каждый запрос может их
переопределить. Больше 50 запросов — ответ 413.
| Поле | Описание |
|---|---|
queries[].query |
Поисковый запрос, обязательное |
queries[].max_results |
1–200, по умолчанию 10. Больше 100 — две страницы и две оплаченные выборки |
queries[].region |
Код региона Яндекса |
queries[].freshness |
pd, pw, pm или py |
queries[].safesearch |
off, moderate или strict |
queries[].include_domains / exclude_domains |
Фильтр доменов; задаётся только у запроса, не в defaults |
defaults |
region, max_results, freshness, safesearch для всех запросов пакета |
cache_ttl |
Максимальный возраст выдачи из кэша и срок хранения новой, в секундах. По умолчанию 86400 (24 часа), потолок — 30 дней, 0 — не брать из кэша |
language / country |
Метки в ответе; на поиск не влияют |
curl -X POST "https://proxy.seyka.ru/v1/search/yandex/smart" \ -H "Authorization: Bearer $SEYKA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "queries": [ { "query": "ремонт квартир" }, { "query": "натяжные потолки", "max_results": 50 } ], "defaults": { "region": 213, "max_results": 20 } }'const res = await fetch('https://proxy.seyka.ru/v1/search/yandex/smart', { method: 'POST', headers: { Authorization: `Bearer ${process.env.SEYKA_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ queries: [{ query: 'ремонт квартир' }, { query: 'натяжные потолки' }], defaults: { region: 213, max_results: 20 }, }),});
const batch = await res.json();for (const item of batch.items) { console.log(item.query, item.status, item.source, item.results?.length ?? 0);}import osimport httpx
r = httpx.post( "https://proxy.seyka.ru/v1/search/yandex/smart", json={ "queries": [{"query": "ремонт квартир"}, {"query": "натяжные потолки"}], "defaults": {"region": 213, "max_results": 20}, }, headers={"Authorization": f"Bearer {os.environ['SEYKA_API_KEY']}"}, timeout=60,)for item in r.json()["items"]: print(item["query"], item["status"], item.get("source"), len(item.get("results") or [])){ "id": "835f2bfa-7c5a-462d-b080-cdee801d23d8", "count": 1, "done": true, "counts": { "pending": 0, "done": 1, "error": 0 }, "billing": { "cost_cents": …, "breakdown": [{ "source": "cache", "count": 1, "unit_cents": …, "cost_cents": … }] }, "items": [ { "query": "ремонт квартир", "status": "done", "source": "cache", "fetched_at": 1786669181, "results": [ { "pos": 1, "doc_id": "ZDB5DBD400EA724B7", "title": "Ремонт квартир в Москве: цены", "url": "https://example.ru/price", "domain": "example.ru", "snippet": "Актуальные цены на ремонт квартир…", "modtime": "20250827T120000", "lang": "ru", "size": 4412, "mime_type": "text/html", "charset": "utf-8", "saved_copy_url": "https://yandexwebcache.net/…" } ], "meta": { "found": 24000000, "reqid": "…", "is_local": true } } ]}Поля ответа
Заголовок раздела «Поля ответа»| Поле | Что это |
|---|---|
id |
Идентификатор пакета: для GET /v1/search/yandex/async/{batchId} и DELETE /v1/search/yandex/cache/{batchId} |
done |
Ни один запрос не остался в работе. Не значит, что все успешны, — смотрите status каждого |
counts |
Сколько запросов в работе, готово и с ошибкой |
items[].status |
queued, pending, done, error или expired |
items[].source |
Ступень, которая ответила: cache, async или sync |
items[].results |
Результаты; [] — запрос ничего не нашёл, null — ещё не готов |
items[].error |
Текст ошибки, если status — error |
items[].meta |
found — сколько документов нашёл Яндекс, reqid — идентификатор для поддержки, is_local — выдача локализована, effective_request — что Яндекс применил на самом деле |
У результата: pos — абсолютная позиция в выдаче (не индекс в массиве: страницы склеиваются и фильтруются),
doc_id — идентификатор документа у Яндекса, domain, snippet и passages, modtime — когда документ
менялся, lang — язык документа, size, mime_type и charset, saved_copy_url — сохранённая копия у Яндекса.
Ошибка одного запроса не роняет пакет: он получает status: "error", остальные отвечают как обычно.
Синхронный пакет
Заголовок раздела «Синхронный пакет»POST /v1/search/yandex/sync отвечает только готовыми результатами: каждый запрос, которого нет в кэше,
сразу идёт в синхронный режим Яндекса. Удобен, когда ответ нужен немедленно и ждать отложенный режим нет
смысла.
Отложенный пакет
Заголовок раздела «Отложенный пакет»POST /v1/search/yandex/async ставит запросы в отложенный режим и отвечает 202 с id пакета. Заберите
результаты, когда удобно, через GET /v1/search/yandex/async/{batchId} — чтение бесплатное, его можно
повторять сколько угодно.
# 1. Отправить пакет — ответ 202 приходит сразуcurl -X POST "https://proxy.seyka.ru/v1/search/yandex/async" \ -H "Authorization: Bearer $SEYKA_API_KEY" \ -H "Content-Type: application/json" \ -d '{"queries": [{"query": "ремонт квартир"}], "defaults": {"region": 213}}'
# 2. Забрать результаты по id из ответаcurl "https://proxy.seyka.ru/v1/search/yandex/async/835f2bfa-7c5a-462d-b080-cdee801d23d8" \ -H "Authorization: Bearer $SEYKA_API_KEY"- Пакет хранится 12 часов; запрос, который не успел за это время, получает
expired. - Результаты отложенного пакета хранятся в кэше не меньше 12 часов, даже если
cache_ttlменьше. - Пакет виден только аккаунту, который его создал (любому его ключу). Чужой или несуществующий
batchIdвозвращает404. - Блока
billingв ответе на чтение нет: всё оплачено при отправке.
Выдача по умолчанию хранится 24 часа; в пакетах срок задаёт cache_ttl (до 30 дней). Совместимые
эндпоинты и POST /v1/search/yandex/smart без cache_ttl берут любую ещё живую запись — так дешевле всего.
Заголовок Cache-Control: no-cache на поиск не действует: у поиска свой кэш выдачи.
Чтобы получить свежую выдачу, сбросьте кэш явно:
# По запросам — тело такое же, как у пакетного поискаcurl -X DELETE "https://proxy.seyka.ru/v1/search/yandex/cache" \ -H "Authorization: Bearer $SEYKA_API_KEY" \ -H "Content-Type: application/json" \ -d '{"queries": [{"query": "ремонт квартир", "region": 213, "max_results": 200}]}'
# Всё, что положил в кэш ваш пакетcurl -X DELETE "https://proxy.seyka.ru/v1/search/yandex/cache/835f2bfa-7c5a-462d-b080-cdee801d23d8" \ -H "Authorization: Bearer $SEYKA_API_KEY"{ "requested": 2, "purged": 2 }Указывайте те же region, freshness, safesearch и max_results, что и в исходном поиске: сбрасываются
страницы, которые покрывает это окно, поэтому запрос без max_results очистит только первую сотню. Кэш
общий, поэтому сброс затрагивает всех, кто получает ту же выдачу. Сброс бесплатный.
Глубина и пагинация
Заголовок раздела «Глубина и пагинация»Яндекс отдаёт выдачу страницами по 100 результатов, поэтому count или max_results больше 100 — это две
выборки и две ступени в X-Search-Rungs. Соседние страницы Яндекса перекрываются; повторы удаляются, и
запрос на 200 обычно возвращает чуть меньше 200 результатов.
offset в GET /v1/search/yandex отсчитывается в результатах. Окно, которое пересекает границу сотни
(например, offset=90&count=20), затрагивает две страницы, и обе оплачиваются.
Регион, свежесть и домены
Заголовок раздела «Регион, свежесть и домены»region— код региона Яндекса:225— Россия,213— Москва,2— Санкт-Петербург,65— Новосибирск. Без него или с0регион определяется по IP. Справочник — в документации Яндекса.freshness—pd,pw,pm,py. Запрос со свежестью — это отдельный поиск, а не фильтр поверх старого, и кэшируется он отдельно.include_domains/exclude_domainsприменяются к уже полученной выдаче, а не отправляются в Яндекс: смена фильтра не требует новой выборки и стоит как ответ из кэша. Домен совпадает вместе с поддоменами:habr.comвключаетcareer.habr.com, но неnothabr.com.
Язык поиска определяется по запросу: запрос с кириллицей ищется по русскоязычной выдаче, без неё — по международной.
Ошибки и лимиты
Заголовок раздела «Ошибки и лимиты»400— пустой запрос в Tavily-совместимомPOST;422— пустой или отсутствующийqв Brave-совместимомGETи любой неверный параметр (например,countбольше 200). В пакете пустой запрос получаетstatus: "error", остальные выполняются как обычно.413— в пакете больше 50 запросов.429— исчерпана квота поиска Яндекса или Яндекс сам ответил отказом по частоте. Совместимые эндпоинты отвечают429; в умном и синхронном пакете такой запрос получаетstatus: "error". В отложенном пакете отказ повторяется, пока не истечёт срок жизни пакета, и тогда запрос получаетstatus: "expired". Повторите позже.404— пакет не найден или принадлежит другому аккаунту.
Остальные коды — в разделе Ошибки.
Поиск оплачивается по ступени, которая ответила; чтение отложенного пакета и сброс кэша бесплатны. Ставки — на странице Цены.