# Upload a file

`POST https://api.cream-ai.de/api/v1/uploads`

Uploads an image or a video for your company, to be used as an attachment of comments (`attachments` of `POST /films/{id}/comments`). Send the bytes of the file as the request body with its media type as `Content-Type` (`image/png`, `image/jpeg`, `image/webp`, `video/mp4`, `video/quicktime`, `video/webm`; no SVG) and a `Content-Length` (required; chunked uploads are rejected with `411 length_required`). Images may be at most 25 MB, videos at most 200 MB. mint checks the content: if it does not match the media type, the answer is `415 file_content_mismatch`. An image of another allowed type (for example a JPEG sent as `image/png`) is stored with its real type; `content_type` of the answer shows it. Uploading the same file (same bytes and type) again returns the existing upload with `200` and extends its expiry; a new upload returns `201`. An upload expires 7 days after it was created or last used. Every API access of your company can use every upload of the company; other companies never see it. The file itself cannot be downloaded through the API. At most 2 uploads run at the same time per mint server: more return `429 rate_limited` with `details.reason` `parallel_uploads` and `Retry-After: 5`. Each company has a storage quota for active uploads (`409 upload_quota_exceeded` with `details.quota_bytes`). A slow upload is aborted after 5 minutes (`503`). Uploads are free of credits.

Scopes: `uploads:write`

## Parameters

- `Idempotency-Key` (header, required): Unique key of this write request (1–128 visible ASCII characters, e.g. a UUID). Retries with the same key return the stored response.
- `filename` (query): Name of the file for display (control characters are removed, at most 160 characters). It is never used as a path.

## Request body

The bytes of the file. Content types: image/png, image/jpeg, image/webp, video/mp4, video/quicktime, video/webm.

## Returns

- 200: The same file was uploaded before: the existing upload (expiry extended).
- 201: The new upload.

## Errors

- 400: Invalid request (invalid_request, invalid_json, invalid_cursor, idempotency_key_required, invalid_idempotency_key, parent_not_found, max_depth_exceeded, narration_too_long, user_not_in_company, template_not_found, category_not_found, feedback_kind_unsupported, upload_not_found).
- 401: Missing, malformed, revoked or expired API key (unauthorized).
- 403: Not allowed (forbidden_scope, ip_not_allowed, company_inactive, api_not_enabled).
- 409: The upload storage of your company is full (upload_quota_exceeded, details.quota_bytes).
- 411: Content-Length is missing (length_required).
- 413: The file is too large for its type (payload_too_large, details.max_bytes).
- 415: Media type not allowed (unsupported_media_type) or content does not match it (file_content_mismatch).
- 422: Idempotency-Key reused with a different request (idempotency_mismatch).
- 429: Too many requests or uploads at the same time (rate_limited).
- 500: Internal error (internal). Quote the request id when you contact support.
- 503: Temporarily unavailable (service_unavailable). Retry later (after Retry-After seconds, if sent).

## Example request

```sh
curl -X POST "https://api.cream-ai.de/api/v1/uploads?filename=screenshot-scene-4.png" \
  -H "Authorization: Bearer $MINT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: image/png" \
  --data-binary @screenshot-scene-4.png
```

## Example response (201)

```json
{
  "object": "upload",
  "id": "upl_3f9a1c7e5b2d4a6c8e0f1a3b5c7d9e1f",
  "filename": "screenshot-scene-4.png",
  "content_type": "image/png",
  "bytes": 284113,
  "sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
  "created_at": "2026-11-10T08:30:12Z",
  "expires_at": "2026-11-17T08:30:12Z"
}
```
