---
title: "Завершить загрузку файла товара или импорта"
method: POST
path: "/api/v1/core/upload-sessions/{id}/finish"
tags: ["Core product transfers"]
---

# Завершить загрузку файла товара или импорта

`POST /api/v1/core/upload-sessions/{id}/finish`

## Request

- Base URL: `https://erp.akeda.ru`
- URL: `https://erp.akeda.ru/api/v1/core/upload-sessions/{id}/finish`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://erp.akeda.ru/oauth2/authorize`, token URL `https://erp.akeda.ru/oauth2/token`, scopes: `akeda:delegate`)

Проверяет, что файл лёг по выданному адресу: размер, контрольную сумму (если заявлена) и антивирус; подменённый после проверки файл отклоняется, заражённый удаляется и до товара не доходит. Затем заводит строку с номером сессии: у сессии товара — файл товара (product_file, миниатюры фото строятся из объекта), у сессии импорта — запуск импорта (product_import). Сессии фото сотрудника и картинки бланка, открытые экраном, завершаются здесь же и отвечают employee_photo и letterhead. Повтор возвращает ту же строку. 409 transfer.not_uploaded — байтов ещё нет; 422 transfer.infected — найдена угроза, файл удалён; 503 transfer.scanner_unavailable — антивирус недоступен, повторите позже.

## Response `200`

Сессия и заведённая строка

- CoreUploadFinishResult: Итог завершения сессии core: заведённый файл товара, запуск импорта, фото сотрудника или бланк юрлица.
  - `session` TransferSession, required: Сессия загрузки файла по подписанному адресу хранилища. Ключи хранилища наружу не отдаются.
    - `id` string, uuid, required
    - `owner_type` string, required
    - `owner_id` string
    - `name` string, required
    - `mime_type` string, required
    - `size_bytes` integer, required
    - `sha256` string
    - `attributes` object
    - `status` 'pending' | 'processing' | 'attached' | 'failed' | 'expired', required
    - `failure` 'infected' | 'size' | 'checksum' | 'storage' | 'owner' | 'aborted' | 'expired'
    - `failure_detail` string
    - `scan_status` 'pending' | 'clean' | 'infected' | 'skipped'
    - `scan_verdict` string
    - `published_ref` string: Номер строки, заведённой по файлу; у почты — id загрузки для upload_ids
    - `expires_at` string, date-time, required
    - `created_at` string, date-time, required
    - `completed_at` string, date-time
    - `upload` TransferInstructions: Как передать байты. Выдаётся один раз, при открытии сессии.
      - `mode` 'post' | 'parts' | 'api', required: post — один multipart POST; parts — PUT каждой части; api — PUT через этот API с авторизацией
      - `url` string
      - `method` string
      - `fields` object: Поля формы для POST; файл идёт после них последним полем
      - `file_field` string: Имя поля формы для файла
      - `headers` object
      - `part_bytes` integer
      - `part_count` integer
      - `direct_urls` object: Подписанный адрес каждой части по её номеру, начиная с 1
      - `requires_authorization` boolean, required: true — адрес требует токен API, агенту по MCP этот путь недоступен
      - `max_bytes` integer, required
      - `expires_at` string, date-time, required
  - `product_file` CoreProductFile
    - `id` string, uuid, required
    - `product_id` string, uuid, required
    - `kind_item_id` string, uuid, required
    - `kind_code` string, required: Код элемента справочника product_file_kinds; пусто без типа
    - `kind_label` string, required
    - `name` string, required
    - `mime_type` string, required
    - `size_bytes` integer, required
    - `is_image` boolean, required
    - `is_primary` boolean, required: Основное фото товара; бывает только у изображения
    - `sort_order` integer, required
    - `uploaded_by_name` string, required
    - `created_at` string, date-time, required
    - `scan_status` 'pending' | 'clean' | 'infected' | 'skipped', required: Вердикт антивируса; skipped — файл не проверялся (загружен формой). Ссылку на скачивание получают clean и skipped
  - `product_import` CoreProductImportRun
    - `id` string, uuid, required
    - `kind` 'product_families' | 'products' | 'product_identifiers', required
    - `format` 'xlsx' | 'xls' | 'ods' | 'csv' | 'tsv', required
    - `status` 'awaiting_upload' | 'uploading' | 'uploaded' | 'mapped' | 'previewed' | 'failed' | 'applied', required
    - `mode` 'create_only' | 'upsert', required
    - `source_name` string, required
    - `source_sha256` string, required
    - `source_size` integer, required
    - `mapping` CoreProductImportMappingState, required
      - `sheet_name` string, required
      - `header_row` integer, required
      - `columns` object, required
      - `skipped` string[]: Колонки, которые человек явно оставил «Не загружать». Непустая колонка без поля и без этой отметки — ошибка проверки (ERP-2202)
      - `new_fields` CoreProductImportNewField[]: Доп. поля, которые применение заведёт из колонок; нужно право settings:write
        - `column` string, required
        - `key` string, required
        - `label` string, required
        - `type` 'text' | 'number' | 'money' | 'date' | 'bool' | 'select', required
        - `entity_types` string[]
      - `add_missing_values` boolean: Добавить недостающие значения списков доп. полей и уровни категорий
    - `schema_version` 'core-products-v1', required
    - `revision` integer, required
    - `schema_revision` string
    - `reference_revision` string
    - `preview_token` string
    - `diff` CoreProductImportDiff[]
      - `row` integer, required
      - `action` 'create' | 'update' | 'unchanged', required
      - `target_id` string, uuid
      - `sku` string
      - `name` string
      - `changes` object
    - `issues` CoreProductImportIssue[]
      - `sheet` string, required
      - `row` integer, required
      - `column` string, required
      - `code` string, required
      - `severity` 'warning' | 'error', required
      - `value` string
      - `message` string, required
      - `hint` string
      - `params` object: Сведения замечания для текста на другом языке (складская загрузка): documents и date у повторной загрузки, candidate у ненайденного артикула с ведущими нулями, column у несопоставленной колонки
    - `created_count` integer, required
    - `updated_count` integer, required
    - `unchanged_count` integer, required
    - `warning_count` integer, required
    - `error_count` integer, required
    - `created_by` integer
    - `created_at` string, date-time, required
    - `previewed_at` string, date-time
    - `applied_at` string, date-time
    - `source_columns` string[]
    - `source_sheets` CoreProductImportSheet[]
      - `name` string, required
    - `target_fields` CoreProductImportField[]
      - `key` string, required
      - `label` string, required
      - `required` boolean, required
      - `type` string, required
    - `columns` CoreProductImportColumn[]: Разбор колонок листа: непустые ячейки, примеры, откуда сопоставление, предложенный тип и ключ нового поля
      - `column` string, required
      - `non_empty` integer, required
      - `samples` string[], required
      - `matched_by` 'key' | 'label' | 'memory' | 'manual' | 'new_field' | 'channel_unknown': channel_unknown — шапка «<Канал> · <параметр>» с каналом, которого среди действующих каналов кабинета нет: выберите поле вручную
      - `suggested_type` string, required
      - `suggested_key` string, required
      - `suggested_label` string, required
      - `distinct` integer, required
      - `values` string[]
      - `type_misfits` object
    - `new_values` CoreProductImportNewValue[]: Значения справочников, которые заведёт применение
      - `dictionary` string, required
      - `field` string
      - `value` string, required
      - `rows` integer, required
    - `channel_price_count` integer: Сколько цен каналов из колонок «<Канал> · Цена» попадёт в черновик установки цен (ERP-2507)
    - `price_set` object: Черновик установки цен, заведённый этим применением из колонок цен каналов (только в ответе применения)
      - `id` string, uuid, required
      - `number` string, required
      - `line_count` integer, required
    - `price_set_error` string: Почему черновик цен каналов не завёлся; карточки при этом уже записаны
  - `employee_photo` CorePhotoResult
    - `photo_url` string, required
  - `letterhead` CoreLetterhead: Бланк юрлица. Ключи файлов наружу не отдаются: images говорит только, есть ли картинка на месте.
    - `company_id` string, uuid, required
    - `version` integer, required
    - `director_name` string
    - `director_title` string
    - `accountant_name` string
    - `accountant_title` string
    - `bank_account_id` string, uuid
    - `print_facsimile` boolean
    - `images` object, required
      - `logo` boolean, required
      - `stamp` boolean, required
      - `director_signature` boolean, required
      - `accountant_signature` boolean, required

## Other responses

- `400`: Некорректный запрос или нарушение бизнес-правила
- `401`: Сессия, ключ или кабинет не подтверждены
- `404`: Запись не найдена или не видима текущему пользователю
- `409`: Конфликт версии, идемпотентности или бизнес-состояния
- `410`: Сессия передачи файла истекла
- `422`: Запрос разобран, но бизнес-значение недопустимо
- `503`: Внешний банк, справочник или контур подключений временно недоступен

---

[API](https://skmtc.dev/akeda/apis/akeda-erp-client-api.md) · [All operations](https://skmtc.dev/akeda/apis/akeda-erp-client-api/llms.txt) · [OpenAPI document](https://skmtc.dev/akeda/apis/akeda-erp-client-api/revisions/3c60ded179f2?raw)
