Все запросы требуют заголовок Authorization: Bearer <токен>
Токены хранятся в src/Presentation.ViewModels/ServerApiCredentials.cs
| Константа | Префикс | Права |
|---|---|---|
| CalibrationBearer | cal_ | Чтение и запись калибровок |
| TrainingEvidenceBearer | tek_ | Загрузка captures, records |
| TrainingEvidenceInventoryBearer | teinv_ | Чтение, листинг, summary |
| DistributionBearer | dist- | Загрузка дистрибутивов |
Флаги DB: CanUploadTrainingEvidence, CanHardDeleteTrainingEvidence, CanUploadDistributions. Превышение лимита → 429.
Возвращает полный активный профиль (включая profileJson) для серийного номера прибора.
| Путь | Описание |
|---|---|
| serial* | Серийный номер прибора (напр. 0454628) |
200: { "schemaVersion":"calibration-profile/v1", "calibrationId":"cal-...", "deviceSerial":"0454628",
"computedAt":"2026-06-18T01:44:53Z", "rmsStereoPx":0.803, "baselineMm":3.556,
"k5Passed":true, "isRecommendedActive":true, "profileJson":{...} }
404: { "errorCode":"calibration_not_found" }
Поиск калибровки по SHA заводской EEPROM прибора. Используется клиентом, когда серийник из EEPROM невалиден (например, прибор 1/11 репортит серийник "11" — номер модели, не уникальный).
Формат eepromSha: 64 hex-символа нижнего регистра, SHA-256 от строки "<block1_hex>\r\n<block2_hex>" (два 80-байтных EEPROM-блока, формат legacy_eeprom_block_pair).
Таблица соответствий: dbo.DeviceEepromKey. Текущие записи: прибор 0454628 (sha 00585a32…).
200: полный active-профиль (тот же формат что /devices/{serial}/active)
404: { "errorCode":"calibration_not_found" } — нет маппинга или нет active-калибровки
422: { "errorCode":"calibration_schema_invalid" } — eepromSha не 64 hex
Б-044 / 2026-07-01. Клиентский резолвер: если /devices/{serial}/active → 404, вычислить eepromSha и обратиться к этому эндпоинту.
Возвращает серийный номер прибора по SHA заводской EEPROM, БЕЗ требования наличия активной калибровки — в отличие от /active, отвечает 200 даже если калибровки ещё нет. Используется для онбординга нового прибора (клиент узнаёт свой серийник по хэшу EEPROM до первой калибровки).
Формат eepromSha: тот же, что у /active (64 hex нижнего регистра).
200: { "deviceSerial":"0454628", "eepromSha":"00585a32...", "createdAt":"2026-07-01T12:46:55Z",
"canonicalEepromSha":"...", "hashConvention":"sha256(bytes-canonical(left,right))/v1",
"enrolment": { "romReceivedAtUtc":"2026-08-27T19:13:04Z",
"identityRegisteredAtUtc":"2026-07-01T12:46:55Z",
"activeProfileBoundAtUtc":"2026-08-18T06:02:23Z",
"activeProfileBoundAtSource":"activation" } }
404: { "errorCode":"eeprom_key_not_found",
"message":"... Read the serial number printed on the device label and register it ...",
"deviceSerialRequiredFrom":"printed_label_or_operator",
"registerRoute":"POST /devices/by-eeprom/{eepromSha}/register",
"enrolment": { "romReceivedAtUtc":"2026-08-27T19:13:04Z",
"identityRegisteredAtUtc":null, "activeProfileBoundAtUtc":null } }
422: { "errorCode":"calibration_schema_invalid" } — eepromSha не 64 hex
Задача 1824 (закон Ф-11). Блок enrolment отвечает на три ОТДЕЛЬНЫХ вопроса, потому что они расходятся: ПЗУ прибора может лежать на сервере, а личности и профиля не быть — ровно так живёт прибор 32eb0ee7… с 27.08. Одно слово «известен» это состояние не описывает и отправляет инженера чинить работающую загрузку.
Серийного номера НЕТ внутри прибора. Полный скан 32 КиБ (#1823) серийника не содержит: DeviceId равен 1 у живого прибора и 11 у 0454628, и это не печатный номер. Поэтому 404 не «ошибка сервера», а требование второго шага: прочитать номер с наклейки и вызвать /register. Тело 404 говорит это словами оператора и называет маршрут.
B18 / 2026-07-07; enrolment и текст 404 — задача 1824 / 2026-09-05.
Сохраняет соответствие SHA заводской EEPROM → серийный номер прибора (заполняет dbo.DeviceEepromKey). Используется, когда хэш ещё неизвестен серверу: пользователь вводит серийник вручную, клиент регистрирует пару, дальше /identity и /active резолвят её автоматически.
Идемпотентно: повторная регистрация того же хэша с тем же серийником → 200. С ДРУГИМ серийником → 409 (перезапись запрещена, конфликт). Серийник, уже закреплённый за ДРУГИМ прибором (другой канонический SHA; устаревшие хэши того же прибора, помеченные SupersededByEepromSha, не считаются другим прибором) → 409 serial_owned_by_other_rom (28.09): один серийник — один прибор, иначе оба получили бы одну калибровку.
| Поле тела | Описание |
|---|---|
| deviceSerial* | Серийный номер прибора (ASCII, до 250 симв.). Источник — только ВНЕ прибора: печатная наклейка или ввод оператора. В памяти прибора серийника нет (#1823, полный скан 32 КиБ), поэтому сервер его не выводит и не угадывает. |
| note | Опциональная заметка (до 500 симв.) |
201: { "deviceSerial":"0454628", "eepromSha":"00585a32...", "createdAt":"...", "alreadyRegistered":false }
200: { "deviceSerial":"0454628", "eepromSha":"...", "alreadyRegistered":true } — уже была та же пара
409: { "errorCode":"eeprom_key_conflict", "deviceSerial":"<существующий>" } — хэш занят ДРУГИМ серийником
409: { "errorCode":"serial_owned_by_other_rom", "deviceSerial":"<запрошенный>", "details":"ownerEepromSha=<канонический SHA владельца>" } — серийник уже принадлежит ДРУГОМУ прибору (другой канонический SHA); ничего не записано
422: { "errorCode":"calibration_schema_invalid" } — eepromSha не 64 hex, либо deviceSerial отсутствует/невалиден
B18 / 2026-07-07. Валидация серийника против ERP (ItemSn) НЕ выполняется — VeriDepthDB изолирована от IntekDB по Б-044.
Сохраняет два 80-байтных блока «окна личности» под их SHA-256. Идемпотентно по содержимому: те же байты → 200 isNew:false, ничего не пишется; ДРУГИЕ байты под тем же хэшем → 409.
| Поле тела | Описание |
|---|---|
| romBase64* | Байты ПЗУ в канонном порядке |
| sha256* | SHA-256 этих байтов; должен совпасть и с путём, и с содержимым |
| crcValid | Сошлась ли CRC при чтении |
| deviceModel | До 128 символов |
| appVersion | До 128 символов (было 64 до задачи 1788 — строка сборки продукта в 81 символ девять раз получала 422) |
| whiteBalance | Необязательный массив квадов по камерам (задача 1824). Продукт, который его не шлёт, кладётся как раньше — это проверяется тестом на точном запросе 1782. Поля элемента: did (256/257 у 1/11), r, gr, gb, b (0..255 либо null), source (rom | vendor_awb | white_sheet), readAtUtc, romOffset (у 1/11 "0x01D0"). |
null значит «не прочитано» и никогда «нули». У левой камеры живого прибора синий множитель действительно равен 0 (99, 21, 17, 0) — это измерение, а не отсутствие данных, и сервер эти два состояния различает.
201/200: { "eepromSha":"...", "romSize":160, "storedAt":"...", "isNew":true|false, "whiteBalanceStored":2 }
409: { "errorCode":"factory_rom_mismatch" } — под этим хэшем уже лежат ДРУГИЕ байты
422: { "errorCode":"calibration_schema_invalid" | "rom_sha_path_mismatch" | "rom_sha_mismatch" | "rom_payload_invalid" }
whiteBalance — задача 1824 / 2026-09-05 (закон Ф-11, предложение #1823). Хэш личности FactoryRomIdentity НЕ меняется: он считается по двум 80-байтным блокам и только по ним, иначе добавление поля переименовало бы каждый прибор в архиве.
200: { "uploadId":32, "eepromSha":"...", "romSize":160, "crcValid":true,
"algorithm":"sha256(left||right)/v1", "receivedAtUtc":"2026-08-27T19:13:04Z",
"canonicalEepromSha":"...", "hashConvention":null,
"whiteBalance":[ { "did":256, "r":99, "gr":21, "gb":17, "b":0,
"source":"rom", "readAtUtc":"...", "romOffset":"0x01D0" } ],
"enrolment": { "romReceivedAtUtc":"...", "identityRegisteredAtUtc":null,
"activeProfileBoundAtUtc":null, "activeProfileBoundAtSource":null } }
404: { "errorCode":"factory_rom_not_found" }
Поля whiteBalance и enrolment добавлены задачей 1824; всё, что было раньше, сохранило имя и смысл.
Закон Ф-11: всё, что лежит в памяти прибора, должно быть записано в систему. Строка ПЗУ описывает 160-байтное «окно личности»; сюда кладётся ВСЯ память, по камерам (did 256/257 — у каждой камеры своя). Байты и маска хранятся в общем blob-хранилище и адресуются своим SHA-256, поэтому повторная отправка того же дампа ничего не дублирует (200 isNew:false).
| Поле тела | Описание |
|---|---|
| did* | Камера: 256 / 257 |
| dumpBase64* | Байты дампа |
| sha256* | SHA-256 дампа; расхождение → 422 memory_dump_sha_mismatch |
| sizeBytes* | Длина дампа; расхождение → 422 memory_dump_size_mismatch |
| readMaskBase64* | Обязательна. По байту на адрес: прочитан / нет. Без маски «прочитано 65536 из 65536» — утверждение о нашем цикле, а не о приборе: непрочитанный байт неотличим от стёртого 0xFF. Ровно этот дефект чинила #1779. Длина должна совпадать с дампом. |
| mirrorPeriod* | Ключ обязателен, значение может быть null (зеркала не найдено). Полное чтение НЕ доказывает объём памяти: маленькая EEPROM отвечает на старшие адреса копией младших и рапортует успех на каждом. |
| readAtUtc* | Когда снято |
| readerVersion* | Чем снято, до 256 символов (напр. Capture.Cli camlh-dump-eeprom @ 8da5b0e9) |
201/200: { "eepromSha":"...", "did":256, "sha256":"...", "sizeBytes":32768,
"blobRef":"...", "readMaskRef":"...", "mirrorPeriod":32768, "isNew":true|false }
422: { "errorCode":"read_mask_required" | "mirror_period_required" | "read_mask_length_mismatch" |
"memory_dump_sha_mismatch" | "memory_dump_size_mismatch" | "memory_dump_payload_invalid" }
Задача 1824 / 2026-09-05. Снимать по команде, а не при каждом подключении: 65 536 чтений регистров занимают минуты и держат камеру, а держатель может быть только один.
Только метаданные: сами байты остаются в хранилище и названы через blobRef / readMaskRef, чтобы список не тащил по 64 КиБ на камеру.
200: { "eepromSha":"...", "memoryDumps":[
{ "did":256, "sha256":"...", "sizeBytes":32768, "blobRef":"...", "readMaskRef":"...",
"mirrorPeriod":32768, "readAtUtc":"...", "readerVersion":"...", "receivedAtUtc":"..." } ] }
Единственный маршрут без ключа. Используется деплоем (tools/Deploy-VeriDepthServer.ps1, шаг 7) как признак того, что приложение поднялось после копирования файлов.
200: {"status":"ok"}
Список всех записей ПЗУ: uploadId, eepromSha, romSize, crcValid, algorithm, deviceModel, appVersion, receivedAtUtc. Сами байты не отдаются — за ними в /devices/by-eeprom/{eepromSha}/factory-rom.
200: { "factoryRoms":[ { "uploadId":32, "eepromSha":"...", "romSize":160, ... } ] }
Тело — application/zip. Профиль {calibrationId} должен существовать и не быть удалён, иначе архив прицепился бы к удалённой записи. Хранится в dbo.ApiBinaryBlob со scope архивов; SHA-256 считается по принятым байтам.
201: { "calibrationId":"cal-...", "storedAt":"...", "isActive":false }
404: профиль не найден 422: неверный Content-Type или пустое тело
Изделие вызывает этот маршрут сразу после POST /captures, чтобы убедиться, что загрузка легла (PrototypeTrainingEvidenceUploader.VerifyCaptureAsync). Ему достаточно 2xx, тело которого СОДЕРЖИТ этот же sha, плюс необязательная строка formatVersion.
Съёмка, у которой пропал blob, всё равно отвечает 200 с hasBlob:false. Вопрос маршрута — «легла ли моя загрузка», а строка и есть загрузка; 404 здесь воспроизводил бы ровно ту ложную неудачу, ради которой маршрут и заведён (задача 1796: 574 вызова с 404 с 12 июня, пока маршрут не существовал).
200: { "sha256":"...", "sizeBytes":2624721, "contentType":"image/png",
"formatVersion":"training-evidence-capture/png/v1", "sourceClass":null,
"deviceId":"...", "calibrationRef":"...", "hasBlob":true }
404: { "errorCode":"capture_not_found" }
Задача 1796 / 2026-09-05.
Изделие вызывает его после измерения, чтобы приписать к съёмке описание и качество (TrainingEvidenceMeasurementSync.PostReingestAsync). Требует ключ с правом CanUploadTrainingEvidence.
| Поле тела | Описание |
|---|---|
| dryRun | По умолчанию true: кто не сказал иначе, получает предпросмотр и НИКАКОЙ записи. Изделие шлёт false явно. |
| formatVersion | До 80 символов; если прислан, formatVersionSource становится manual_reingest |
| description / notes | До 2000 символов |
| quality | Число |
| deviceId, hardwareDeviceId, calibrationRef, sourceClass, sourceCreatedAtUtc | Тоже принимаются; поле, которого нет в теле, сохраняет текущее значение (COALESCE) |
applied означает, что строка изменилась, а не что мы не были в режиме предпросмотра. Соседнее приложение на этом же сервере отвечает applied = Not dryRun — и 20–21 июня выдало 2008 «успехов», не изменив ни одной строки (его база стояла с 12 июня). Здесь applied истинно только когда UPDATE прошёл и затронул строку, а rowsUpdated называет их число.
Порядок отказов: 403 раньше 400. Право ключа проверяется ПЕРВЫМ, до формата sha256. Значит ключ без CanUploadTrainingEvidence получит 403 даже на заведомо кривом хэше — и клиент, отлаживающий хэш не тем ключом, услышит жалобу не на то. Поведение оставлено как есть (так же устроен обработчик, у которого прочитана форма), но теперь об этом написано: увидели 403 — сначала проверьте ключ, а не съёмку.
200: { "sha256":"...", "dryRun":false, "applied":true, "rowsUpdated":1,
"changes":{ "description":{"from":"...","to":"..."} },
"before":{...}, "after":{...} }
403: нет права 400: плохой sha, неверный JSON, слишком длинное поле 404: съёмки нет
Задача 1861 / 2026-09-05. Форма прочитана у соседнего приложения (T1860), а не угадана по клиенту.
Возвращает идентификатор сессии и токены; по ним работают маршруты /{sessionId}/publish и /{sessionId}/watch (рукопожатия WebSocket, авторизуются токеном в URL, а не ключом — поэтому в каталоге их нет).
201: { "sessionId":"...", "publishUrl":"...", "watchUrl":"...", "viewerUrl":"..." }
200: { "sessions":[ { "sessionId":"...", "state":"...", "createdAt":"..." } ] }200: { "sessionId":"...", "state":"...", "publisherConnected":true, "viewers":1 }
404: сессия не найденаТо же, что POST /{sessionId}/stop — два способа сказать одно и то же, оба поддерживаются.
200: { "sessionId":"...", "state":"stopped" }200: { "sessionId":"...", "state":"stopped" }С задачи 1897 все маршруты реконструкции требуют ключ — тот же, что и загрузка съёмок.
Нет ключа или он не живой → 401 unauthorized; живой ключ без права CanUploadTrainingEvidence
→ 403 forbidden. Проверено на живом сервере 06.09.2026: без ключа 401, ключ калибровок 403, ключ обучающих данных 200.
Ключа «только на чтение» не существует. Право одно — то же, что разрешает загружать съёмки,
поэтому потребитель, которому нужны только облака, не может обойтись без права загрузки. Это осознанное состояние,
а не упущение: отдельная возможность будет заведена тогда, когда появится такой потребитель, и не раньше (решение 1913).
Оператор к этому не относится — страница Viewer3D.aspx сама читает модель из базы и ключа не требует.
200: { "jobs":[ { "status":"done", "count":619 } ] }
201/200: { "jobId":123, "status":"pending" }200: { "jobId":123, "status":"done|pending|running|failed", "errorMessage":null }
404: задания нетОтдаёт model/gltf-binary из dbo.ReconstructionResult.ResultBlob — это единственное место, где хранится результат; в dbo.ApiBinaryBlob его нет.
Читается страницей Viewer3D.aspx. Отдаёт MeasurementPoints3dJson, посчитанный воркером; endpoints3d — те же концы отрезка, что на снимке, но в миллиметрах.
200: [ { "endpoints3d":[{"x":0.658,"y":-2.806,"z":10.736}, ...], "computedValueMm":null } ]
Список всех калибровок прибора (метаданные, без profileJson). Используется клиентом для версионного резолва.
200: { "deviceSerial":"0454628", "calibrations":[
{ "calibrationId":"cal-...", "isActive":true, "uploadedAt":"...", "rmsStereoPx":0.803, "baselineMm":3.556 }
] }
| Заголовок | Значение |
|---|---|
| Content-Type* | application/json |
| X-Content-SHA256* | SHA-256 hex тела запроса |
Тело — JSON схемы calibration-profile/v1. Обязательные поля: schemaVersion, calibrationId, deviceSerial, rmsStereoPx, baselineMm, k5Passed, profileJson.
201: { "calibrationId":"cal-...", "storedAt":"...", "isActive":true }
409: { "errorCode":"calibration_already_exists" }
409: { "errorCode":"device_not_registered", "deviceSerial":"..." } — серийник не найден в реестре приборов IntekDB.ItemSn
422: { "errorCode":"calibration_schema_invalid", "details":"..." }
ItemSnID резолвится автоматически из IntekDB.dbo.ItemSn по DeviceSerial (кросс-БД, один сервер) — ручная регистрация в ItemSnCalibration не нужна, если прибор уже стоит на учёте в ERP.
Помечает калибровку удалённой (IsDeleted=1). Данные сохраняются в БД.
200: { "deleted":true }
404: { "errorCode":"calibration_not_found" }
| Заголовок | Описание |
|---|---|
| Content-Type* | image/png |
| X-Content-SHA256* | SHA-256 hex тела (64 символа) |
| X-Artifact-Uid | Стабильный UID артефакта (опц.) |
Тело — бинарный PNG. Сервер извлекает DeviceId, CalibrationRef, HardwareDeviceId из tEXt Metadata внутри PNG. Повторная загрузка идемпотентна.
201/200: { "sha256":"...", "sizeBytes":1048576, "alreadyExisted":false,
"extractedDeviceId":"0454628", "evidenceDeviceId":"0454628",
"hardwareDeviceId":"intek-1_11:vid_192a_pid_0803",
"extractedCalibrationRef":"cal-...", "artifactUid":null }
| Заголовок | Описание |
|---|---|
| Content-Type* | video/x-msvideo |
| X-Format-Version* | stereo-scan-video/v1 |
| X-Content-SHA256* | SHA-256 hex тела |
| X-Device-Id* | ID устройства (напр. 0454628) |
| X-Hardware-Device-Id | Hardware ID (опц.) |
| X-Calibration-Ref | ID калибровки (опц.) |
| X-Artifact-Uid | Стабильный UID артефакта (опц.) |
Тело — AVI-файл, стерео side-by-side (левый|правый кадр, RGB24). Метаданные из заголовков.
201/200: { "sha256":"...", "sizeBytes":123456, "alreadyExisted":false,
"formatVersion":"stereo-scan-video/v1", "sourceClass":"scan",
"evidenceDeviceId":"...", "artifactUid":"..." }
Возвращает бинарный файл (PNG или AVI) с оригинальным Content-Type.
200: <binary body>
404: { "errorCode":"capture_not_found" }
| Параметр | Тип | Описание |
|---|---|---|
| sha256* | path | SHA-256 оригинального capture (64 hex-символа) |
| engine* | query | Идентификатор движка: cre, sgbm, hitnet и т.д. Regex: ^[a-z0-9-]{1,32}$ |
| тело* | Content-Type: image/png | PNG-рендер 3D-превью от клиентского Audit3DPreviewRenderer |
Хранится в dbo.ApiBinaryBlob с scope te-preview-{engineId}. Идемпотентно (upsert по sha256+engine). Требует флаг CanUploadTrainingEvidence.
200: { "stored":true, "captureSha256":"...", "engineId":"cre", "previewSizeBytes":45678 }
400: { "errorCode":"empty_body" | "invalid_payload" | "invalid_engine" }
403: { "errorCode":"forbidden" }
| Параметр | Тип | Описание |
|---|---|---|
| sha256* | path | SHA-256 оригинального capture |
| engine* | query | Идентификатор движка (тот же, что при POST) |
200: <image/png binary> — превью от указанного движка
404: { "errorCode":"preview_not_found" } — превью ещё не загружено
400: { "errorCode":"invalid_engine" }
Для отображения в браузере без токена используйте PreviewImage.aspx?sha={sha}&engine={engineId} (admin-только).
| Заголовок | Значение |
|---|---|
| Content-Type* | application/json |
Тело — JSON схемы training-evidence/v1. Обязательные поля:
{ "schemaVersion":"training-evidence/v1", "evidenceId":"gtpkg-...",
"captureSha256":"<sha256 PNG или видео>",
"deviceId":"0454628", "sourceClass":"point_to_point",
"conditionBucket":"standard", "consent":"explicit_opt_in",
"measurementJson":{...}, "groundTruthJson":{...} }
201/200: { "evidenceId":"...", "alreadyExisted":false }
404: { "errorCode":"capture_not_found" }
422: { "errorCode":"schema_invalid", "details":"..." }
| Query-параметр | Описание | По умолч. |
|---|---|---|
| limit | Кол-во (1–500) | 100 |
| offset | Смещение | 0 |
| deviceId | Фильтр по ID устройства | — |
| sourceClass | point_to_point, scan, … | — |
| conditionBucket | Условие съёмки | — |
| trainableForOwnDeviceBucket | true/false | — |
| hasGroundTruth | true/false | — |
| captureStatus | not_found — осиротевшие (нет живого capture) | — |
200: { "totalRecords":26, "totalCaptures":569, "referencedCaptures":23, "unreferencedCaptures":546,
"byDevice":{...}, "bySourceClass":{...},
"withGroundTruth":26, "trainableForOwnDeviceBucket":22 }
⚠ Endpoint /latest возвращает только версии, у которых есть оба артефакта: windows и linux-x64.
200: { "version":"0.9.7.25", "releasedAt":"...",
"windowsUrl":"/api/distributions/v1/0.9.7.25/windows",
"linuxUrl":"/api/distributions/v1/0.9.7.25/linux-x64",
"windowsSha256":"...", "linuxSha256":"...",
"windowsSizeBytes":156429678, "linuxSizeBytes":53124200 }
404: нет версии с обоими артефактами
В отличие от /latest, не требует наличия ОБОИХ артефактов — берёт самый новый релиз, у которого есть указанная платформа. platform: windows или linux-x64. Именно этот путь использует установщик клиента (DistributionUpdateClient.cs).
200: { "version":"0.9.7.25", "platform":"windows", "downloadUrl":"...", "sha256":"...",
"sizeBytes":78750873, "filename":"...", "releasedAt":"...", "releaseNotes":"..." }
400: distribution_schema_invalid (platform не windows/linux-x64)
404: distribution_not_found (нет ни одного релиза с этой платформой)
B24.2 / 2026-07-07. Портировано с itcworld (эталонная рабочая копия).
Все релизы (не только с обоими артефактами), отсортированы по семантической версии убыв.
200: { "items": [ { "version":"...", "releasedAt":"...", "releaseNotes":"...",
"windows":{...}, "linux_x64":{...} }, ... ] }
B24.2 / 2026-07-07.
Та же структура что /latest. Версия в формате N.N.N.N.
400: distribution_schema_invalid (неверный формат версии) 404: distribution_not_found
Возвращает бинарный архив (zip / tar.gz) для указанной версии и платформы.
Требует CanUploadDistributions=1.
| Заголовок | Значение |
|---|---|
| Content-Type* | application/zip (windows) или application/x-tar (linux) |
| X-Version* | Версия, напр. 0.9.7.26 |
| X-Platform* | windows или linux-x64 |
| X-Content-SHA256* | SHA-256 hex тела |
Все ошибки: { "errorCode":"...", "message":"...", "details":"..." }
| errorCode | HTTP | Значение |
|---|---|---|
| calibration_not_found | 404 | Калибровка не найдена |
| calibration_already_exists | 409 | CalibrationID уже в базе |
| calibration_schema_invalid | 422 | Нарушение схемы calibration-profile/v1 |
| capture_not_found | 404 | Capture по SHA256 не найден |
| schema_invalid | 400/422 | Неверный формат запроса |
| payload_integrity_mismatch | 400 | SHA256 тела не совпал с X-Content-SHA256 |
| method_not_allowed | 405 | Метод не поддерживается для этого пути |
| forbidden | 403 | Ключ не имеет нужного флага |
| distribution_not_found | 404 | Дистрибутив не найден |
| server_error | 500 | Внутренняя ошибка (детали в details) |
| # | Задача | Статус |
|---|---|---|
| Ф-2 | Re-key 701 PNG (через пересылку, без нового endpoint) | Через POST /captures |
| Ф-3 | Relink 14 осиротевших records | Через re-POST /records |
| Ф-6 | Rich EndpointArray (координаты в мм) | Стоп-гейт Владельца |