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

# Image Upload Guidance

> Upload local images and get 48-hour temporary public URLs for image-to-image, image-to-video, and vision APIs

> Last updated: 2026-06-06

Crazyrouter provides temporary public image upload endpoints for converting local reference images into model-readable public URLs. They are suitable for Kling, Veo, Seedance, Runway, Luma, MiniMax, Nano Banana Pro, Doubao Seedream, and other APIs that accept `image_url`, `image_urls`, `image_list`, `images`, or `image_input`.

<Note>
  Temporary images are kept for 48 hours by default and then cleaned up automatically. Storage during that period is not billed separately; current anti-abuse controls use per-user upload quota and rate limits.
</Note>

## Endpoint Overview

| Scenario                   | Endpoint                         |
| -------------------------- | -------------------------------- |
| Local file upload          | `POST /v1/files/uploads`         |
| Base64 image upload        | `POST /v1/files/uploads/base64`  |
| Remote image rehosting     | `POST /v1/files/uploads/url`     |
| Presigned direct R2 upload | `POST /v1/files/uploads/presign` |

Common limits:

| Item               | Current rule                                                  |
| ------------------ | ------------------------------------------------------------- |
| Auth               | `Authorization: Bearer YOUR_API_KEY`                          |
| Supported formats  | `image/png`, `image/jpeg`, `image/webp`, `image/gif`          |
| Single file size   | 20MB                                                          |
| User upload quota  | 200MB / rolling 24-hour window                                |
| Default expiration | 48 hours                                                      |
| Returned URL       | `https://media.crazyrouter.com/task-artifacts/tmp-inputs/...` |

## Local File Upload

```bash cURL theme={null}
curl -X POST https://api.crazyrouter.com/v1/files/uploads \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "file=@./reference.png" \
  -F "purpose=model_input"
```

Example response:

```json theme={null}
{
  "id": "file_e5bbce820b5941409682a9c5e9ba79f1",
  "url": "https://media.crazyrouter.com/task-artifacts/tmp-inputs/2026/06/07/user-1/file_e5bbce820b5941409682a9c5e9ba79f1.png",
  "mime_type": "image/png",
  "size": 2025,
  "expires_at": "2026-06-09T04:41:35Z"
}
```

## Base64 Upload

```bash cURL theme={null}
curl -X POST https://api.crazyrouter.com/v1/files/uploads/base64 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "data": "data:image/png;base64,iVBORw0KGgoAAA...",
    "filename": "reference.png",
    "purpose": "model_input"
  }'
```

## Remote URL Rehosting

```bash cURL theme={null}
curl -X POST https://api.crazyrouter.com/v1/files/uploads/url \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "url": "https://example.com/reference.png",
    "filename": "reference.png",
    "purpose": "model_input"
  }'
```

The remote URL must be an `http` or `https` image URL reachable by Crazyrouter servers. The system checks file size, MIME type, and SSRF protection rules.

## Presigned Direct R2 Upload

For high-upload-volume workflows, request a presigned upload URL first, then upload the image directly from your client to the storage endpoint with `PUT`. The image bytes do not pass through the Crazyrouter application server.

First, request a direct upload URL:

```bash cURL theme={null}
curl -X POST https://api.crazyrouter.com/v1/files/uploads/presign \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "filename": "reference.jpg",
    "content_type": "image/jpeg",
    "size": 12345,
    "purpose": "model_input"
  }'
```

Example response:

```json theme={null}
{
  "id": "file_e5bbce820b5941409682a9c5e9ba79f1",
  "upload_url": "https://...r2.cloudflarestorage.com/...?...",
  "url": "https://media.crazyrouter.com/task-artifacts/tmp-inputs/2026/06/21/user-1/file_e5bbce820b5941409682a9c5e9ba79f1.jpg",
  "method": "PUT",
  "headers": {
    "Content-Type": "image/jpeg",
    "Content-Length": "12345"
  },
  "mime_type": "image/jpeg",
  "size": 12345,
  "expires_at": "2026-06-22T04:41:35Z",
  "upload_expires_at": "2026-06-21T04:56:35Z"
}
```

Then upload the file directly to `upload_url`:

```bash cURL theme={null}
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: image/jpeg" \
  -H "Content-Length: 12345" \
  --data-binary @./reference.jpg
```

After the upload succeeds, use the returned `url` as the image URL in the model request.

<Warning>
  The `upload_url` is a short-lived write URL, valid for about 15 minutes by default. `Content-Type` and `Content-Length` must match the presign request. Do not pass `upload_url` to the model; use the returned `url` instead.
</Warning>

## Example: Use a Local Reference Image for Kling Image-to-Video

First, upload the local reference image:

```bash cURL theme={null}
UPLOAD_RESPONSE=$(curl -sS -X POST https://api.crazyrouter.com/v1/files/uploads \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "file=@./portrait.png" \
  -F "purpose=model_input")

IMAGE_URL=$(python -c "import json,sys; print(json.load(sys.stdin)['url'])" <<< "$UPLOAD_RESPONSE")
echo "$IMAGE_URL"
```

Then pass the returned `IMAGE_URL` to Kling image-to-video:

```bash cURL theme={null}
curl -X POST https://api.crazyrouter.com/kling/v1/videos/image2video \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "model_name": "kling-v3",
    "prompt": "The person in the image slowly turns their head and smiles, cinematic lighting",
    "image_urls": ["'"$IMAGE_URL"'"],
    "duration": "5",
    "mode": "std"
  }'
```

The submit request returns a task ID. Use the [Kling task query](/en/video/kling/query) endpoint to get the final video result.

<Warning>
  Temporary URLs are not a permanent asset library. Make sure the URL has not expired before submitting a generation task, and do not store it as a long-term business image URL.
</Warning>
