{"components":{"schemas":{"Bank":{"properties":{"bankId":{"pattern":"^[0-9]{12}$","type":"string"},"bics":{"items":{"type":"string"},"type":"array"},"createdAt":{"example":"2026-07-29T09:00:54.628Z","type":"string"},"iconFile":{"type":["string","null"]},"isActive":{"type":"boolean"},"name":{"type":"string"},"shortName":{"type":["string","null"]},"source":{"type":["string","null"]},"updatedAt":{"example":"2026-07-29T09:00:54.628Z","type":"string"}},"type":"object"},"Binding":{"properties":{"bankId":{"pattern":"^[0-9]{12}$","type":"string"},"isPrimary":{"type":"boolean"},"paymentSystem":{"enum":["MIR","VISA","MASTERCARD","UP"],"type":"string"},"source":{"type":"string"}},"required":["bankId"],"type":"object"},"Error":{"properties":{"code":{"enum":["INVALID_REQUEST","UNAUTHORIZED","BANK_NOT_FOUND","ICON_NOT_FOUND","MAPPING_CONFLICT","STORAGE_UNAVAILABLE","STORE_BUSY","INTERNAL_ERROR"],"type":"string"},"currentBankId":{"description":"Текущая привязка при MAPPING_CONFLICT","type":"string"},"iconStatus":{"enum":["found","icon_missing","bank_not_found"],"type":"string"},"matchedBy":{"enum":["bankId","bic","bin"],"type":"string"},"message":{"description":"Значение БИН в текст не попадает","type":"string"},"retryAfterSeconds":{"type":"integer"}},"required":["code","message"],"type":"object"},"ImportReport":{"properties":{"accepted":{"type":"integer"},"applied":{"type":"boolean"},"rejected":{"items":{"properties":{"bankId":{"type":"string"},"line":{"type":"integer"},"reason":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"Miss":{"properties":{"firstSeen":{"type":"string"},"iconStatus":{"enum":["icon_missing","bank_not_found"],"type":"string"},"keyType":{"enum":["bank_id","bic","bin"],"type":"string"},"keyValue":{"description":"Для bin — не более 8 цифр","type":"string"},"lastSeen":{"type":"string"},"requestCount":{"type":"integer"},"resolvedBankId":{"type":["string","null"]}},"type":"object"},"ResolveResponse":{"properties":{"bankId":{"type":"string"},"bankName":{"type":"string"},"bics":{"items":{"type":"string"},"type":"array"},"iconStatus":{"enum":["found","icon_missing"],"type":"string"},"iconUrl":{"description":"null, когда банк известен, а файла иконки нет","type":["string","null"]},"matchedBy":{"enum":["bankId","bic","bin"],"type":"string"},"matchedValue":{"description":"Для bin — совпавший префикс из справочника, а не вход потребителя","type":"string"}},"required":["bankId","bankName","bics","matchedBy","matchedValue","iconStatus"],"type":"object"}},"securitySchemes":{"adminToken":{"description":"В локальном профиле не требуется","in":"header","name":"X-Admin-Token","type":"apiKey"}}},"info":{"description":"Сервис иконок банков по id / БИК / БИН. Принимает любой из трёх идентификаторов, сводит к каноническому bank_id и отдаёт иконку.","title":"bank-icon-serv","version":"2.0.0"},"openapi":"3.1.0","paths":{"/api/v1/admin/banks":{"get":{"parameters":[{"in":"query","name":"isActive","schema":{"type":"boolean"}},{"in":"query","name":"source","schema":{"type":"string"}},{"description":"Вхождение в наименование","in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"default":100,"type":"integer"}},{"in":"query","name":"offset","schema":{"default":0,"type":"integer"}}],"responses":{"200":{"description":"Постраничная выдача"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"STORE_BUSY: хранилище занято или недоступно"}},"security":[{"adminToken":[]}],"summary":"Список банков","tags":["admin"]},"post":{"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Bank"}}},"required":true},"responses":{"201":{"description":"Банк создан"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"MAPPING_CONFLICT: банк с таким id уже есть"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"STORE_BUSY"}},"security":[{"adminToken":[]}],"summary":"Создание банка","tags":["admin"]}},"/api/v1/admin/banks/{bankId}":{"delete":{"parameters":[{"in":"path","name":"bankId","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Удалён"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Банк не найден"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"STORE_BUSY"}},"security":[{"adminToken":[]}],"summary":"Удаление вместе с БИК и БИН (каскад)","tags":["admin"]},"get":{"parameters":[{"in":"path","name":"bankId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Банк"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Банк не найден"}},"security":[{"adminToken":[]}],"tags":["admin"]},"put":{"parameters":[{"in":"path","name":"bankId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Bank"}}},"required":true},"responses":{"200":{"description":"Изменённый банк"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Банк не найден"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"STORE_BUSY"}},"security":[{"adminToken":[]}],"summary":"Правка полей, включая isActive и iconFile","tags":["admin"]}},"/api/v1/admin/bics":{"get":{"parameters":[{"in":"query","name":"bankId","schema":{"type":"string"}}],"responses":{"200":{"description":"Список БИК"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"}},"security":[{"adminToken":[]}],"tags":["admin"]}},"/api/v1/admin/bics/{bic}":{"delete":{"parameters":[{"in":"path","name":"bic","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Привязка снята"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Привязка не найдена"}},"security":[{"adminToken":[]}],"tags":["admin"]},"put":{"parameters":[{"in":"path","name":"bic","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Binding"}}},"required":true},"responses":{"204":{"description":"Привязано"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"MAPPING_CONFLICT: БИК занят другим банком, в теле currentBankId"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"STORE_BUSY"}},"security":[{"adminToken":[]}],"summary":"Привязка БИК к банку","tags":["admin"]}},"/api/v1/admin/bins":{"get":{"parameters":[{"in":"query","name":"bankId","schema":{"type":"string"}}],"responses":{"200":{"description":"Список БИН"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"}},"security":[{"adminToken":[]}],"tags":["admin"]}},"/api/v1/admin/bins/{bin}":{"delete":{"parameters":[{"in":"path","name":"bin","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Привязка снята"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Привязка не найдена"}},"security":[{"adminToken":[]}],"tags":["admin"]},"put":{"parameters":[{"in":"path","name":"bin","required":true,"schema":{"pattern":"^[0-9]{6}([0-9]{2})?$","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Binding"}}},"required":true},"responses":{"204":{"description":"Привязано"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"MAPPING_CONFLICT: БИН занят другим банком"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"STORE_BUSY"}},"security":[{"adminToken":[]}],"summary":"Привязка БИН к банку; в справочнике допустимы только 6 или 8 цифр","tags":["admin"]}},"/api/v1/admin/import":{"post":{"parameters":[{"in":"query","name":"mode","schema":{"enum":["insert","upsert"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}},"text/csv":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportReport"}}},"description":"Пакет применён"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportReport"}}},"description":"Пакет НЕ применён: список отклонённых строк с причинами"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"STORE_BUSY"}},"security":[{"adminToken":[]}],"summary":"Массовая загрузка. Одна транзакция: применяется целиком либо не применяется","tags":["admin"]}},"/api/v1/admin/misses":{"delete":{"responses":{"200":{"description":"Число вытесненных записей"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"}},"security":[{"adminToken":[]}],"summary":"Применить ограничители: retention и потолок с вытеснением","tags":["admin"]},"get":{"parameters":[{"in":"query","name":"iconStatus","schema":{"enum":["icon_missing","bank_not_found"],"type":"string"}},{"in":"query","name":"keyType","schema":{"enum":["bank_id","bic","bin"],"type":"string"}},{"description":"Нижняя граница lastSeen, ISO-8601 UTC","in":"query","name":"since","schema":{"type":"string"}},{"in":"query","name":"until","schema":{"type":"string"}},{"in":"query","name":"format","schema":{"enum":["json","csv"],"type":"string"}},{"in":"query","name":"limit","schema":{"default":1000,"type":"integer"}}],"responses":{"200":{"description":"Реестр в JSON либо CSV"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"}},"security":[{"adminToken":[]}],"summary":"Выгрузка реестра промахов, по убыванию частоты","tags":["admin"]}},"/api/v1/admin/reindex-icons":{"post":{"responses":{"200":{"description":"Размер индекса, доступность, расхождения"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"}},"security":[{"adminToken":[]}],"summary":"Принудительная пересборка индекса наличия иконок","tags":["admin"]}},"/api/v1/admin/reload":{"post":{"responses":{"200":{"description":"Число банков и БИН в новом словаре"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"UNAUTHORIZED"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"STORE_BUSY"}},"security":[{"adminToken":[]}],"summary":"Принудительное перестроение словаря в памяти","tags":["admin"]}},"/api/v1/banks":{"get":{"parameters":[{"description":"Member id СБП, ровно 12 цифр","in":"query","name":"bankId","required":false,"schema":{"pattern":"^[0-9]{12}$","type":"string"}},{"description":"БИК, ровно 9 цифр","in":"query","name":"bic","required":false,"schema":{"pattern":"^[0-9]{9}$","type":"string"}},{"description":"БИН карты, 6-19 цифр; усекается до 8 до любой другой обработки","in":"query","name":"bin","required":false,"schema":{"pattern":"^[0-9]{6,19}$","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveResponse"}}},"description":"Банк найден. iconStatus различает found и icon_missing","headers":{"X-Bank-Icon-Status":{"description":"Причина результата. Присутствует на 200, 304 и 404 — там, где причина определена данными; на 400 и 503 не проставляется","schema":{"enum":["found","icon_missing","bank_not_found"],"type":"string"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Ни одного идентификатора, больше одного, либо неверная форма"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Идентификатор не разрешился: BANK_NOT_FOUND"}},"summary":"Банк и адрес его иконки: ровно один из bankId | bic | bin","tags":["public"]}},"/api/v1/banks/icon":{"get":{"parameters":[{"description":"Member id СБП, ровно 12 цифр","in":"query","name":"bankId","required":false,"schema":{"pattern":"^[0-9]{12}$","type":"string"}},{"description":"БИК, ровно 9 цифр","in":"query","name":"bic","required":false,"schema":{"pattern":"^[0-9]{9}$","type":"string"}},{"description":"БИН карты, 6-19 цифр; усекается до 8 до любой другой обработки","in":"query","name":"bin","required":false,"schema":{"pattern":"^[0-9]{6,19}$","type":"string"}}],"responses":{"200":{"content":{"image/png":{"schema":{"format":"binary","type":"string"}}},"description":"Файл иконки","headers":{"X-Bank-Icon-Status":{"description":"Причина результата. Присутствует на 200, 304 и 404 — там, где причина определена данными; на 400 и 503 не проставляется","schema":{"enum":["found","icon_missing","bank_not_found"],"type":"string"}}}},"304":{"description":"ETag совпал с If-None-Match","headers":{"X-Bank-Icon-Status":{"description":"Причина результата. Присутствует на 200, 304 и 404 — там, где причина определена данными; на 400 и 503 не проставляется","schema":{"enum":["found","icon_missing","bank_not_found"],"type":"string"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Неверный запрос"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"BANK_NOT_FOUND либо ICON_NOT_FOUND"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"INTERNAL_ERROR: файл больше лимита либо испорченная ссылка"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"STORAGE_UNAVAILABLE: каталог иконок недоступен"}},"summary":"Иконка банка: тот же вход, вместо JSON — сам файл","tags":["public"]}},"/healthz/live":{"get":{"responses":{"200":{"description":"Жив"}},"summary":"Живость: не зависит ни от каталога иконок, ни от базы","tags":["service"]}},"/healthz/ready":{"get":{"responses":{"200":{"description":"Готов"},"503":{"description":"Каталог иконок недоступен"}},"summary":"Готовность: учитывает каталог иконок, НЕ учитывает базу","tags":["service"]}},"/icons/{file}":{"get":{"parameters":[{"in":"path","name":"file","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"image/png":{"schema":{"format":"binary","type":"string"}}},"description":"Файл иконки"},"304":{"description":"ETag совпал"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Файл не найден либо имя выводит за пределы каталога"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Хранилище иконок недоступно"}},"summary":"Локальная отдача файла иконки (только локальный профиль)","tags":["public"]}},"/metrics":{"get":{"responses":{"200":{"description":"Текстовый формат Prometheus"}},"summary":"Метрики в формате Prometheus","tags":["service"]}}},"servers":[{"url":"/"}]}