Ozon V2: расширенная карточка и поиск

Пять методов парсера Ozon. V1 и V2 используют один клиентский ключ, доступ и общую квоту Ozon.

Базовый URL: https://bhapi.ru. Все методы принимают POST с Content-Type: application/json и X-API-Token: YOUR_OZON_API_TOKEN. Клиентский ключ передавайте только в заголовке. Ответ успешного запроса: {"status":"ok","data":…}. В V2 цены числовые; V1 сохраняет компактную карточку со строковыми ценами.

Объект запроса не допускает неизвестных полей. Примеры ниже синтетические; замените SKU, URL изображения и ключ своими значениями.

Карточка по URL

POST/ozon/api/v2/item/detail-by-url
Запрос карточки по URL
ПолеТип / значениеОписание
urlstring, обязательноПолный HTTPS URL ozon.ru или www.ozon.ru с числовым SKU в /product/…, до 4096 символов. Credentials, private host, нестандартный порт, fragment и короткие ссылки запрещены; tracking query удаляется.
no_cacheboolean = falseДополнительный параметр кэша карточки, см. ниже.
optionsobject, необязательноПараметры извлечения карточки, см. общую таблицу.

Успешный ответ: расширенная карточка товара.

Примеры карточка по url

cURL
curl -X POST "https://bhapi.ru/ozon/api/v2/item/detail-by-url" \
  -H "X-API-Token: YOUR_OZON_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
  "url": "https://www.ozon.ru/product/123456789/",
  "no_cache": false
}'
Python
import requests

response = requests.post(
    "https://bhapi.ru/ozon/api/v2/item/detail-by-url",
    headers={
        "X-API-Token": "YOUR_OZON_API_TOKEN",
    },
    json={'url': 'https://www.ozon.ru/product/123456789/', 'no_cache': False},
    timeout=100,
)
response.raise_for_status()
result = response.json()["data"]
print(result)
JavaScript
const response = await fetch("https://bhapi.ru/ozon/api/v2/item/detail-by-url", {
  method: "POST",
  headers: {
    "X-API-Token": "YOUR_OZON_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "url": "https://www.ozon.ru/product/123456789/",
    "no_cache": false
  })
});
if (!response.ok) throw new Error("HTTP " + response.status);
const result = (await response.json()).data;
console.log(result);
PHP
<?php
$ch = curl_init("https://bhapi.ru/ozon/api/v2/item/detail-by-url");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 100,
    CURLOPT_HTTPHEADER => [
        "X-API-Token: YOUR_OZON_API_TOKEN",
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => '{
      "url": "https://www.ozon.ru/product/123456789/",
      "no_cache": false
    }',
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($body === false || $status !== 200) {
    throw new RuntimeException("HTTP " . $status);
}
$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR)["data"];

Карточка по SKU

POST/ozon/api/v2/item/detail-by-sku
Запрос карточки по SKU
ПолеТип / значениеОписание
skustring | integer, обязательноПоложительный числовой идентификатор до 20 цифр, например 123456789. Boolean и дробное число не принимаются.
no_cacheboolean = falseДополнительный параметр кэша карточки.
optionsobject, необязательноПараметры извлечения карточки, см. общую таблицу.

Успешный ответ: расширенная карточка товара.

Примеры карточка по sku

cURL
curl -X POST "https://bhapi.ru/ozon/api/v2/item/detail-by-sku" \
  -H "X-API-Token: YOUR_OZON_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
  "sku": "123456789",
  "no_cache": false
}'
Python
import requests

response = requests.post(
    "https://bhapi.ru/ozon/api/v2/item/detail-by-sku",
    headers={
        "X-API-Token": "YOUR_OZON_API_TOKEN",
    },
    json={'sku': '123456789', 'no_cache': False},
    timeout=100,
)
response.raise_for_status()
result = response.json()["data"]
print(result)
JavaScript
const response = await fetch("https://bhapi.ru/ozon/api/v2/item/detail-by-sku", {
  method: "POST",
  headers: {
    "X-API-Token": "YOUR_OZON_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "sku": "123456789",
    "no_cache": false
  })
});
if (!response.ok) throw new Error("HTTP " + response.status);
const result = (await response.json()).data;
console.log(result);
PHP
<?php
$ch = curl_init("https://bhapi.ru/ozon/api/v2/item/detail-by-sku");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 100,
    CURLOPT_HTTPHEADER => [
        "X-API-Token: YOUR_OZON_API_TOKEN",
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => '{
      "sku": "123456789",
      "no_cache": false
    }',
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($body === false || $status !== 200) {
    throw new RuntimeException("HTTP " . $status);
}
$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR)["data"];

Фильтры поиска

POST/ozon/api/v2/search/filters

Параметры описаны в общей таблице поиска.

Дополнительные параметры фильтров
ПолеТип / значениеОписание
fullboolean = trueЗагрузить полную панель фильтров.
keystring, необязательноКлюч фильтра из ответа, 1–128 символов; раскрывает его дополнительные значения.

Передайте ровно один источник query или context; cursor запрещён. Ответ содержит контекст и описания фильтров; пустой список товаров здесь допустим.

Успешный ответ: поисковая выдача и контекст.

Примеры фильтры поиска

cURL
curl -X POST "https://bhapi.ru/ozon/api/v2/search/filters" \
  -H "X-API-Token: YOUR_OZON_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
  "query": "беспроводные наушники",
  "full": true,
  "no_cache": false
}'
Python
import requests

response = requests.post(
    "https://bhapi.ru/ozon/api/v2/search/filters",
    headers={
        "X-API-Token": "YOUR_OZON_API_TOKEN",
    },
    json={'query': 'беспроводные наушники', 'full': True, 'no_cache': False},
    timeout=100,
)
response.raise_for_status()
result = response.json()["data"]
print(result)
JavaScript
const response = await fetch("https://bhapi.ru/ozon/api/v2/search/filters", {
  method: "POST",
  headers: {
    "X-API-Token": "YOUR_OZON_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "query": "беспроводные наушники",
    "full": true,
    "no_cache": false
  })
});
if (!response.ok) throw new Error("HTTP " + response.status);
const result = (await response.json()).data;
console.log(result);
PHP
<?php
$ch = curl_init("https://bhapi.ru/ozon/api/v2/search/filters");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 100,
    CURLOPT_HTTPHEADER => [
        "X-API-Token: YOUR_OZON_API_TOKEN",
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => '{
      "query": "беспроводные наушники",
      "full": true,
      "no_cache": false
    }',
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($body === false || $status !== 200) {
    throw new RuntimeException("HTTP " . $status);
}
$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR)["data"];

Поиск по изображению

POST/ozon/api/v2/search/by-image
Изображение для поиска
ПолеТип / значениеОписание
image_urlstring, один источник обязателенПубличный HTTPS URL JPEG/PNG/WebP. Credentials, private/loopback/link-local адреса и небезопасные перенаправления не допускаются.
image_base64string, один источник обязателенСтрогий base64 содержимого JPEG/PNG/WebP без data: префикса; декодированный файл максимум 8 MiB. Не передавайте одновременно image_url.
cropobject, необязательноleft=0, top=0, width=1, height=1. Нормализованные координаты: left/top от 0 до <1, width/height >0 до 1; прямоугольник целиком внутри изображения.

Параметры получения выдачи, сортировки и фильтров совпадают с текстовым поиском. query, context, cursor в этом методе запрещены. Продолжайте найденную выдачу через next_cursor в обычном /search; фильтры уточняйте по context.

Успешный ответ: поисковая выдача и контекст.

Примеры поиск по изображению

cURL
curl -X POST "https://bhapi.ru/ozon/api/v2/search/by-image" \
  -H "X-API-Token: YOUR_OZON_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
  "image_url": "https://YOUR_PUBLIC_HOST/product.jpg",
  "no_cache": false
}'
Python
import requests

response = requests.post(
    "https://bhapi.ru/ozon/api/v2/search/by-image",
    headers={
        "X-API-Token": "YOUR_OZON_API_TOKEN",
    },
    json={'image_url': 'https://YOUR_PUBLIC_HOST/product.jpg', 'no_cache': False},
    timeout=100,
)
response.raise_for_status()
result = response.json()["data"]
print(result)
JavaScript
const response = await fetch("https://bhapi.ru/ozon/api/v2/search/by-image", {
  method: "POST",
  headers: {
    "X-API-Token": "YOUR_OZON_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "image_url": "https://YOUR_PUBLIC_HOST/product.jpg",
    "no_cache": false
  })
});
if (!response.ok) throw new Error("HTTP " + response.status);
const result = (await response.json()).data;
console.log(result);
PHP
<?php
$ch = curl_init("https://bhapi.ru/ozon/api/v2/search/by-image");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 100,
    CURLOPT_HTTPHEADER => [
        "X-API-Token: YOUR_OZON_API_TOKEN",
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => '{
      "image_url": "https://YOUR_PUBLIC_HOST/product.jpg",
      "no_cache": false
    }',
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($body === false || $status !== 200) {
    throw new RuntimeException("HTTP " . $status);
}
$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR)["data"];

Дополнительные параметры и кэш

no_cache — необязательный boolean, по умолчанию false. Для карточек true обходит внутренний кэш готовой карточки парсера; false разрешает использовать доступный кэш и может сократить время ответа. Наличие кэша не гарантируется. Параметр не отключает кэши Ozon и не гарантирует мгновенную актуальность цены. Строки, числа и null вместо boolean дают 422.

Для поиска кэш готовой выдачи не используется: параметр принят для единообразия, но не меняет это поведение. Курсор может вернуть ранее полученный буфер. no_cache=true не сбрасывает context/cursor, сессию и cookies и не заставляет повторно загрузить накопленные элементы.

options карточки
ПолеТип / значениеОписание
timeout_secondsnumber, необязательноОбщий бюджет операции >0, максимум 80 секунд и не выше предела сервера.
max_attemptsinteger, необязательно1–3, не выше серверного лимита.
max_additional_pagesinteger, необязательно0–10 дополнительных страниц, не выше серверного лимита.
include_rich_contentboolean = trueВключить расширенное содержимое.
include_variantsboolean = trueВключить варианты товара.
include_review_mediaboolean = trueВключить доступные медиа отзывов; это не выгрузка всех отзывов.
Параметры поиска
ПолеТип / значениеОписание
querystring, один источник1–500 символов после удаления пробелов по краям, без управляющих символов.
contextstring, один источникКонтекст из ответа для изменения поиска, сортировки или фильтров.
cursorstring, один источникПоследний next_cursor для последовательного продолжения; не повторяйте query/context.
sortingenum = scorescore, new, price, price_desc, rating, discount.
pageinteger = 11–100. Явная страница начинает выборку заново, не заменяет cursor.
filtersobject = {}До 32 ключей длиной 1–128 символов; используйте поддерживаемые ключи из текущей выдачи.
deny_category_predictionboolean = trueНе сужать новый текстовый поиск предсказанной категорией. Не гарантирует поиск по всем категориям.
result_limitinteger = 36Верхняя граница числа товаров, 1–500 по схеме; сервер может иметь меньший предел.
max_pagesinteger = 1Максимум загруженных страниц за операцию, 1–10 по схеме; сервер может ограничивать сильнее.
include_filtersboolean = trueПри false ключ filters отсутствует в JSON ответа.
no_cacheboolean = falseДополнительный параметр; не сбрасывает сохранённый контекст.
optionsobject, необязательноtimeout_seconds >0, максимум 80; max_attempts=1 (1–3); max_requests=12 (1–32). Серверные пределы могут быть меньше.

Для обычного поиска требуется ровно один источник: query, context или cursor. С курсором запрещено явно указывать sorting, page, filters, deny_category_prediction, даже с default-значениями. Не указанные явно лимиты upstream может уменьшить до текущих серверных значений; превышение явного лимита даёт 422.

Типы значений filters
ПолеТип / значениеОписание
booleantrue | falseПереключатель из поддерживаемого фильтра.
listarray[string]До 100 значений длиной 1–128; точные keys из values ответа, не отображаемые заголовки.
rangeobjectfrom_value и to_value — конечные числа >=0, from_value <= to_value. Например {"from_value":100,"to_value":1000}.

Контекст, фильтры и продолжение

Начните с {"query":"наушники"}. Из ответа возьмите next_cursor и отправьте следующий запрос на /ozon/api/v2/search:

JSON · продолжение
{"cursor":"COPY_NEXT_CURSOR_FROM_YOUR_RESPONSE","result_limit":36,"no_cache":false}

Удалите исходные query/context/sorting/page/filters/deny_category_prediction. Продолжайте новым next_cursor из каждого ответа, пока has_more=false и next_cursor=null. Не определяйте конец по числу элементов: returned_count может быть меньше запрошенного лимита, когда продолжение ещё есть.

context позволяет изменить сортировку/фильтры или получить их описания; выборка начинается заново, по умолчанию с первой страницы. context и next_cursor могут совпадать как строки, но их назначение определяется полем запроса.

Контекст привязан к тому же клиентскому ключу Ozon и текущему сервису. Срок доступности — не более 300 секунд; он может закончиться раньше при перезапуске, смене сессии или вытеснении состояния. Старое значение не продлевается чтением. При 409 search_context_expired начните новый поиск. Повтор cursor не объявляется идемпотентным; автоматическое продолжение после ошибки не выполняется.

Поля расширенной карточки

status="ok", data содержит один объект карточки. Цены здесь числовые и не пересчитываются; валюта указана в prices.currency. Отсутствующие значения представлены null либо пустыми списками в соответствии с типом.

data: карточка товара
ПолеТип / значениеОписание
skustringЧисловой идентификатор товара.
urlstringКанонический URL того же SKU.
titlestringНазвание товара.
brandstring | object | nullБренд, включая структурированное представление источника.
manufacturerarray[string | null] | nullПроизводитель; не подменяется брендом.
descriptionstring | nullОсновное описание.
additional_description_fieldsarray[object]Дополнительные поля описания в структуре источника.
rich_contentarray[any]Расширенное содержимое в структуре источника.
imagesarray[string]Изображения товара.
pricesobjectcurrency: string; regular, bank_card, original: number | null — обычная, по карте и исходная цена.
ratingobjectvalue: number | null — рейтинг; review_count: integer | null — число отзывов.
characteristicsobjecttotal_count: integer | null; items: массив характеристик.
characteristics.items[]objectid: string | null; name: string; values: array[string | null].
sellerobjectname, url, rating_display: string | null — продавец и отображаемый рейтинг.
review_mediaarray[object] | nullДоступные медиа отзывов в структуре источника.
category_patharray[object]Элементы name: string | null, url: string; путь категорий.
variantsarray[object] | nullПодтверждённые варианты в структуре источника; рекомендации не подменяют варианты.
data_qualityobjectis_partial: boolean; missing_fields: array[string] — признаки неполноты.
data_freshnessobjectassembled_at: string — время сборки; cache_hit: boolean; cache_age_seconds, cache_ttl_seconds: number >=0.
JSON · синтетический пример карточки
{
  "status": "ok",
  "data": {
    "sku": "123456789", "url": "https://www.ozon.ru/product/123456789/",
    "title": "Наушники", "brand": "Пример", "manufacturer": null,
    "description": "Пример описания", "additional_description_fields": [], "rich_content": [],
    "images": ["https://ir.ozone.ru/example/item.jpg"],
    "prices": {"currency":"RUB","regular":1990,"bank_card":1890,"original":2490},
    "rating": {"value":4.7,"review_count":23},
    "characteristics": {"total_count":1,"items":[{"id":null,"name":"Цвет","values":["Чёрный"]}]},
    "seller": {"name":"Магазин","url":null,"rating_display":null},
    "review_media": null, "category_path": [], "variants": [],
    "data_quality": {"is_partial":false,"missing_fields":[]},
    "data_freshness": {"assembled_at":"2026-10-26T09:00:00Z","cache_hit":false,"cache_age_seconds":0,"cache_ttl_seconds":300}
  }
}

Поля поиска и фильтров

data: поисковая выдача
ПолеТип / значениеОписание
returned_countintegerЧисло элементов этого ответа, равно длине items.
pageinteger | nullТекущая страница источника.
pages_fetchedintegerСтраницы, загруженные в этой операции.
has_morebooleanДоступно ли продолжение.
contextstringКонтекст для изменения/уточнения поиска.
next_cursorstring | nullСледующее продолжение; при окончании null.
itemsarray[object]Товары этого ответа, включая допустимый пустой массив.
sortsenumОдна строка итоговой сортировки, не массив вариантов.
filtersarray[object], ключ необязателенОписания фильтров. Ключ отсутствует при include_filters=false.
items[]: товар поиска
ПолеТип / значениеОписание
skustringИдентификатор товара.
urlstringURL товара.
titlestring | nullНазвание.
imagesarray[string]Изображения выдачи.
pricenumber | nullОтображаемая цена в поисковой плитке; может отличаться от карточки.
original_pricenumber | nullИсходная цена в выдаче.
currencystring | nullВалюта.
ratingnumber | nullРейтинг.
review_countinteger | nullКоличество отзывов.
filters[]: описание фильтра
ПолеТип / значениеОписание
keystring | nullМашинный ключ фильтра.
typestring | nullТип фильтра источника.
titlestring | nullОтображаемое имя.
supportedbooleanМожно ли применить этот тип через API.
selectedboolean | nullСостояние переключателя.
valuesarray[object]key: string | null; title: string | null; selected: boolean=false.
has_more_valuesbooleanДоступно ли раскрытие дополнительных значений.
minimumnumber | nullНижняя граница диапазона.
maximumnumber | nullВерхняя граница диапазона.
JSON · синтетическая пустая выдача
{"status":"ok","data":{"returned_count":0,"page":1,"pages_fetched":1,"has_more":false,"context":"CONTEXT_FROM_YOUR_RESPONSE","next_cursor":null,"items":[],"sorts":"score","filters":[]}}

Ошибки

Таблицы и примеры этого раздела описывают ошибки legacy (формат по умолчанию). Чтобы получать единый контракт ошибок, передайте заголовок X-BHAPI-Error-Format: problem-v1. Статусы некоторых ошибок в этом режиме отличаются; успешные ответы не меняются. Общий справочник кодов, форматов и действий клиента →

Ошибки Ozon V2
ПолеТип / значениеОписание
401 / 403Доступ BHAPIПроверьте клиентский ключ, его привязку к Ozon и действующий доступ.
404item_not_foundТовар не найден или недоступен.
409search_context_expiredКонтекст недоступен: начните новый поиск.
413 / 415 / 422ЗапросПревышен размер, неверный Content-Type либо параметры, фильтр или бюджет операции.
429parser_overloaded / квотаПерегрузка парсера или ограничение BHAPI. Для перегрузки учитывайте Retry-After.
502upstream_invalid_responseНекорректный ответ источника или несовпадение SKU.
503upstream_unavailable / upstream_unreachable / upstream_access_restricted / parser_internal_errorСервис, источник или сохранённый контекст временно недоступны.
504upstream_timeoutИсточник не ответил в пределах бюджета.
500internal_error / finalization_failedВнутренняя ошибка BHAPI или незавершённая запись подтверждённого результата; проверьте исход до повторного вызова.

По умолчанию ошибка находится в detail. Выберите X-BHAPI-Error-Format: problem-v1 для общего контракта. Формат может изменять отдельные HTTP-статусы: точные правила — в справочнике ошибок. Ошибки не возвращаются как успешная карточка или пустая выдача.

Квоты и ограничения

Каждый успешный публичный вызов расходует одну единицу общей квоты Ozon: карточка, фильтры, cursor, пустой поиск и cache HIT учитываются одинаково. Внутренние страницы и запросы не увеличивают этот расход. Отказы источника и ошибки валидации не расходуют успешную квоту. При finalization_failed успешный результат уже мог быть учтён: проверьте исход через поддержку до нового вызова. V1 и V2 делят один остаток; условия и лимиты ключа смотрите в кабинете.

Пагинация, количество результатов и фильтры ограничены текущим состоянием Ozon. Поиск не является полной стабильной выгрузкой каталога; доставка, регион, batch и полная выгрузка отзывов в эти методы не входят.