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

# Upload files

> Upload your own images, videos or audio and get a ready-to-use URL to feed any AI endpoint.

## The problem

Most AI endpoints take your media as a **URL** (`image_url`, `video_url`, `audio_url`, `reference_images`, …). That's easy when your file already lives on the public internet — but if it's a local file, or something you generated on the fly, you have nowhere to point those endpoints to.

The **Upload Files API** solves this: you upload the file once and get back a **readable URL** (`asset_url`) that you can drop into any endpoint that accepts a URL — images, video or audio alike.

<Note>
  `asset_url` is a plain, publicly-fetchable URL. Anywhere an endpoint asks for an `image_url` / `video_url` / `audio_url` (or a reference image), pass the `asset_url` of your upload.
</Note>

## How it works

<Steps>
  <Step title="Request an upload URL">
    Call `POST /v1/ai/uploads/request-url` with the `content_type` of each file. You get back, per file, a short-lived `upload_url` (to send the bytes to) and a readable `asset_url` (to use later).
  </Step>

  <Step title="Upload the bytes">
    `PUT` the raw file bytes to `upload_url`, including the returned `headers`. The upload happens directly against storage — the `upload_url` is short-lived (see `expires_in`).
  </Step>

  <Step title="Use the asset_url">
    Pass the `asset_url` as the input URL of any AI endpoint that accepts one. Re-fetch it any time from `GET /v1/ai/uploads`.
  </Step>
</Steps>

## Supported file types

Pass one of these as `content_type`:

| Type  | MIME types                                                        |
| ----- | ----------------------------------------------------------------- |
| Image | `image/png`, `image/jpeg`, `image/webp`                           |
| Video | `video/mp4`, `video/webm`, `video/quicktime`                      |
| Audio | `audio/mpeg`, `audio/wav`, `audio/mp4`, `audio/webm`, `audio/ogg` |

Maximum size: **1 GiB** per file.

## 1. Request an upload URL

```bash theme={null}
curl -X POST "https://api.magnific.com/v1/ai/uploads/request-url" \
  -H "x-magnific-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "files": [
      { "content_type": "image/png" }
    ]
  }'
```

You can request up to **14** files in a single call (`files` array).

```json theme={null}
{
  "files": [
    {
      "file_id": "upl_img_a1b2c3d4e5f6",
      "upload_url": "https://.../v1/ai/uploads/...",
      "headers": {
        "Content-Type": "image/png",
        "x-goog-content-length-range": "0,1073741824"
      },
      "expires_in": 120,
      "asset_url": "https://cdn-magnific.freepik.com/uploads/.../...?token=...",
      "asset_url_expires_in": 86400
    }
  ]
}
```

<ResponseField name="file_id" type="string">
  Identifier of the uploaded file (`upl_…`).
</ResponseField>

<ResponseField name="upload_url" type="string">
  Pre-signed URL to `PUT` the raw file bytes to. Short-lived — see `expires_in`.
</ResponseField>

<ResponseField name="headers" type="object">
  Headers you **must** include in the `PUT` request (they are part of the URL signature).
</ResponseField>

<ResponseField name="expires_in" type="integer">
  Seconds until `upload_url` expires (do the `PUT` right after requesting it).
</ResponseField>

<ResponseField name="asset_url" type="string">
  Readable URL of the uploaded file. Valid once the `PUT` completes. Use it as the input URL in any endpoint that accepts one. Expires in \~24h — don't persist it.
</ResponseField>

<ResponseField name="asset_url_expires_in" type="integer">
  Seconds until `asset_url` expires (counted from this response).
</ResponseField>

## 2. Upload the bytes

`PUT` the file to the `upload_url`, echoing the `headers` from step 1. Do **not** send your API key here — the request goes straight to storage and is authorized by the signed URL.

```bash theme={null}
curl -X PUT "PASTE_upload_url_HERE" \
  -H "Content-Type: image/png" \
  -H "x-goog-content-length-range: 0,1073741824" \
  --data-binary "@./my-image.png"
```

<Warning>
  The `Content-Type` you send here **must match** the `content_type` you requested in step 1, and the `x-goog-content-length-range` header is required — both are covered by the URL signature.
</Warning>

## 3. Use the `asset_url`

Once the upload completes, pass the `asset_url` wherever an endpoint expects a URL:

```bash theme={null}
curl -X POST "https://api.magnific.com/v1/ai/classifier/image" \
  -H "x-magnific-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "PASTE_asset_url_HERE"
  }'
```

The same `asset_url` works for video and audio inputs on endpoints that accept them (`video_url`, `audio_url`, …).

## List your uploads

Lost the response from step 1, or your `asset_url` expired? List your files — each item comes with a **freshly-signed** `asset_url`:

```bash theme={null}
curl "https://api.magnific.com/v1/ai/uploads" \
  -H "x-magnific-api-key: YOUR_API_KEY"
```

```json theme={null}
{
  "files": [
    {
      "file_id": "upl_img_a1b2c3d4e5f6",
      "content_type": "image/png",
      "size_bytes": 20480,
      "created_at": "2026-07-03T10:00:00Z",
      "expires_at": "2026-07-10T10:00:00Z",
      "ttl_seconds": 604800,
      "asset_url": "https://cdn-magnific.freepik.com/uploads/.../...?token=...",
      "asset_url_expires_in": 86400
    }
  ]
}
```

## Expiration

<Note>
  Two independent clocks:

  * **`asset_url_expires_in`** — how long the URL itself stays valid (**\~1 day**). An expired URL returns `403` — just call `GET /v1/ai/uploads` again to get a fresh one (a new URL is signed on every listing). Don't persist the `asset_url`.
  * **`ttl_seconds`** — how long until the **file** becomes eligible for auto-deletion (**\~7 days**). Deletion is eventual, so a file may linger a little past this — but once it is deleted, its `asset_url` stops working. Treat uploads as a staging area, not storage.
</Note>
