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

# Unggah Gambar

> Unggah gambar untuk mendapatkan URL yang dapat digunakan dengan API pembuatan gambar/video

<Note>
  **Playground dokumentasi tidak mendukung unggah file**: Silakan gunakan contoh kode cURL, Python, atau JavaScript di bawah ini untuk menguji.
</Note>

<Warning>
  **Perubahan Penting:** Untuk performa dan kontrol biaya yang lebih baik, kami tidak lagi mendukung pengiriman data gambar base64 secara langsung di API pembuatan. Gunakan API ini untuk mengunggah gambar, mendapatkan URL, lalu memanggil API pembuatan.
</Warning>

## Mengapa mengunggah gambar terlebih dahulu?

1. **Optimasi Performa** - encoding base64 memperbesar data sebesar 33%; mengunggah terlebih dahulu secara signifikan mengurangi ukuran body permintaan
2. **Gunakan Ulang Gambar** - Unggah sekali, gunakan URL berkali-kali tanpa transfer berulang

## Alur Kerja

```mermaid theme={null}
sequenceDiagram
    participant Client
    participant APIMart
    participant Storage

    Client->>APIMart: POST /v1/uploads/images (Upload image file)
    APIMart->>Storage: Save image
    Storage-->>APIMart: Return storage path
    APIMart-->>Client: Return image URL
    Client->>APIMart: POST /v1/images/generations (Use image URL)
```

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.apimart.ai/v1/uploads/images \
    --header 'Authorization: Bearer <token>' \
    --form 'file=@/path/to/your/image.jpg'
  ```

  ```python Python theme={null}
  import requests

  # Upload image
  with open('image.jpg', 'rb') as f:
      response = requests.post(
          "https://api.apimart.ai/v1/uploads/images",
          headers={
              "Authorization": "Bearer <token>"
          },
          files={
              "file": f
          }
      )

  result = response.json()
  image_url = result['url']
  print(f"Image URL: {image_url}")

  # Use the uploaded image for generation
  response = requests.post(
      "https://api.apimart.ai/v1/images/generations",
      headers={
          "Authorization": "Bearer <token>",
          "Content-Type": "application/json"
      },
      json={
          "model": "gemini-3-pro-image-preview",
          "prompt": "Create a variation based on this image",
          "image_urls": [{"url": image_url}]
      }
  )
  ```

  ```javascript JavaScript theme={null}
  // Upload image
  const formData = new FormData();
  formData.append('file', fileInput.files[0]);

  const uploadResponse = await fetch('https://api.apimart.ai/v1/uploads/images', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer <token>'
    },
    body: formData
  });

  const uploadResult = await uploadResponse.json();
  const imageUrl = uploadResult.url;
  console.log(`Image URL: ${imageUrl}`);

  // Use the uploaded image for generation
  const genResponse = await fetch('https://api.apimart.ai/v1/images/generations', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer <token>',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      model: 'gemini-3-pro-image-preview',
      prompt: 'Create a variation based on this image',
      image_urls: [{url: imageUrl}]
    })
  });
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "url": "https://upload.apimart.ai/f/image/9990000123456-a1b2c3d4-photo.jpg",
    "filename": "photo.jpg",
    "content_type": "image/jpeg",
    "bytes": 235680,
    "created_at": 1743436800
  }
  ```

  ```json 400 - Missing File Field theme={null}
  {
    "error": {
      "message": "missing or invalid file field: http: no such file",
      "type": "invalid_request_error"
    }
  }
  ```

  ```json 400 - Unsupported Format theme={null}
  {
    "error": {
      "message": "unsupported image type: application/pdf, allowed: jpeg, png, gif, webp",
      "type": "invalid_request_error"
    }
  }
  ```

  ```json 413 - File Too Large theme={null}
  {
    "error": {
      "message": "file size 25165824 exceeds maximum 20971520 bytes",
      "type": "invalid_request_error"
    }
  }
  ```

  ```json 429 - Rate Limit Exceeded theme={null}
  {
    "error": {
      "code": 429,
      "message": "Rate limit exceeded. Please try again later",
      "type": "rate_limit_error"
    }
  }
  ```

  ```json 500 - Upload Failed theme={null}
  {
    "error": {
      "message": "failed to upload image",
      "type": "server_error"
    }
  }
  ```
</ResponseExample>

## Otorisasi

<ParamField header="Authorization" type="string" required>
  Semua API memerlukan autentikasi Bearer Token

  Dapatkan API Key:

  Kunjungi [Halaman Manajemen API Key](https://apimart.ai/keys) untuk mendapatkan API Key Anda

  Tambahkan ke header request:

  ```
  Authorization: Bearer YOUR_API_KEY
  ```
</ParamField>

## Body

<ParamField body="file" type="file" required>
  File gambar

  Format yang didukung: JPEG (.jpg, .jpeg), PNG (.png), WebP (.webp), GIF (.gif)

  Ukuran file maksimum: 20MB
</ParamField>

## Response

<ResponseField name="url" type="string">
  URL akses publik untuk gambar, dapat digunakan secara langsung di API pembuatan (berlaku selama 72 jam)
</ResponseField>

<ResponseField name="filename" type="string">
  Nama file asli
</ResponseField>

<ResponseField name="content_type" type="string">
  Tipe MIME yang terdeteksi, misal `image/jpeg`
</ResponseField>

<ResponseField name="bytes" type="integer">
  Ukuran file dalam byte
</ResponseField>

<ResponseField name="created_at" type="integer">
  Waktu unggah sebagai Unix timestamp (detik)
</ResponseField>

## Contoh Lengkap: Alur Kerja Gambar-ke-Gambar

```python Python theme={null}
import requests
import time

API_KEY = "your-Apimart-key"
BASE_URL = "https://api.apimart.ai"

# Step 1: Upload reference image
def upload_image(file_path):
    with open(file_path, 'rb') as f:
        response = requests.post(
            f"{BASE_URL}/v1/uploads/images",
            headers={"Authorization": f"Bearer {API_KEY}"},
            files={"file": f}
        )
    return response.json()['url']

# Step 2: Create generation task
def create_generation(image_url, prompt):
    response = requests.post(
        f"{BASE_URL}/v1/images/generations",
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json"
        },
        json={
            "model": "gemini-3-pro-image-preview",
            "prompt": prompt,
            "image_urls": [{"url": image_url}],
            "size": "16:9"
        }
    )
    return response.json()['id']

# Step 3: Poll task status
def wait_for_result(task_id):
    while True:
        response = requests.get(
            f"{BASE_URL}/v1/images/generations/{task_id}",
            headers={"Authorization": f"Bearer {API_KEY}"}
        )
        result = response.json()

        if result['status'] == 'completed':
            return result['url']
        elif result['status'] == 'failed':
            raise Exception(f"Generation failed: {result.get('fail_reason')}")

        time.sleep(2)

# Execute workflow
image_url = upload_image("reference.jpg")
print(f"Image uploaded: {image_url}")

task_id = create_generation(image_url, "Transform this photo into Ghibli anime style")
print(f"Task created: {task_id}")

result_url = wait_for_result(task_id)
print(f"Generation complete: {result_url}")
```
