> ## 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.

# Grok Imagine 2.0 Ext Pembuatan Gambar

>  - Text-to-image asinkron; polling hasil dengan task_id
- 1–12 gambar per permintaan; ditagih per gambar yang berhasil dikirim ($0.08 per gambar)
- Hanya output url; tanpa image-to-image / streaming
- URL gambar kedaluwarsa dalam 72 jam 

<Info>
  **Text-to-image · tugas asinkron.** Kirim `POST /v1/images/generations`, lalu polling [Dapatkan status tugas](/id/api-reference/tasks/status).\
  Nama model tetap `grok-imagine-2.0-ext`. **Tidak didukung**: gambar referensi, `stream`, atau nilai `response_format` selain `url`.
</Info>

<Warning>
  Jangan menaruh API key di bundle browser (`VITE_*` / `NEXT_PUBLIC_*`, LocalStorage, dll.). Lebih baik browser memanggil BFF Anda sendiri; simpan key APIMart di server.
</Warning>

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.apimart.ai/v1/images/generations \
    --header 'Authorization: Bearer <token>' \
    --header 'Content-Type: application/json' \
    --header 'Accept: application/json' \
    --header 'Idempotency-Key: 8eacb46d-ef4e-4f4e-82de-830bd8bc67e2' \
    --header 'X-APIMart-Response-Version: 2026-07-27' \
    --data '{
      "model": "grok-imagine-2.0-ext",
      "prompt": "A red apple on a white ceramic plate, clean studio product photo",
      "n": 1,
      "size": "1:1",
      "resolution": "quality",
      "response_format": "url"
    }'
  ```

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

  url = "https://api.apimart.ai/v1/images/generations"

  payload = {
      "model": "grok-imagine-2.0-ext",
      "prompt": "A red apple on a white ceramic plate, clean studio product photo",
      "n": 1,
      "size": "1:1",
      "resolution": "quality",
      "response_format": "url",
  }

  headers = {
      "Authorization": "Bearer <token>",
      "Content-Type": "application/json",
      "Accept": "application/json",
      "Idempotency-Key": str(uuid.uuid4()),
      "X-APIMart-Response-Version": "2026-07-27",
  }

  response = requests.post(url, json=payload, headers=headers)

  print(response.status_code, response.json())
  ```

  ```javascript JavaScript theme={null}
  const url = "https://api.apimart.ai/v1/images/generations";

  const payload = {
    model: "grok-imagine-2.0-ext",
    prompt: "A red apple on a white ceramic plate, clean studio product photo",
    n: 1,
    size: "1:1",
    resolution: "quality",
    response_format: "url",
  };

  const headers = {
    Authorization: "Bearer <token>",
    "Content-Type": "application/json",
    Accept: "application/json",
    "Idempotency-Key": crypto.randomUUID(),
    "X-APIMart-Response-Version": "2026-07-27",
  };

  fetch(url, {
    method: "POST",
    headers: headers,
    body: JSON.stringify(payload),
  })
    .then(async (response) => {
      console.log(response.status, await response.json());
    })
    .catch((error) => console.error("Error:", error));
  ```
</RequestExample>

<ResponseExample>
  ```json 202 theme={null}
  {
    "code": 202,
    "request_id": "2026081111342261665927mpb4IPDb",
    "data": {
      "id": "task_01KZQE5CM0Y3KZ6M1N1BK619MX",
      "object": "generation.task",
      "type": "image",
      "status": "pending",
      "progress": 0,
      "poll_url": "/v1/tasks/task_01KZQE5CM0Y3KZ6M1N1BK619MX"
    }
  }
  ```

  ```json 400 theme={null}
  {
    "request_id": "20260811...",
    "error": {
      "message": "`response_format` for grok-imagine-2.0-ext only supports `url` (got: b64_json)",
      "type": "invalid_response_format",
      "param": "",
      "code": "invalid_response_format"
    }
  }
  ```

  ```json 401 theme={null}
  {
    "error": {
      "code": 401,
      "message": "Autentikasi gagal. Periksa API key Anda",
      "type": "authentication_error"
    }
  }
  ```

  ```json 402 theme={null}
  {
    "error": {
      "code": 402,
      "message": "Saldo tidak mencukupi. Silakan top up dan coba lagi",
      "type": "payment_required"
    }
  }
  ```

  ```json 429 theme={null}
  {
    "error": {
      "code": 429,
      "message": "Terlalu banyak permintaan. Silakan coba lagi nanti",
      "type": "rate_limit_error"
    }
  }
  ```
</ResponseExample>

## Kemampuan dan batasan

| Dimensi        | Kontrak                                                                         |
| -------------- | ------------------------------------------------------------------------------- |
| Model          | Tetap `grok-imagine-2.0-ext`                                                    |
| Kemampuan      | **Hanya text-to-image**                                                         |
| Mode           | Tugas asinkron                                                                  |
| Jumlah `n`     | `1`–`12`, default `1`                                                           |
| `size`         | 7 rasio aspek + 5 alias piksel (di bawah)                                       |
| Output         | Hanya `response_format=url` (juga default)                                      |
| Kualitas       | Bidang publik `resolution`; nilai terverifikasi `quality`                       |
| Tidak didukung | Image-to-image, `stream=true`, `quality` publik, `style`, `b64_json` / `base64` |
| Penagihan      | Harga satuan tetap; menagih gambar yang **berhasil dikirim**                    |

## Autentikasi dan header yang direkomendasikan

<ParamField header="Authorization" type="string" required>
  Bearer token. Dapatkan key dari [halaman API Key](https://apimart.ai/keys).

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

| Header                       | Catatan                                                                                                                                   |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `Content-Type`               | `application/json` (submit)                                                                                                               |
| `Accept`                     | `application/json`                                                                                                                        |
| `Idempotency-Key`            | Sangat direkomendasikan. UUID baru per generasi yang dikonfirmasi pengguna; retry jaringan **harus memakai ulang** key dan body yang sama |
| `X-APIMart-Response-Version` | Lebih baik `2026-07-27` untuk bentuk submit yang stabil (`data.id`)                                                                       |

## Parameter permintaan

<ParamField body="model" type="string" required>
  Nilai tetap: `grok-imagine-2.0-ext`
</ParamField>

<ParamField body="prompt" type="string" required>
  Prompt. Harus non-kosong setelah trim. Trim sebelum submit.
</ParamField>

<ParamField body="n" type="integer" default="1">
  Jumlah gambar: `1`–`12`. `0` eksplisit error. Abaikan untuk `1`.
</ParamField>

<ParamField body="size" type="string">
  Rasio aspek. **Lebih baik string rasio** (UI sebaiknya hanya menampilkan rasio):

  | `size` | Orientasi | Penggunaan tipikal         |
  | ------ | --------- | -------------------------- |
  | `1:1`  | Persegi   | Produk, avatar             |
  | `2:3`  | Potret    | Poster, full-body          |
  | `3:2`  | Lanskap   | Foto, adegan lebar         |
  | `3:4`  | Potret    | E-commerce, orang          |
  | `4:3`  | Lanskap   | Gambar display             |
  | `9:16` | Vertikal  | Cover Story / video pendek |
  | `16:9` | Lebar     | Banner, cover video        |

  Alias piksel: `1024x1024` (1:1), `1024x1792` (2:3), `1792x1024` (3:2), `720x1280` (9:16), `1280x720` (16:9).

  Nilai di luar whitelist mengembalikan `400 invalid_size` (mis. `1:2`, `2:1`, `4:5`, `auto`).

  <Note>
    Piksel aktual untuk rasio tertentu dapat berbeda dari tabel alias (mis. `1:1` dapat mengembalikan 1408×1408). Percayai gambar yang dikembalikan; jangan menulis ulang `size` dari piksel terukur.
  </Note>
</ParamField>

<ParamField body="resolution" type="string">
  Bidang mode kualitas. Nilai terverifikasi: `quality`.

  * Abaikan (model default mode quality), atau
  * Kirim `resolution: "quality"` secara eksplisit

  **Bukan** tier piksel `1K` / `2K` / `4K`; framing dikontrol oleh `size`.

  <Warning>
    Jangan kirim bidang publik `quality` — Anda mendapat `400 invalid_quality`. Gunakan `resolution`.
  </Warning>
</ParamField>

<ParamField body="response_format" type="string" default="url">
  Hanya `url` yang diizinkan. Boleh diabaikan. `b64_json` / `base64` → `400 invalid_response_format`.
</ParamField>

<ParamField body="webhook" type="string">
  Opsional. HTTPS **base URL** publik. Saat status terminal, platform POST ke `{webhook}/callback`. Hanya sisi server — lihat [Webhook](#webhook-opsional).
</ParamField>

### Parameter yang tidak didukung

| Parameter                                  | Perilaku                                     |
| ------------------------------------------ | -------------------------------------------- |
| `quality`                                  | `400 invalid_quality` → gunakan `resolution` |
| `style`                                    | `400 invalid_style`                          |
| `image_urls` / `image_with_roles`          | `400 invalid_image_input`                    |
| `stream: true`                             | `400 invalid_stream`                         |
| `response_format: "b64_json"` / `"base64"` | `400 invalid_response_format`                |

Bangun permintaan dengan whitelist; jangan meneruskan objek form generik dari model gambar lain.

## Contoh permintaan

### Minimal

```json theme={null}
{
  "model": "grok-imagine-2.0-ext",
  "prompt": "A red apple on a white ceramic plate, clean studio product photo"
}
```

### Direkomendasikan

```json theme={null}
{
  "model": "grok-imagine-2.0-ext",
  "prompt": "A red apple on a white ceramic plate, clean studio product photo",
  "n": 1,
  "size": "1:1",
  "resolution": "quality",
  "response_format": "url"
}
```

## Respons submit

Lebih baik `X-APIMart-Response-Version: 2026-07-27`. Sukses adalah HTTP **`202`**; task id ada di **`data.id`** (jangan andalkan format lama `data[0].task_id`).

Simpan:

* `data.id` untuk polling
* `request_id` untuk debugging gateway
* `Idempotency-Key` untuk retry aman saat hasil tidak diketahui
* parameter permintaan asli untuk UI / dukungan

## Idempotensi dan retry aman

Pembuatan gambar ditagih — **sangat disarankan** `Idempotency-Key` (1–191 karakter ASCII yang dapat dicetak; UUID paling mudah; disimpan \~24 jam).

| Skenario                           | Perilaku                                      | Tindakan                                       |
| ---------------------------------- | --------------------------------------------- | ---------------------------------------------- |
| Key sama + body sama sudah selesai | Replay; header `Idempotency-Replayed: true`   | Gunakan task id yang sama                      |
| Key sama masih diproses            | `409 idempotency_in_progress` + `Retry-After` | Tunggu, retry **key dan body yang sama**       |
| Key sama, body berbeda             | `409 idempotency_key_reused`                  | Pekerjaan logis baru butuh key baru            |
| Hasil tidak pasti                  | `409 idempotency_result_indeterminate`        | Jangan buat key baru; selidiki dengan key lama |

Pada timeout jaringan POST saat Anda tidak tahu apakah server menerima pekerjaan, **jangan langsung buat key baru** — retry dengan key / body / versi respons yang sama.

## Polling tugas

```http theme={null}
GET /v1/tasks/{task_id}?language=en
Authorization: Bearer YOUR_API_KEY
Accept: application/json
```

Opsional `language`: `zh` / `en` / `ko` / `ja` (hanya lokalisasi pesan kegagalan). Lihat [Dapatkan status tugas](/id/api-reference/tasks/status).

### Status

| `status`                 | Terminal | Penanganan                                                             |
| ------------------------ | :------: | ---------------------------------------------------------------------- |
| `pending` / `processing` |   Tidak  | Lanjut polling (`result` bisa absen — bukan kegagalan)                 |
| `completed`              |    Ya    | Parse `result.images`                                                  |
| `failed`                 |    Ya    | Tampilkan `error.message`; `cost` adalah `0` (pre-charge dikembalikan) |
| `unknown`                |   Tidak  | Retry singkat; jika bertahan, hubungi dukungan dengan task id          |

Polling sekitar setiap **2 detik**; batas mendekati **10 menit** atau **120** percobaan. Hormati `Retry-After` pada `429`. Tugas disimpan \~3 hari secara default — simpan task id jika klien timeout.

### Contoh selesai

```json theme={null}
{
  "code": 200,
  "data": {
    "id": "task_01KZQE5CM0Y3KZ6M1N1BK619MX",
    "status": "completed",
    "progress": 100,
    "created": 1786419262,
    "completed": 1786419275,
    "actual_time": 13,
    "estimated_time": 100,
    "cost": 0.08,
    "credits_cost": 0.8,
    "result": {
      "images": [
        {
          "expires_at": 1786505675,
          "url": [
            "https://example.com/image/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.jpg"
          ],
          "image_ids": [
            "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
          ]
        }
      ]
    }
  }
}
```

### Parsing `url` dan `image_ids`

```text theme={null}
result.images[]
  ├─ url[]          ← authoritative display/download field (array)
  ├─ image_ids[]    ← optional opaque IDs
  └─ expires_at     ← Unix seconds; multiply by 1000 for JS Date
```

1. Gunakan `url[]` untuk tampilan; saat `n>1`, telusuri semua entri
2. Pasangkan per indeks hanya jika `image_ids.length === url.length`
3. `image_ids` yang hilang tetap memungkinkan tampilan
4. Tautan berlaku **72 jam** — unduh segera; juga percayai `expires_at`

## Penagihan

Harga dasar **\$0.08 per gambar** (pengiriman berhasil):

| `n` | Estimasi dasar |
| --: | -------------: |
|   1 |         \$0.08 |
|   4 |         \$0.32 |
|   8 |         \$0.64 |
|  12 |         \$0.96 |

* UI pra-submit sebaiknya mengatakan “estimasi”; USD final adalah **`data.cost`**
* **`data.credits_cost`** adalah tampilan kredit (saat ini \~ USD × 10)
* Pre-charge berdasarkan jumlah diminta; settle berdasarkan jumlah berhasil (refund parsial jika gagal parsial)
* Gagal penuh: `cost=0`, pre-charge dikembalikan
* Jangan membangun kunci harga dari `resolution`; model ini flat per gambar

## Webhook (opsional)

```json theme={null}
{
  "webhook": "https://your-service.example.com/apimart"
}
```

* Berikan **base URL**; platform memanggil `{base}/callback`
* Harus publik dan lolos pemeriksaan SSRF
* Jika `webhook_secret` diset, tanda tangan adalah `hex(HMAC-SHA256(secret, raw_body))` atas byte mentah
* Body callback cocok dengan `data` kueri tugas (tanpa wrapper ekstra `{code,data}`)
* Tetap sediakan polling frekuensi rendah sebagai fallback

## Kesalahan umum

| HTTP | `error.code`              | Penyebab                   | Tindakan                                                     |
| ---: | ------------------------- | -------------------------- | ------------------------------------------------------------ |
|  400 | `invalid_request`         | Prompt kosong / JSON buruk | Validasi input                                               |
|  400 | `invalid_n`               | `n` di luar 1–12           | Batasi jumlah                                                |
|  400 | `invalid_size`            | Size tidak di whitelist    | Opsi select tetap                                            |
|  400 | `invalid_response_format` | Bukan `url`                | Perbaiki atau abaikan                                        |
|  400 | `invalid_quality`         | `quality` publik dikirim   | Gunakan `resolution`                                         |
|  400 | `invalid_style`           | `style` dikirim            | Hapus                                                        |
|  400 | `invalid_image_input`     | Gambar referensi           | Ganti model                                                  |
|  400 | `invalid_stream`          | `stream=true`              | Hapus                                                        |
|  400 | `invalid_idempotency_key` | Key buruk                  | Gunakan UUID                                                 |
|  401 | Gagal autentikasi         | Key buruk                  | Perbaiki credentials server                                  |
|  402 | Pembayaran diperlukan     | Saldo rendah               | Top up                                                       |
|  409 | `idempotency_*`           | Konflik idempotensi        | Lihat tabel di atas                                          |
|  429 | Rate limit                | Terlalu cepat              | Hormati `Retry-After`                                        |
|  5xx | Kesalahan server          | —                          | Simpan Idempotency-Key; jangan ganti key secara membabi buta |

Lebih baik `error.message` untuk UI. Jangan tampilkan detail autentikasi internal ke pengguna akhir.

## Perbedaan dari 1.5 (ringkasan)

| Item            | Grok Imagine 1.5                  | 2.0 Ext                                           |
| --------------- | --------------------------------- | ------------------------------------------------- |
| Model           | `grok-imagine-1.5-apimart`, dll.  | `grok-imagine-2.0-ext`                            |
| Image-to-image  | Didukung (lihat dokumen 1.5)      | **Tidak didukung**                                |
| Jumlah          | Lihat dokumen 1.5                 | **1–12**                                          |
| Bidang kualitas | Lihat dokumen 1.5                 | `resolution` (`quality`); jangan `quality` publik |
| Output          | Lihat dokumen 1.5                 | **Hanya url**                                     |
| TTL URL         | Lihat dokumen 1.5 (sering 24 jam) | **72 jam**                                        |
| Harga satuan    | Lihat dokumen 1.5                 | **\$0.08 / gambar**                               |
