{"openapi": "3.0.3", "info": {"title": "Прагматика Эксперт — каталог автомобилей с пробегом", "version": "0.1.0", "description": "То же, что MCP-сервер, обычным JSON поверх HTTP. Поиск, карточка, словари и сравнение — без ключа (30 запросов в минуту с адреса); статистика, подписки и заявки — по ключу. Как получить ключ: /developers/ai/.", "contact": {"url": "https://pragmatika-expert.ru/developers/ai/"}}, "servers": [{"url": "https://pragmatika-expert.ru"}], "paths": {"/api/v1/search_vehicles": {"post": {"operationId": "search_vehicles", "summary": "Поиск автомобилей с пробегом в сети «Прагматика Эксперт» (шесть городов, единый склад).", "description": "Поиск автомобилей с пробегом в сети «Прагматика Эксперт» (шесть городов, единый склад). Один вызов возвращает лестницу: точные совпадения (exact), близкие с пометкой compromise (close, всегда matched:false), что можно смягчить и сколько машин это даст (relax). Пустого ответа без следующего шага не бывает. Поле status говорит, что произошло: exact_matches, allowed_alternatives, needs_relaxation, no_matches, needs_clarification или data_unavailable — последний значит, что выгрузка недоступна, а не что машин нет.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"brand": {"type": "string", "description": "Марка: название или slug из get_dictionaries."}, "model": {"type": "string", "description": "Модель, название из get_dictionaries."}, "price_min": {"type": "integer", "description": "Цена от, рубли."}, "price_max": {"type": "integer", "description": "Цена до, рубли. Это потолок: выше него мы не предлагаем, пока не передан may_relax."}, "year_min": {"type": "integer"}, "year_max": {"type": "integer"}, "mileage_max": {"type": "integer", "description": "Пробег до, км."}, "body": {"type": "string", "description": "Кузов, например «универсал»."}, "gear": {"type": "string", "description": "Коробка. «Автомат» — только классический автомат: робот и вариатор — другие коробки."}, "drive": {"type": "string"}, "engine": {"type": "string", "description": "Тип двигателя."}, "color": {"type": "string"}, "city": {"type": "string", "description": "Город (slug из get_dictionaries) или any."}, "owners_max": {"type": "integer", "description": "Не больше стольких владельцев по ПТС."}, "original_pts": {"type": "boolean"}, "must_have": {"type": "array", "items": {"type": "string"}, "description": "Жёсткие условия — имена полей выше. Нарушать их нельзя ни при каких обстоятельствах."}, "prefer": {"type": "array", "items": {"type": "string"}, "description": "Пожелания — имена полей выше. Мы можем предложить машины без них, честно отметив это."}, "may_relax": {"type": "object", "description": "Разрешённые отклонения, например {\"price_max\": 50000} — на сколько можно выйти. Без этого бюджет не расширяется."}, "sort": {"type": "string", "enum": ["price", "mileage", "year", "fresh", "days_on_lot"]}, "limit": {"type": "integer", "description": "По умолчанию 5, максимум 20."}, "cursor": {"type": "string", "description": "next_cursor из прошлого ответа."}, "context_id": {"type": "string", "description": "Если вы уже приходили с этой задачей."}}}}}}, "responses": {"200": {"description": "Ответ инструмента. Поле status говорит, что произошло.", "content": {"application/json": {"schema": {"type": "object"}}}}, "400": {"description": "needs_clarification — запрос надо уточнить, message говорит как."}, "429": {"description": "Лимит запросов в минуту."}, "503": {"description": "data_unavailable — выгрузка недоступна. Это не значит, что машин нет."}}}}, "/api/v1/get_vehicle": {"post": {"operationId": "get_vehicle", "summary": "Одна машина целиком: характеристики, комплектация (код, название, уровень), цена как объект (cash_price — без условий, скидки с пометкой mandatory), наличие со временем сверки, история цены, фотографии, адрес площадки, ссылка.", "description": "Одна машина целиком: характеристики, комплектация (код, название, уровень), цена как объект (cash_price — без условий, скидки с пометкой mandatory), наличие со временем сверки, история цены, фотографии, адрес площадки, ссылка.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"id": {"type": "string", "description": "Идентификатор вида v_123 из поиска."}, "context_id": {"type": "string"}}, "required": ["id"]}}}}, "responses": {"200": {"description": "Ответ инструмента. Поле status говорит, что произошло.", "content": {"application/json": {"schema": {"type": "object"}}}}, "400": {"description": "needs_clarification — запрос надо уточнить, message говорит как."}, "429": {"description": "Лимит запросов в минуту."}, "503": {"description": "data_unavailable — выгрузка недоступна. Это не значит, что машин нет."}}}}, "/api/v1/get_dictionaries": {"post": {"operationId": "get_dictionaries", "summary": "Все допустимые значения полей поиска с количеством машин по каждому.", "description": "Все допустимые значения полей поиска с количеством машин по каждому. Вызовите один раз, чтобы не ошибиться в написании.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"context_id": {"type": "string"}}}}}}, "responses": {"200": {"description": "Ответ инструмента. Поле status говорит, что произошло.", "content": {"application/json": {"schema": {"type": "object"}}}}, "400": {"description": "needs_clarification — запрос надо уточнить, message говорит как."}, "429": {"description": "Лимит запросов в минуту."}, "503": {"description": "data_unavailable — выгрузка недоступна. Это не значит, что машин нет."}}}}, "/api/v1/get_availability_stats": {"post": {"operationId": "get_availability_stats", "summary": "Ответ на вопрос «а вообще такие бывают?»: сколько таких продано за полгода, средний срок продажи, как часто появляются, когда ушла последняя.", "description": "Ответ на вопрос «а вообще такие бывают?»: сколько таких продано за полгода, средний срок продажи, как часто появляются, когда ушла последняя. Агрегаты без привязки к сделкам. Требует ключ.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"brand": {"type": "string", "description": "Марка: название или slug из get_dictionaries."}, "model": {"type": "string", "description": "Модель, название из get_dictionaries."}, "price_min": {"type": "integer", "description": "Цена от, рубли."}, "price_max": {"type": "integer", "description": "Цена до, рубли. Это потолок: выше него мы не предлагаем, пока не передан may_relax."}, "year_min": {"type": "integer"}, "year_max": {"type": "integer"}, "mileage_max": {"type": "integer", "description": "Пробег до, км."}, "body": {"type": "string", "description": "Кузов, например «универсал»."}, "gear": {"type": "string", "description": "Коробка. «Автомат» — только классический автомат: робот и вариатор — другие коробки."}, "drive": {"type": "string"}, "engine": {"type": "string", "description": "Тип двигателя."}, "color": {"type": "string"}, "city": {"type": "string", "description": "Город (slug из get_dictionaries) или any."}, "owners_max": {"type": "integer", "description": "Не больше стольких владельцев по ПТС."}, "original_pts": {"type": "boolean"}}}}}}, "responses": {"200": {"description": "Ответ инструмента. Поле status говорит, что произошло.", "content": {"application/json": {"schema": {"type": "object"}}}}, "400": {"description": "needs_clarification — запрос надо уточнить, message говорит как."}, "429": {"description": "Лимит запросов в минуту."}, "503": {"description": "data_unavailable — выгрузка недоступна. Это не значит, что машин нет."}, "401": {"description": "Нужен ключ или он отозван."}}, "security": [{"ApiKey": []}, {"Bearer": []}]}}, "/api/v1/watch_vehicles": {"post": {"operationId": "watch_vehicles", "summary": "Подписка на появление машин по условиям поиска.", "description": "Подписка на появление машин по условиям поиска. Персональных данных не принимает: телефон и почту через инструменты мы не берём. Укажите callback_url (https) — пришлём POST при появлении; либо приходите на poll_url. Если человек хочет получать уведомления сам, отдайте ему human_url: он откроет страницу и сам даст согласие. До 20 подписок на ключ, срок 30 дней, не чаще одного уведомления в сутки. Требует ключ.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"query": {"type": "object", "properties": {"brand": {"type": "string", "description": "Марка: название или slug из get_dictionaries."}, "model": {"type": "string", "description": "Модель, название из get_dictionaries."}, "price_min": {"type": "integer", "description": "Цена от, рубли."}, "price_max": {"type": "integer", "description": "Цена до, рубли. Это потолок: выше него мы не предлагаем, пока не передан may_relax."}, "year_min": {"type": "integer"}, "year_max": {"type": "integer"}, "mileage_max": {"type": "integer", "description": "Пробег до, км."}, "body": {"type": "string", "description": "Кузов, например «универсал»."}, "gear": {"type": "string", "description": "Коробка. «Автомат» — только классический автомат: робот и вариатор — другие коробки."}, "drive": {"type": "string"}, "engine": {"type": "string", "description": "Тип двигателя."}, "color": {"type": "string"}, "city": {"type": "string", "description": "Город (slug из get_dictionaries) или any."}, "owners_max": {"type": "integer", "description": "Не больше стольких владельцев по ПТС."}, "original_pts": {"type": "boolean"}, "must_have": {"type": "array", "items": {"type": "string"}, "description": "Жёсткие условия — имена полей выше. Нарушать их нельзя ни при каких обстоятельствах."}, "prefer": {"type": "array", "items": {"type": "string"}, "description": "Пожелания — имена полей выше. Мы можем предложить машины без них, честно отметив это."}, "may_relax": {"type": "object", "description": "Разрешённые отклонения, например {\"price_max\": 50000} — на сколько можно выйти. Без этого бюджет не расширяется."}}}, "callback_url": {"type": "string"}, "ttl_days": {"type": "integer"}, "context_id": {"type": "string"}}, "required": ["query"]}}}}, "responses": {"200": {"description": "Ответ инструмента. Поле status говорит, что произошло.", "content": {"application/json": {"schema": {"type": "object"}}}}, "400": {"description": "needs_clarification — запрос надо уточнить, message говорит как."}, "429": {"description": "Лимит запросов в минуту."}, "503": {"description": "data_unavailable — выгрузка недоступна. Это не значит, что машин нет."}, "401": {"description": "Нужен ключ или он отозван."}}, "security": [{"ApiKey": []}, {"Bearer": []}]}}, "/api/v1/compare_vehicles": {"post": {"operationId": "compare_vehicles", "summary": "Сравнение 2–6 машин по идентификаторам.", "description": "Сравнение 2–6 машин по идентификаторам. Отдаёт только различающиеся поля с пометкой, что лучше и на сколько.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"ids": {"type": "array", "items": {"type": "string"}}, "context_id": {"type": "string"}}, "required": ["ids"]}}}}, "responses": {"200": {"description": "Ответ инструмента. Поле status говорит, что произошло.", "content": {"application/json": {"schema": {"type": "object"}}}}, "400": {"description": "needs_clarification — запрос надо уточнить, message говорит как."}, "429": {"description": "Лимит запросов в минуту."}, "503": {"description": "data_unavailable — выгрузка недоступна. Это не значит, что машин нет."}}}}, "/api/v1/request_vehicle": {"post": {"operationId": "request_vehicle", "summary": "Заявка на поиск под заказ: сеть выкупает и привозит машины.", "description": "Заявка на поиск под заказ: сеть выкупает и привозит машины. Контактов человека не принимает — менеджер получит заявку с пометкой «от агента» и увидит, что именно искали. Чтобы с человеком связались, он сам оставляет телефон на сайте. Требует ключ.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"query": {"type": "object", "properties": {"brand": {"type": "string", "description": "Марка: название или slug из get_dictionaries."}, "model": {"type": "string", "description": "Модель, название из get_dictionaries."}, "price_min": {"type": "integer", "description": "Цена от, рубли."}, "price_max": {"type": "integer", "description": "Цена до, рубли. Это потолок: выше него мы не предлагаем, пока не передан may_relax."}, "year_min": {"type": "integer"}, "year_max": {"type": "integer"}, "mileage_max": {"type": "integer", "description": "Пробег до, км."}, "body": {"type": "string", "description": "Кузов, например «универсал»."}, "gear": {"type": "string", "description": "Коробка. «Автомат» — только классический автомат: робот и вариатор — другие коробки."}, "drive": {"type": "string"}, "engine": {"type": "string", "description": "Тип двигателя."}, "color": {"type": "string"}, "city": {"type": "string", "description": "Город (slug из get_dictionaries) или any."}, "owners_max": {"type": "integer", "description": "Не больше стольких владельцев по ПТС."}, "original_pts": {"type": "boolean"}, "must_have": {"type": "array", "items": {"type": "string"}, "description": "Жёсткие условия — имена полей выше. Нарушать их нельзя ни при каких обстоятельствах."}, "prefer": {"type": "array", "items": {"type": "string"}, "description": "Пожелания — имена полей выше. Мы можем предложить машины без них, честно отметив это."}, "may_relax": {"type": "object", "description": "Разрешённые отклонения, например {\"price_max\": 50000} — на сколько можно выйти. Без этого бюджет не расширяется."}}}, "comment": {"type": "string", "description": "Что важно человеку, до 500 символов. Без контактов."}, "context_id": {"type": "string"}}, "required": ["query"]}}}}, "responses": {"200": {"description": "Ответ инструмента. Поле status говорит, что произошло.", "content": {"application/json": {"schema": {"type": "object"}}}}, "400": {"description": "needs_clarification — запрос надо уточнить, message говорит как."}, "429": {"description": "Лимит запросов в минуту."}, "503": {"description": "data_unavailable — выгрузка недоступна. Это не значит, что машин нет."}, "401": {"description": "Нужен ключ или он отозван."}}, "security": [{"ApiKey": []}, {"Bearer": []}]}}}, "components": {"securitySchemes": {"ApiKey": {"type": "apiKey", "in": "header", "name": "X-API-Key"}, "Bearer": {"type": "http", "scheme": "bearer"}}}}