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
/ozon/api/v2/item/detail-by-url| Поле | Тип / значение | Описание |
|---|---|---|
url | string, обязательно | Полный HTTPS URL ozon.ru или www.ozon.ru с числовым SKU в /product/…, до 4096 символов. Credentials, private host, нестандартный порт, fragment и короткие ссылки запрещены; tracking query удаляется. |
no_cache | boolean = false | Дополнительный параметр кэша карточки, см. ниже. |
options | object, необязательно | Параметры извлечения карточки, см. общую таблицу. |
Успешный ответ: расширенная карточка товара.
Примеры карточка по url
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
}'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)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
$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
/ozon/api/v2/item/detail-by-sku| Поле | Тип / значение | Описание |
|---|---|---|
sku | string | integer, обязательно | Положительный числовой идентификатор до 20 цифр, например 123456789. Boolean и дробное число не принимаются. |
no_cache | boolean = false | Дополнительный параметр кэша карточки. |
options | object, необязательно | Параметры извлечения карточки, см. общую таблицу. |
Успешный ответ: расширенная карточка товара.
Примеры карточка по sku
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
}'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)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
$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"];Поиск товаров
/ozon/api/v2/searchПараметры описаны в общей таблице поиска.
Успешный ответ: поисковая выдача и контекст.
Примеры поиск товаров
curl -X POST "https://bhapi.ru/ozon/api/v2/search" \
-H "X-API-Token: YOUR_OZON_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"query": "беспроводные наушники",
"no_cache": false
}'import requests
response = requests.post(
"https://bhapi.ru/ozon/api/v2/search",
headers={
"X-API-Token": "YOUR_OZON_API_TOKEN",
},
json={'query': 'беспроводные наушники', 'no_cache': False},
timeout=100,
)
response.raise_for_status()
result = response.json()["data"]
print(result)const response = await fetch("https://bhapi.ru/ozon/api/v2/search", {
method: "POST",
headers: {
"X-API-Token": "YOUR_OZON_API_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({
"query": "беспроводные наушники",
"no_cache": false
})
});
if (!response.ok) throw new Error("HTTP " + response.status);
const result = (await response.json()).data;
console.log(result);<?php
$ch = curl_init("https://bhapi.ru/ozon/api/v2/search");
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": "беспроводные наушники",
"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"];Фильтры поиска
/ozon/api/v2/search/filtersПараметры описаны в общей таблице поиска.
| Поле | Тип / значение | Описание |
|---|---|---|
full | boolean = true | Загрузить полную панель фильтров. |
key | string, необязательно | Ключ фильтра из ответа, 1–128 символов; раскрывает его дополнительные значения. |
Передайте ровно один источник query или context; cursor запрещён. Ответ содержит контекст и описания фильтров; пустой список товаров здесь допустим.
Успешный ответ: поисковая выдача и контекст.
Примеры фильтры поиска
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
}'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)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
$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"];Поиск по изображению
/ozon/api/v2/search/by-image| Поле | Тип / значение | Описание |
|---|---|---|
image_url | string, один источник обязателен | Публичный HTTPS URL JPEG/PNG/WebP. Credentials, private/loopback/link-local адреса и небезопасные перенаправления не допускаются. |
image_base64 | string, один источник обязателен | Строгий base64 содержимого JPEG/PNG/WebP без data: префикса; декодированный файл максимум 8 MiB. Не передавайте одновременно image_url. |
crop | object, необязательно | left=0, top=0, width=1, height=1. Нормализованные координаты: left/top от 0 до <1, width/height >0 до 1; прямоугольник целиком внутри изображения. |
Параметры получения выдачи, сортировки и фильтров совпадают с текстовым поиском. query, context, cursor в этом методе запрещены. Продолжайте найденную выдачу через next_cursor в обычном /search; фильтры уточняйте по context.
Успешный ответ: поисковая выдача и контекст.
Примеры поиск по изображению
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
}'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)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
$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 и не заставляет повторно загрузить накопленные элементы.
| Поле | Тип / значение | Описание |
|---|---|---|
timeout_seconds | number, необязательно | Общий бюджет операции >0, максимум 80 секунд и не выше предела сервера. |
max_attempts | integer, необязательно | 1–3, не выше серверного лимита. |
max_additional_pages | integer, необязательно | 0–10 дополнительных страниц, не выше серверного лимита. |
include_rich_content | boolean = true | Включить расширенное содержимое. |
include_variants | boolean = true | Включить варианты товара. |
include_review_media | boolean = true | Включить доступные медиа отзывов; это не выгрузка всех отзывов. |
| Поле | Тип / значение | Описание |
|---|---|---|
query | string, один источник | 1–500 символов после удаления пробелов по краям, без управляющих символов. |
context | string, один источник | Контекст из ответа для изменения поиска, сортировки или фильтров. |
cursor | string, один источник | Последний next_cursor для последовательного продолжения; не повторяйте query/context. |
sorting | enum = score | score, new, price, price_desc, rating, discount. |
page | integer = 1 | 1–100. Явная страница начинает выборку заново, не заменяет cursor. |
filters | object = {} | До 32 ключей длиной 1–128 символов; используйте поддерживаемые ключи из текущей выдачи. |
deny_category_prediction | boolean = true | Не сужать новый текстовый поиск предсказанной категорией. Не гарантирует поиск по всем категориям. |
result_limit | integer = 36 | Верхняя граница числа товаров, 1–500 по схеме; сервер может иметь меньший предел. |
max_pages | integer = 1 | Максимум загруженных страниц за операцию, 1–10 по схеме; сервер может ограничивать сильнее. |
include_filters | boolean = true | При false ключ filters отсутствует в JSON ответа. |
no_cache | boolean = false | Дополнительный параметр; не сбрасывает сохранённый контекст. |
options | object, необязательно | 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.
| Поле | Тип / значение | Описание |
|---|---|---|
boolean | true | false | Переключатель из поддерживаемого фильтра. |
list | array[string] | До 100 значений длиной 1–128; точные keys из values ответа, не отображаемые заголовки. |
range | object | from_value и to_value — конечные числа >=0, from_value <= to_value. Например {"from_value":100,"to_value":1000}. |
Контекст, фильтры и продолжение
Начните с {"query":"наушники"}. Из ответа возьмите next_cursor и отправьте следующий запрос на /ozon/api/v2/search:
{"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 либо пустыми списками в соответствии с типом.
| Поле | Тип / значение | Описание |
|---|---|---|
sku | string | Числовой идентификатор товара. |
url | string | Канонический URL того же SKU. |
title | string | Название товара. |
brand | string | object | null | Бренд, включая структурированное представление источника. |
manufacturer | array[string | null] | null | Производитель; не подменяется брендом. |
description | string | null | Основное описание. |
additional_description_fields | array[object] | Дополнительные поля описания в структуре источника. |
rich_content | array[any] | Расширенное содержимое в структуре источника. |
images | array[string] | Изображения товара. |
prices | object | currency: string; regular, bank_card, original: number | null — обычная, по карте и исходная цена. |
rating | object | value: number | null — рейтинг; review_count: integer | null — число отзывов. |
characteristics | object | total_count: integer | null; items: массив характеристик. |
characteristics.items[] | object | id: string | null; name: string; values: array[string | null]. |
seller | object | name, url, rating_display: string | null — продавец и отображаемый рейтинг. |
review_media | array[object] | null | Доступные медиа отзывов в структуре источника. |
category_path | array[object] | Элементы name: string | null, url: string; путь категорий. |
variants | array[object] | null | Подтверждённые варианты в структуре источника; рекомендации не подменяют варианты. |
data_quality | object | is_partial: boolean; missing_fields: array[string] — признаки неполноты. |
data_freshness | object | assembled_at: string — время сборки; cache_hit: boolean; cache_age_seconds, cache_ttl_seconds: number >=0. |
{
"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}
}
}Поля поиска и фильтров
| Поле | Тип / значение | Описание |
|---|---|---|
returned_count | integer | Число элементов этого ответа, равно длине items. |
page | integer | null | Текущая страница источника. |
pages_fetched | integer | Страницы, загруженные в этой операции. |
has_more | boolean | Доступно ли продолжение. |
context | string | Контекст для изменения/уточнения поиска. |
next_cursor | string | null | Следующее продолжение; при окончании null. |
items | array[object] | Товары этого ответа, включая допустимый пустой массив. |
sorts | enum | Одна строка итоговой сортировки, не массив вариантов. |
filters | array[object], ключ необязателен | Описания фильтров. Ключ отсутствует при include_filters=false. |
| Поле | Тип / значение | Описание |
|---|---|---|
sku | string | Идентификатор товара. |
url | string | URL товара. |
title | string | null | Название. |
images | array[string] | Изображения выдачи. |
price | number | null | Отображаемая цена в поисковой плитке; может отличаться от карточки. |
original_price | number | null | Исходная цена в выдаче. |
currency | string | null | Валюта. |
rating | number | null | Рейтинг. |
review_count | integer | null | Количество отзывов. |
| Поле | Тип / значение | Описание |
|---|---|---|
key | string | null | Машинный ключ фильтра. |
type | string | null | Тип фильтра источника. |
title | string | null | Отображаемое имя. |
supported | boolean | Можно ли применить этот тип через API. |
selected | boolean | null | Состояние переключателя. |
values | array[object] | key: string | null; title: string | null; selected: boolean=false. |
has_more_values | boolean | Доступно ли раскрытие дополнительных значений. |
minimum | number | null | Нижняя граница диапазона. |
maximum | number | null | Верхняя граница диапазона. |
{"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.
Статусы некоторых ошибок в этом режиме отличаются; успешные ответы не меняются.
Общий справочник кодов, форматов и действий клиента →
| Поле | Тип / значение | Описание |
|---|---|---|
401 / 403 | Доступ BHAPI | Проверьте клиентский ключ, его привязку к Ozon и действующий доступ. |
404 | item_not_found | Товар не найден или недоступен. |
409 | search_context_expired | Контекст недоступен: начните новый поиск. |
413 / 415 / 422 | Запрос | Превышен размер, неверный Content-Type либо параметры, фильтр или бюджет операции. |
429 | parser_overloaded / квота | Перегрузка парсера или ограничение BHAPI. Для перегрузки учитывайте Retry-After. |
502 | upstream_invalid_response | Некорректный ответ источника или несовпадение SKU. |
503 | upstream_unavailable / upstream_unreachable / upstream_access_restricted / parser_internal_error | Сервис, источник или сохранённый контекст временно недоступны. |
504 | upstream_timeout | Источник не ответил в пределах бюджета. |
500 | internal_error / finalization_failed | Внутренняя ошибка BHAPI или незавершённая запись подтверждённого результата; проверьте исход до повторного вызова. |
По умолчанию ошибка находится в detail. Выберите X-BHAPI-Error-Format: problem-v1 для общего контракта. Формат может изменять отдельные HTTP-статусы: точные правила — в справочнике ошибок. Ошибки не возвращаются как успешная карточка или пустая выдача.
Квоты и ограничения
Каждый успешный публичный вызов расходует одну единицу общей квоты Ozon: карточка, фильтры, cursor, пустой поиск и cache HIT учитываются одинаково. Внутренние страницы и запросы не увеличивают этот расход. Отказы источника и ошибки валидации не расходуют успешную квоту. При finalization_failed успешный результат уже мог быть учтён: проверьте исход через поддержку до нового вызова. V1 и V2 делят один остаток; условия и лимиты ключа смотрите в кабинете.
Пагинация, количество результатов и фильтры ограничены текущим состоянием Ozon. Поиск не является полной стабильной выгрузкой каталога; доставка, регион, batch и полная выгрузка отзывов в эти методы не входят.