---
title: "Preview File Migration"
method: POST
path: "/internal/files/migrate/preview"
tags: ["internal"]
---

# Preview File Migration

`POST /internal/files/migrate/preview`

Resolve a whole planned import against the tenant, storing nothing.

An import driver is a one-off script pointed at a directory nobody has read carefully,
and its cheapest failure is the one it does not notice: a vendor whose documents all
landed nowhere, a folder created under a misspelling beside the real one, ten thousand
uploads addressed to the wrong tenant. So the plan is resolved before any bytes move —
the manifest is names and ids only — and the answer is per item plus rolled up, since
"which document failed" and "is this the import I meant" are different questions.

It carries the same permission gate as `POST /files/migrate` deliberately, even though
it only reads: a credential that can preview an import can run it, so a driver that gets
past this call cannot then fail thousands of uploads in on a 403.

The whole manifest arrives at once rather than a page at a time, because the folder
rollups are only true when deduplicated across all of it — three hundred documents
naming one new folder create one folder, and a paged preview would call it new on every
page.

Cost does not scale with the manifest: the vendor, folder and existing-document lookups
are four set-based queries (plus a chunk per five hundred distinct filenames) whatever
the item count, and everything else is decided in memory.

## Request body

- MigrationPreviewRequest — The import to resolve and validate without storing anything.
  - `company_id` string, uuid, required
  - `items` MigrationPreviewItem[]
    - `filename` string, required
    - `document_type` string, required
    - `vendor_id` string, uuid, nullable
    - `project_id` string, uuid, nullable
    - `project_name` string, nullable
    - `path` string, nullable
    - `size_bytes` integer, nullable

## Response `200`

Successful Response

- MigrationPreviewResponse — The whole planned import, resolved and validated, with nothing written. `blocked_count`, `skippable_count` and `recommended_count` partition `total_items` — every item is refused, accepted-but-pointless, or worth uploading. The folder rollups and `destinations[].file_count` cover the **recommended** items only, so they answer "what happens if I import what this preview told me to" rather than describing work a driver following the preview would never do. `destinations` itself is the exception: it also lists a vendor that would receive nothing, which is the point.
  - `company_id` string, uuid, required
  - `company_name` string, required
  - `total_items` integer, required
  - `recommended_count` integer, required
  - `skippable_count` integer, required
  - `blocked_count` integer, required
  - `folders_to_create` MigrationPreviewFolder[], required
    - `vendor_id` string, uuid, nullable, required
    - `vendor_name` string, nullable, required
    - `project_name` string, required
    - `project_id` string, uuid, nullable, required
    - `file_count` integer, required
  - `folders_reused` MigrationPreviewFolder[], required
    - `vendor_id` string, uuid, nullable, required
    - `vendor_name` string, nullable, required
    - `project_name` string, required
    - `project_id` string, uuid, nullable, required
    - `file_count` integer, required
  - `destinations` MigrationPreviewDestination[], required
    - `vendor_id` string, uuid, nullable, required
    - `vendor_name` string, nullable, required
    - `file_count` integer, required
    - `folder_count` integer, required
    - `blocked_count` integer, required
  - `problem_counts` object, required
  - `warning_counts` object, required
  - `importable_extensions` string[], required
  - `download_only_extensions` string[], required
  - `items` MigrationPreviewItemResult[], required
    - `index` integer, required
    - `path` string, nullable, required
    - `filename` string, required
    - `will_upload` boolean, required
    - `recommended` boolean, required
    - `problems` MigrationPreviewProblem[], required
    - `warnings` MigrationPreviewWarning[], required
    - `document_type` string, nullable, required
    - `vendor_id` string, uuid, nullable, required
    - `vendor_name` string, nullable, required
    - `project_id` string, uuid, nullable, required
    - `project_name` string, nullable, required
    - `folder_action` 'reuse' | 'create' | 'none', required — What a planned import would do to the folder it names.

## Other responses

- `422` — Validation Error

## Changes

- **2026-09-04** `816d6dca5096` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/kobaltlabs/apis/fastapi/changes/internal/files/migrate/preview/post.md)

---

[API](https://skmtc.dev/kobaltlabs/apis/fastapi.md) · [All operations](https://skmtc.dev/kobaltlabs/apis/fastapi/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/kobaltlabs/fastapi/revisions/816d6dca5096/schema)
