# AutoMask API: задания, исходники и архивы Обновлено 7 сентября 2026 года. Базовый путь: `/api/v1`. Машиночитаемая схема: `/api/openapi.json`. HTML-документация: `/docs/api`. ## Авторизация и совместимость Передавайте ключ заголовком `X-API-Key: YOUR_API_KEY` или `Authorization: Bearer YOUR_API_KEY`. Не помещайте ключ в URL. Новые ресурсы доступны по ключу; гостевой сценарий сохраняется у старого `POST /process`. Браузерные запросы с cookie защищены CSRF. Маршруты `/process`, `/analyze`, старый `GET /jobs/{id}`, `/` POST и `/info` сохранены. В ответ статуса добавлено поле `job`; старые поля остаются на месте. ## Независимые операции | mode | Результат | Стоимость успешного задания | |---|---|---| | plate | Фото со скрытым номером | 5 кредитов | | background | Новый фон, номер сохраняется | 5 кредитов | | studio_background | Новый фон и скрытие найденного номера | 5 кредитов | | plate_mask | PNG-маска номера без итогового фото | 5 кредитов | | background_mask | PNG-маска фона без итогового фото | 5 кредитов | | analyze | JSON-анализ фотографии | 1 кредит | В комбинированном режиме отсутствие номера не мешает замене фона. В режиме `plate`/`plate_mask` отсутствие номера означает неуспешное задание. Ненайденная маска фона — ошибка операций, которым нужен фон. Кредиты резервируются при постановке и списываются только за успех. Ошибка или отмена освобождает резерв. Кэш распознавания не меняет тариф: новая успешная обработка оплачивается заново. `plate_mask_only` — старый параметр способа закрашивания номера, а НЕ запрос только маски. Для этого используйте `mode=plate_mask`. ## Создание задания ```bash curl -X POST "$BASE/api/v1/jobs" \ -H "X-API-Key: $AUTOMASK_KEY" \ -H "Idempotency-Key: photo-123-background-v1" \ -F "file=@car.jpg" -F "mode=background" -F "background=studio" ``` Можно передать multipart `file`, URL изображения `url` или `asset_id`. JSON поддерживает `url`/`asset_id`; бинарные файлы передаются multipart. Задавайте один источник. URL проходит серверную проверку; переадресации запрещены. Поддерживаются JPG, PNG и WebP; размер ограничен `MAX_UPLOAD_MB` сервера. Параметры: `mode`, `background` (`studio`, `warm`, `graphite`, `showroom`), `background_file`, `plate_color` (`#RRGGBB`), `plate_smoothing`, `plate_mask_only`, `webhook_url`. Последние параметры обработки не используются режимом `analyze`. Неизвестные режим и пресет возвращают HTTP 400, а не заменяются молча. Успешная постановка задачи возвращает HTTP 202, `Location` и `Retry-After: 2`: ```json { "job": { "id": "job_...", "status": "queued", "operation": "background", "stage": "queued", "cancel_requested": false, "cost_credits": 5, "attempts": 0, "created_at": "2026-09-07T10:00:00", "started_at": null, "finished_at": null, "output": null, "error": null, "links": {"self": "/api/v1/jobs/job_..."} }, "idempotent_replay": false } ``` `Idempotency-Key` привязан к ключу доступа и типу операции. Повтор с тем же телом и файлами возвращает то же задание даже при уже зарезервированном балансе. Другие параметры/файлы с прежним ключом дают 409. Повторяйте запрос в том же формате: JSON и multipart не считаются одинаковыми. TTL записи соответствует сроку хранения заданий. Для старых записей без отпечатка проверка тела недоступна. URL сравнивается как строка; содержимое удалённого URL при повторе не скачивается. ## Исходник загружается один раз ```bash curl -X POST "$BASE/api/v1/assets" -H "X-API-Key: $AUTOMASK_KEY" -F "file=@car.jpg" # 201: {"asset_id":"asset_...","expires_at":"...","original_name":"car.jpg"} curl -X POST "$BASE/api/v1/jobs" -H "X-API-Key: $AUTOMASK_KEY" \ -H 'Content-Type: application/json' -H 'Idempotency-Key: variant-1' \ -d '{"asset_id":"asset_...","mode":"background","background":"warm"}' ``` Исходник принадлежит создавшему его ключу. Чужой ID даёт 404, истёкший — 410. До 100 активных исходников на ключ; срок хранения — `CLEANUP_DAYS`, по умолчанию 7 дней. Созданное задание получает свою копию файла и не зависит от дальнейшего истечения исходника. Загрузка доступна обычному активному ключу аккаунта. При повторной обработке того же изображения worker может использовать готовые маски и анализ. Кэш разделён по ключу, содержимому исходника, набору моделей, их путям/размерам/времени изменения и порогам. Цвет и пресет не запускают распознавание заново при наличии соответствующего кэша. `inference_cached` в результате показывает попадание. При обновлении алгоритма меняется версия кэша. ## Статусы и управление `GET /jobs/{id}` возвращает `job` и совместимые старые поля. Используйте `job.status`, а не старое булево `result`: `queued` → `processing` → `success` / `failed` / `cancelled`. Для элементов приостановленного архива возможен `paused`. `stage` для выполняемой задачи: `inference` или `finalizing`. Это этапы сервера, не процент прогресса и не прогноз времени. При `success` поле `output` содержит результат: `url`, `mask_url`, `plate_mask_url`, `background_mask_url`, `output_kind`, `analysis` и квоту. Для `analyze` URL изображения нет — результатом является анализ. Ссылки подписаны и ограничены по времени; повторно запросите статус для их обновления. | Маршрут | Поведение | |---|---| | GET /jobs?limit=25&before=123&status=queued | Задания текущего ключа; `next_cursor` для следующей страницы, limit 1–100 | | POST /jobs/{id}/cancel | Отмена одиночного задания | | POST /jobs/{id}/retry | Повтор неуспешного одиночного задания | | GET /files?limit=25&before=123 | Собственные файлы и подписанные ссылки | | DELETE /files/{id} | Удаление своего результата | Отмена ожидающей задачи немедленная, повтор отмены безопасен. Для выполняемой задачи возвращается 202 и `cancel_requested=true`: вызов модели заканчивается, после чего отмена фиксируется без списания кредитов. На этапе `finalizing` отмена уже невозможна (409). Успешное задание отменить нельзя. Отдельные задачи архива управляются через архив целиком. Повтор допускается только для `failed`, при наличии исходника и фона. Резерв создаётся заново; повтор уже поставленной задачи даёт 409. Истёкшие файлы — 410. Автоматические повторы временных ошибок остаются включены. Сбой сети и окончание ожидания клиента НЕ означают ошибку задания. Сохраните ID и продолжите опрос позже. Интерфейс сохраняет только ID в sessionStorage, не API-ключ. После перезагрузки при необходимости введите прежний ключ. ## Архивы через API ```bash curl -X POST "$BASE/api/v1/batches" -H "X-API-Key: $AUTOMASK_KEY" \ -F 'archive=@cars.zip' -F 'mode=background' ``` Ответ 202 содержит `batch` и `status_url`. ZIP доступен ключу активного аккаунта. Архив поддерживает пять режимов обработки, кроме `analyze`. `GET /batches/{id}` — прогресс; `POST /batches/{id}/pause`, `/resume`, `/cancel`, `/retry` — управление; `GET /batches/{id}/download` — скачивание результатов. Доступ ограничен ключом, создавшим архив. Лимиты файлов, распакованного объёма и ZIP задаются существующими `BATCH_ARCHIVE_*` настройками. Загрузка архива пока не поддерживает `Idempotency-Key`: не повторяйте её вслепую. ## Webhook Доставка успешных/неуспешных обработок и завершённых архивов сохраняет прежний JSON-контракт и повторы с задержкой. Анализ и отмена одиночного задания пока контролируются опросом статуса. Получатель должен обрабатывать дубликаты по ID. Добавлены заголовки `X-AutoMask-Timestamp` и `X-AutoMask-Signature: v1=`. Секрет — API-ключ, которым создано задание/архив. Подпись: `HMAC-SHA256(secret, timestamp + "." + raw_request_body)`. Проверяйте исходные байты, а не повторно сериализованный JSON. ```python import hashlib, hmac, time def verify(body, timestamp, signature, api_key): if abs(time.time() - int(timestamp)) > 300: return False expected = 'v1=' + hmac.new( api_key.encode(), timestamp.encode() + b'.' + body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, signature) ``` Обрабатывайте некорректный timestamp как отказ проверки. Возвращайте 2xx только после надёжного приёма события. Ключ нельзя передавать в логи или клиентский JS при серверной интеграции. Удаление/замена ключа требует согласования проверки ожидающих webhook с получателем. ## Ошибки 400 — параметры; 401 — авторизация; 402 — кредиты; 404 — отсутствующий/чужой ресурс; 409 — конфликт ключа повтора или состояния; 410 — истёкший исходник; 413 — размер; 415 — формат; 429 — лимит запросов; 500 — ошибка сервера. HTTP 200 при чтении статуса не означает успешную обработку: проверяйте `job.status`. Старые прикладные коды 800/802/803 внутри результата не являются HTTP-статусами.