# Uploads

> Get your photos, videos and audio to a model.

Source: https://docs.nocamclub.com/api/uploads

A file goes into `images`, `videos` or `audios` of a generation as either a public https address or a `file_…` id.

| | Formats | Up to |
|---|---|---|
| Photo | PNG, JPEG, WebP | 10 MB |
| Video | MP4, MOV (some models: MP4 only) | 50 MB |
| Audio | MP3, WAV | 15 MB |

How many files and how long they may be depends on the model: see `maxItems` and the descriptions in its `input_schema`.

The file's first bytes decide what it is, not its name or the type you claim.

## Three ways

### 1. Just pass an address

The simplest. We fetch it when you start the generation.

```json
{ "model": "nano-banana-2", "input": { "prompt": "img1 on a rooftop", "images": ["https://example.com/me.jpg"] } }
```

### 2. Have us fetch it first

Do this when you'll use the file several times, or want to know it's good before you start.

```bash
curl https://api.nocamclub.com/v1/uploads \
  -H "Authorization: Bearer $NOCAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/clip.mp4" }'
```

```json
{
  "id": "file_01a1b37b65dc7dcd8c060f296add5cf8",
  "object": "file",
  "kind": "video",
  "content_type": "video/mp4",
  "bytes": 4581035,
  "duration_seconds": 8,
  "status": "ready",
  "expires_at": "2026-11-09T00:00:00.000Z"
}
```

We only fetch public https addresses: never `localhost` or a private network.

### 3. Upload from your machine

For local files and anything big. Files go straight to storage, not through our API.

```bash
# 1. Ask for a link, saying what you'll send
curl https://api.nocamclub.com/v1/uploads \
  -H "Authorization: Bearer $NOCAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "content_type": "video/mp4", "bytes": 4581035 }'
# -> { "id": "file_…", "upload_url": "https://…", "upload_method": "PUT", "upload_headers": { "content-type": "video/mp4" }, … }

# 2. PUT the file there, with that content type, within 15 minutes
curl -X PUT -H "content-type: video/mp4" --upload-file clip.mp4 "$UPLOAD_URL"

# 3. Have it checked: gives you the length, and refuses a bad file now rather than later
curl -X POST https://api.nocamclub.com/v1/uploads/$FILE_ID/complete \
  -H "Authorization: Bearer $NOCAM_API_KEY"
```

Step 3 is optional: a file is checked the first time a generation uses it.

A file is `pending` from step 1 until it's checked, with `bytes` still `null`, and `ready` after. Fetching by address (way 2) gives a `ready` file at once.

## After that

- **Files stay for 48 hours**, then they're removed. Using an old one answers `invalid_parameter`: upload it again.
- **Only your account can use your files.** Another account's id is simply not found.
- `GET /v1/uploads/{id}` shows a file's state.

## Length limits

A video or audio file's length is read when it's uploaded. If it's over the model's limit, the generation is refused with [`invalid_parameter`](https://docs.nocamclub.com/errors/invalid_parameter.md) before anything is charged. Video limits are for all the videos of a request together, and the same file sent twice counts twice. Audio limits are per file.

If a file's length can't be read, the request goes ahead and the model decides. A refusal gives the credits back.

## What can go wrong

| Code | Why |
|---|---|
| [`file_too_large`](https://docs.nocamclub.com/errors/file_too_large.md) | Over the size limit above |
| [`unsupported_media`](https://docs.nocamclub.com/errors/unsupported_media.md) | It isn't one of those formats, whatever its name says |
| [`upload_not_found`](https://docs.nocamclub.com/errors/upload_not_found.md) | `/complete` came before the file did |
| [`invalid_parameter`](https://docs.nocamclub.com/errors/invalid_parameter.md) | The address can't be fetched, or a file isn't yours, is the wrong kind or has expired |
| [`bad_input_file`](https://docs.nocamclub.com/errors/bad_input_file.md) | The model itself couldn't read it, after the generation started |
