---
title: "Generate a presigned URL for file upload"
method: POST
path: "/v1/uploads/presign"
---

# Generate a presigned URL for file upload

`POST /v1/uploads/presign`

## Request

- Base URL: `https://api.clichefactory.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.clichefactory.com/v1/uploads/presign`
- Auth: none declared

Generate a presigned PUT URL so the SDK can upload a file directly to S3.

Optional ``Idempotency-Key`` header. Replay returns the *same* URL
(and ``document_id`` / ``dataset_id``) so a client retrying after a
network blip can still complete its upload to the original S3 path.
Note: presigned URLs expire after ~1 h regardless of the 24 h
idempotency TTL — clients whose cached URL has expired should retry
with a fresh key.

## Headers

- `Idempotency-Key` string, nullable
- `X-API-KEY` string, nullable

## Request body

- PresignUploadRequest: Request to generate a presigned PUT URL for a file upload.
  - `tenant_id` string
  - `project_id` string
  - `task_id` string
  - `environment` string: Logical environment tag (dev / prod / staging). Recorded as metadata on the canonical envelope and the document control-plane row, and echoed back on the response ``scope``. Does NOT drive bucket selection — that is server-owned via ``S3_BUCKET_NAME``. Kept on the request body for backwards compatibility and for logical scoping; clients can omit it and accept the default.
  - `upload_kind` 'document' | 'training_input' | 'training_ground_truth', required
  - `filename` string, required: Original filename (e.g. example.pdf, invoice_001.json)
  - `content_length` integer, nullable: File size in bytes (for validation)
  - `content_type` string, nullable: MIME type (can be derived)
  - `dataset_id` string, nullable: Training dataset ID. Required for training kinds. Server generates if omitted.
  - `document_id` string, nullable: Document ID for extraction uploads. Server generates if omitted.
  - `artifact_id` string, nullable: Artifact ID. When provided, server resolves scope from the artifact record.

## Response `200`

Successful Response

- PresignUploadResponse: Response containing the presigned upload URL and canonical file URI.
  - `upload_url` string, required: Presigned PUT URL
  - `method` string
  - `headers` object
  - `expires_in_s` integer: URL validity in seconds
  - `file_uri` string, required: Canonical s3:// URI of the uploaded file
  - `dataset_id` string, nullable: Dataset ID (for training kinds)
  - `document_id` string, nullable: Document ID (for document kind)
  - `scope` object: Echoed scope for debugging

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/clichefactory/apis/aio-server.md) · [All operations](https://skmtc.dev/clichefactory/apis/aio-server/llms.txt) · [OpenAPI document](https://skmtc.dev/clichefactory/apis/aio-server/revisions/9bd59f9bbb31?raw)
