{"openapi":"3.0.0","paths":{"/api/v1/cities":{"get":{"description":"Постраничный справочник городов с необязательным фильтром по вхождению в название.","operationId":"CitiesController_list","parameters":[{"name":"page","required":false,"in":"query","description":"Номер страницы","schema":{"minimum":1,"maximum":1000,"default":1,"example":1,"type":"integer"}},{"name":"limit","required":false,"in":"query","description":"Размер страницы","schema":{"minimum":1,"maximum":100,"default":20,"example":20,"type":"integer"}},{"name":"name","required":false,"in":"query","description":"Фильтр по названию города (вхождение, без учёта регистра). Пустое значение равносильно отсутствию фильтра.","schema":{"minLength":1,"maxLength":255,"example":"Новосиб","type":"string"}}],"responses":{"200":{"description":"Страница справочника","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CitiesListResponseDto"}}}},"400":{"description":"Некорректные параметры запроса","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Токен отсутствует или недействителен","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"Исчерпан месячный лимит запросов токена; лимит обнуляется 1-го числа","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"token":[]}],"summary":"Список городов","tags":["cities"]}},"/api/v1/cities/search":{"get":{"description":"Поиск по вхождению в название города или региона. Выдача ранжируется: точное совпадение, затем совпадение по префиксу, затем вхождение.","operationId":"CitiesController_search","parameters":[{"name":"q","required":true,"in":"query","description":"Поисковый запрос: название города или региона","schema":{"minLength":2,"maxLength":255,"example":"Новосиб","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Максимум городов в выдаче","schema":{"minimum":1,"maximum":50,"default":10,"example":10,"type":"integer"}}],"responses":{"200":{"description":"Найденные города","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CityDto"}}}}},"400":{"description":"Некорректные параметры запроса","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Токен отсутствует или недействителен","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"Исчерпан месячный лимит запросов токена; лимит обнуляется 1-го числа","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"token":[]}],"summary":"Поиск города","tags":["cities"]}},"/api/v1/cities/{identifier}":{"get":{"description":"Принимает ФИАС города либо его внутренний числовой id.","operationId":"CitiesController_findOne","parameters":[{"name":"identifier","required":true,"in":"path","description":"ФИАС города или внутренний id","schema":{"example":"c2deb16a-0330-4f05-821f-1d09c93331e6","type":"string"}}],"responses":{"200":{"description":"Город","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CityDto"}}}},"400":{"description":"Идентификатор нераспознан","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Токен отсутствует или недействителен","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Город не найден","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"Исчерпан месячный лимит запросов токена; лимит обнуляется 1-го числа","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"token":[]}],"summary":"Город по идентификатору","tags":["cities"]}},"/api/v1/vehicles":{"get":{"description":"Доступные машины с характеристиками: грузоподъёмность, объём, габариты, типы кузова со способами загрузки, оснащением и признаком температурного режима.","operationId":"VehiclesController_findAll","parameters":[],"responses":{"200":{"description":"Типы транспортных средств","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VehicleDto"}}}}},"401":{"description":"Токен отсутствует или недействителен","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"Исчерпан месячный лимит запросов токена; лимит обнуляется 1-го числа","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"token":[]}],"summary":"Список типов транспортных средств","tags":["vehicles"]}},"/api/v1/calculate/ltl":{"post":{"description":"Итоговая стоимость с учётом всех надбавок и коэффициентов клиента, даты подачи и доставки, детализация по услугам.","operationId":"CalculateController_ltl","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LtlCalculationDto"}}}},"responses":{"200":{"description":"Результат расчёта","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationResponseDto"}}}},"400":{"description":"Некорректные параметры запроса","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Токен отсутствует или недействителен","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Город или машина не найдены","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"Расчёт для указанных параметров недоступен","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"Исчерпан месячный лимит запросов токена; лимит обнуляется 1-го числа","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"503":{"description":"Сервис расчёта недоступен","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"token":[]}],"summary":"Расчёт сборного груза (LTL)","tags":["calculate"]}},"/api/v1/calculate/ftl":{"post":{"description":"Итоговая стоимость с учётом всех надбавок и коэффициентов клиента, даты подачи и доставки, детализация по услугам. Машина и тип кузова — из справочника `GET /vehicles`.","operationId":"CalculateController_ftl","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FtlCalculationDto"}}}},"responses":{"200":{"description":"Результат расчёта","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationResponseDto"}}}},"400":{"description":"Некорректные параметры запроса","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"401":{"description":"Токен отсутствует или недействителен","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"404":{"description":"Город или машина не найдены","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"422":{"description":"Расчёт для указанных параметров недоступен","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"429":{"description":"Исчерпан месячный лимит запросов токена; лимит обнуляется 1-го числа","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}},"503":{"description":"Сервис расчёта недоступен","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponseDto"}}}}},"security":[{"token":[]}],"summary":"Расчёт выделенного транспорта (FTL)","tags":["calculate"]}}},"info":{"title":"Clever Public API","description":"Публичное API. Города и регионы адресуются по ФИАС; внутренние коды справочников наружу не отдаются. Все методы требуют заголовок `Authorization: Bearer <токен>`; токен выдаёт администратор и привязывает его к логину потребителя.","version":"v1","contact":{}},"tags":[{"name":"cities","description":"Справочник городов"},{"name":"vehicles","description":"Справочник транспортных средств"},{"name":"calculate","description":"Расчёт стоимости перевозки"}],"servers":[],"components":{"securitySchemes":{"token":{"type":"http","scheme":"bearer","description":"Токен доступа, выданный администратором"}},"schemas":{"ErrorBodyDto":{"type":"object","properties":{"code":{"type":"integer","description":"HTTP-код ответа","example":400},"message":{"type":"string","description":"Описание ошибки. Несколько сообщений валидации склеиваются через «; ».","example":"Некорректные параметры запроса"}},"required":["code","message"]},"ErrorResponseDto":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorBodyDto"}},"required":["error"]},"CityRegionDto":{"type":"object","properties":{"fias_id":{"type":"string","format":"uuid","nullable":true,"description":"ФИАС региона. Может быть null: бэкфилл покрывает не все регионы.","example":"1ac46b49-3209-4814-b7bf-a509ea1aecd9"},"name":{"type":"string","description":"Название региона. Пустая строка, если регион не привязан.","example":"Новосибирская"}},"required":["fias_id","name"]},"CityDto":{"type":"object","properties":{"id":{"type":"integer","description":"Внутренний идентификатор города","example":1234},"fias_id":{"type":"string","format":"uuid","description":"ФИАС города","example":"c2deb16a-0330-4f05-821f-1d09c93331e6"},"name":{"type":"string","description":"Название города","example":"Новосибирск"},"region":{"description":"Регион города","allOf":[{"$ref":"#/components/schemas/CityRegionDto"}]}},"required":["id","fias_id","name","region"]},"PaginationMetaDto":{"type":"object","properties":{"page":{"type":"integer","description":"Текущая страница","example":1},"limit":{"type":"integer","description":"Размер страницы","example":20},"total":{"type":"integer","description":"Всего записей с учётом фильтра","example":145},"total_pages":{"type":"integer","description":"Всего страниц","example":8}},"required":["page","limit","total","total_pages"]},"CitiesListResponseDto":{"type":"object","properties":{"data":{"description":"Города текущей страницы","type":"array","items":{"$ref":"#/components/schemas/CityDto"}},"meta":{"description":"Пагинация","allOf":[{"$ref":"#/components/schemas/PaginationMetaDto"}]}},"required":["data","meta"]},"VehicleDimensionsDto":{"type":"object","properties":{"length":{"type":"number","description":"Длина кузова, м","example":13.6},"width":{"type":"number","description":"Ширина кузова, м","example":2.45},"height":{"type":"number","description":"Высота кузова, м","example":2.7}},"required":["length","width","height"]},"VehicleBodyTypeDto":{"type":"object","properties":{"name":{"type":"string","enum":["Тент","Борт","Изотерм","Реф"],"description":"Тип кузова. Значение годится как `truckType` в POST /calculate/ftl.","example":"Реф"},"temperature_controlled":{"type":"boolean","description":"Поддерживает температурный режим (рефрижератор или изотермический кузов)","example":true},"loading":{"type":"array","description":"Доступные комбинации загрузки. Значения годятся как `load` в POST /calculate/ftl.","example":["Зад","Зад/Бок"],"items":{"type":"string","enum":["Зад","Зад/Бок","Зад/Верх","Зад/Бок/Верх"]}},"options":{"type":"array","description":"Дополнительное оснащение. Значения годятся как `dop` в POST /calculate/ftl.","example":["ремни","Гидроборт"],"items":{"type":"string","enum":["ремни","коники","деревянный пол","обрешетка","Гидроборт"]}}},"required":["name","temperature_controlled","loading","options"]},"VehicleLimitDto":{"type":"object","properties":{"name":{"type":"string","description":"Название характеристики","example":"Мест"},"unit":{"type":"string","description":"Единица измерения","example":"шт"},"min":{"type":"number","description":"Нижняя граница","example":1},"max":{"type":"number","nullable":true,"description":"Верхняя граница. null — не ограничена.","example":33}},"required":["name","unit","min","max"]},"VehicleDto":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","description":"Идентификатор машины. Годится как `truckId` в POST /calculate/ftl.","example":"2f1c3c9e-3c5e-4d0a-9a53-1a2b3c4d5e6f"},"name":{"type":"string","description":"Название машины","example":"20 тонн : 92 куба"},"capacity_kg":{"type":"number","description":"Грузоподъёмность, кг","example":20000},"volume_m3":{"type":"number","description":"Объём кузова, м³","example":89.96},"dimensions_m":{"description":"Габариты кузова, м","allOf":[{"$ref":"#/components/schemas/VehicleDimensionsDto"}]},"body_types":{"description":"Типы кузова, доступные для этой машины в расчёте. Кузова, которых нет в справочнике расчёта, в выдачу не попадают.","type":"array","items":{"$ref":"#/components/schemas/VehicleBodyTypeDto"}},"limits":{"description":"Дополнительные ограничения и характеристики","type":"array","items":{"$ref":"#/components/schemas/VehicleLimitDto"}}},"required":["uuid","name","capacity_kg","volume_m3","dimensions_m","body_types","limits"]},"CargoDto":{"type":"object","properties":{"height":{"type":"number","description":"Высота места, см","example":120},"length":{"type":"number","description":"Длина места, см","example":120},"width":{"type":"number","description":"Ширина места, см","example":80},"places":{"type":"number","description":"Количество мест","example":2},"weight":{"type":"number","description":"Вес одного места, кг","example":300},"rotable":{"type":"boolean","description":"Можно ли поворачивать груз и класть на бок","example":true},"stackable":{"type":"boolean","description":"Можно ли ставить на груз другой груз","example":false}},"required":["height","length","width","places","weight","rotable","stackable"]},"LtlCalculationDto":{"type":"object","properties":{"points":{"minItems":2,"maxItems":2,"description":"ФИАС города отправления и города назначения","example":["0c5b2444-70a0-4932-980c-b4dc0d3f02b5","c2deb16a-0330-4f05-821f-1d09c93331e6"],"type":"array","items":{"type":"string","format":"uuid"}},"insurance":{"type":"number","description":"Объявленная стоимость груза для страхования, ₽. 0 — оценивается по весу.","example":0},"dimensions":{"minItems":1,"description":"Грузовые места: габариты и вес каждого места","type":"array","items":{"$ref":"#/components/schemas/CargoDto"}}},"required":["points","insurance","dimensions"]},"CalculationServiceDto":{"type":"object","properties":{"name":{"type":"string","description":"Название услуги","example":"Доставка"},"slug":{"type":"string","description":"Код услуги","example":"delivery"},"value":{"type":"number","description":"Стоимость услуги, ₽. Скидки — отрицательным числом.","example":45000}},"required":["name","slug","value"]},"CalculationResponseDto":{"type":"object","properties":{"total":{"type":"number","description":"Итоговая стоимость со всеми надбавками, ₽","example":45000},"currency":{"type":"string","enum":["RUB"],"description":"Валюта","example":"RUB"},"loading_date":{"type":"string","format":"date-time","nullable":true,"description":"Плановая дата подачи транспорта под загрузку, ISO-8601","example":"2026-09-14T00:00:00+03:00"},"delivery_date":{"type":"string","format":"date-time","nullable":true,"description":"Плановая дата доставки, ISO-8601","example":"2026-09-16T00:00:00+03:00"},"delivery_days":{"type":"integer","nullable":true,"description":"Срок в пути, сутки","example":2},"services":{"description":"Детализация по услугам; сумма строк равна `total`","type":"array","items":{"$ref":"#/components/schemas/CalculationServiceDto"}}},"required":["total","currency","loading_date","delivery_date","delivery_days","services"]},"FtlCalculationDto":{"type":"object","properties":{"points":{"minItems":2,"maxItems":2,"description":"ФИАС города отправления и города назначения","example":["0c5b2444-70a0-4932-980c-b4dc0d3f02b5","c2deb16a-0330-4f05-821f-1d09c93331e6"],"type":"array","items":{"type":"string","format":"uuid"}},"insurance":{"type":"number","description":"Объявленная стоимость груза для страхования, ₽. 0 — оценивается по весу.","example":0},"truckId":{"type":"string","format":"uuid","description":"Идентификатор машины — поле `uuid` из `GET /vehicles`","example":"2f1c3c9e-3c5e-4d0a-9a53-1a2b3c4d5e6f"},"truckType":{"type":"string","enum":["Тент","Борт","Изотерм","Реф"],"description":"Тип кузова. Должен быть среди `body_types` выбранной машины в `GET /vehicles`.","example":"Тент"},"dop":{"type":"array","description":"Дополнительное оснащение. Пустая строка — без дополнений","example":["ремни"],"items":{"type":"string","enum":["ремни","коники","деревянный пол","обрешетка","Гидроборт"]}},"load":{"type":"string","enum":["Зад","Зад/Бок","Зад/Верх","Зад/Бок/Верх",""],"description":"Способ загрузки. Пустая строка — без требований.","example":"Зад"},"weight":{"type":"number","description":"Вес груза, кг","example":5000}},"required":["points","insurance","truckId","truckType","dop","load","weight"]}}}}