---
title: "Sign a Media Upload"
method: POST
path: "/v2/media/uploads/sign"
tags: ["media"]
---

# Sign a Media Upload

`POST /v2/media/uploads/sign`

## Request

- Base URL: `https://api.stuut.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.stuut.ai/v2/media/uploads/sign`
- Auth: HTTP bearer

Mints a short-lived signature for a direct browser-to-Cloudinary upload.
The browser POSTs the file plus every returned field to ``upload_url`` and
reads ``secure_url`` from Cloudinary's response. The API secret never
leaves the backend; only the upload is signed (delivery stays public).

## Request body

- SignUploadRequest: Request a signed upload for a given media purpose.
  - `purpose` 'signature' | 'logo' | 'invoice_pdf_logo', required: What the upload is for; scopes the folder and limits.

## Response `200`

Successful Response

- SignedUploadResponse: Provider-neutral signed-upload envelope. Same shape as an S3 presigned POST, so storage can be swapped later with no frontend/SDK change: the client POSTs ``file`` + every key in ``fields`` to ``upload_url`` and reads ``secure_url`` from the response.
  - `upload_url` string, required: Endpoint the browser POSTs the file + fields to.
  - `fields` SignedUploadFields, required: Form fields the browser must POST verbatim alongside the file. Cloudinary recomputes the signature from these params and rejects on any mismatch, so the client sends them byte-for-byte as returned here. Every signed param is included — omitting one would break signature validation.
    - `api_key` string, required: Cloudinary API key.
    - `timestamp` integer, required: Unix seconds the signature was minted; Cloudinary time-bounds it.
    - `signature` string, required: HMAC of the signed params; authenticates the upload.
    - `asset_folder` string, nullable, required: Org-scoped Media Library folder, e.g. 'tenants/<org>/signatures' (dynamic-folder mode; decoupled from the delivery URL). Null for fixed-location uploads that pin a public_id instead.
    - `public_id` string, nullable, required: Fixed asset id for single-slot uploads (e.g. 'tenants/<org>/logo'); the upload always lands at this id so the delivery URL is stable. Null otherwise.
    - `overwrite` boolean, nullable, required: When true, a re-upload replaces the existing asset at public_id.
    - `invalidate` boolean, nullable, required: When true, purges the CDN cache so the replacement shows immediately.
    - `allowed_formats` string, required: Comma-separated upload format allowlist.
    - `transformation` string, nullable, required: Incoming transformation applied at upload (e.g. 'c_limit,w_400,h_400'); null when the purpose imposes no size limit.

## Other responses

- `422`: Validation Error

---

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