---
title: "Mint signed upload URLs"
method: POST
path: "/migrations/{migration_id}/files"
tags: ["Migrations"]
---

# Mint signed upload URLs

`POST /migrations/{migration_id}/files`

## Request

- Base URL: `https://app.vern.so/api/v1`
- URL: `https://app.vern.so/api/v1/migrations/{migration_id}/files`
- Auth: API key in header `x-api-key`
- TypeScript: <https://skmtc.dev/vern-so/apis/vern-api/docs/migrations/:migration_id/files/post.ts> (a function with typed inputs; its response is checked against the schema)

Request one signed upload URL per file, then PUT each file's bytes to its `signed_url`. Files are workbook-level — not mapped to templates.

## Request body

- object
  - `files` object[], required
    - `name` string, required
    - `content_type` string

## Response `201`

One signed upload per requested file.

- object
  - `files` SignedUpload[]
    - `name` string
    - `storage_path` string
    - `signed_url` string: PUT the file's bytes here.
    - `token` string
    - `content_type` string

## Other responses

- `400`: Malformed request.
- `401`: API key missing, malformed, or revoked.
- `404`: The referenced resource isn't in your account.
- `429`: Rate limit hit. Counted per account, not per API key. Creating a migration and starting a `generate` run are limited to 30/hour each; answering a run is limited to 30/hour; reads allow 30/minute and writes 30/minute. `Retry-After` gives the seconds until the window resets, alongside `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`.

## Changes

- **2026-06-18** `c5a09eb23a64`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/vern-so/apis/vern-api/changes/migrations/:migration_id/files/post.md)

---

[API](https://skmtc.dev/vern-so/apis/vern-api.md) - [All operations](https://skmtc.dev/vern-so/apis/vern-api/llms.txt) - [OpenAPI document](https://skmtc.dev/vern-so/apis/vern-api/revisions/6ae61af2db81?raw)
