---
title: "Prepare upload"
method: POST
path: "/storage/prepare-upload"
tags: ["storage"]
---

# Prepare upload

`POST /storage/prepare-upload`

Returns the key an upload should use for the given file — unchanged when free, numerically suffixed ("a.pdf" → "a (2).pdf") when the name is already taken — plus a V4 signed PUT URL for exactly that key. PUT the file body to upload_url sending upload_headers verbatim: they carry an if-generation-match precondition (412 if the object appeared meanwhile — re-resolve and retry) and a content-length-range that GCS enforces on the actual received bytes (400 when over max_size_bytes). Called once per file right before its upload. Refused with 409 inside folders synced from an external data source.

## Request body

- ModelsStoragePrepareUploadRequest
  - `business_node_id` string
  - `key` string
  - `md5` string
  - `path` string

## Response `200`

OK

- ModelsStoragePrepareUploadResponse
  - `already_exists` boolean
  - `key` string
  - `max_size_bytes` integer
  - `upload_headers` object
  - `upload_url` string

## Other responses

- `400` — Bad Request
- `401` — Unauthorized
- `403` — Forbidden
- `409` — Conflict
- `500` — Internal Server Error

---

[API](https://skmtc.net/resourcly/apis/resourcly-api.md) · [All operations](https://skmtc.net/resourcly/apis/resourcly-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/resourcly/resourcly-api/revisions/7f97d8cd0f1e/schema)
