> ## Documentation Index
> Fetch the complete documentation index at: https://docs.creatok.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Files

> Upload reference images and videos before submitting a generation job.

Use this flow before sending reference images, reference videos, or first/end-frame images to generation:

1. Call `POST /files` for each file to receive an upload grant and `file_id`.
2. Send the file bytes to `upload_url` with every returned `upload_fields` entry as multipart form data.
3. After the upload succeeds, pass `file_id` in `referenceImageKeys`, `referenceVideoKeys`, `firstFrameKey`, or `endFrameKey`.

> [!NOTE]
>
> Receiving a `file_id` does not mean the file has been uploaded. Complete step 2 before submitting generation. Use `file_id` directly; you do not need to construct a storage path or download URL. `upload_fields.key` is also accepted.

`POST /files` creates a signed upload grant. Send JSON with the MIME type, file size in bytes, and filename. This endpoint does not receive the file bytes.

```bash theme={null}
curl https://api.creatok.ai/v1/files \
  -H "Authorization: Bearer $CREATOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content_type":"image/jpeg","size":123456,"filename":"reference.jpg"}'
```

All three fields are required. `size` must be a positive integer. `filename` must contain 1–255 characters after trimming and no control characters. Send a MIME type without parameters, such as `image/jpeg`. Unknown fields are rejected.

The HTTP `200` response contains `file_id`, `upload_url`, `upload_fields`, and `expires_at`. Upload with a **multipart POST**, not PUT. Include every returned form field unchanged and append the `file` field last. Do not send your API key to the upload URL.

```javascript Node.js theme={null}
import { readFile } from "node:fs/promises";

const bytes = await readFile("reference.jpg");
const response = await fetch("https://api.creatok.ai/v1/files", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CREATOK_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ content_type: "image/jpeg", size: bytes.length, filename: "reference.jpg" }),
});
if (!response.ok) throw new Error(await response.text());
const grant = await response.json();
const form = new FormData();
for (const [key, value] of Object.entries(grant.upload_fields)) form.append(key, value);
form.append("file", new Blob([bytes], { type: "image/jpeg" }), "reference.jpg");
const upload = await fetch(grant.upload_url, { method: "POST", body: form });
if (!upload.ok) throw new Error(await upload.text());
console.log(grant.file_id); // Use in referenceImageKeys or firstFrameKey.
```

The signed grant expires after six hours. Image uploads are limited to 10 MiB; other uploads to 100 MiB. The storage service rejects uploads exceeding the signed limit. Model-specific restrictions can be stricter; see [Video models](/guides/video-models).

Wait for a successful upload before submitting generation. Use the returned `file_id` or `upload_fields.key`; both refer to the same uploaded object and are scoped to your workspace. Video references go in `referenceVideoKeys`. Reference audio is not currently accepted by the generation request schema.

Uploaded inputs are temporary. Submit promptly, and keep your originals in your own storage. An expired grant requires a new grant and upload. An accepted job retains its own copy of reference inputs.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.