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

# Quickstart

> Learn how to onboard to imini Open Platform and make your first API call.

This guide walks you through the full flow from setting up your account to making your first API call. It takes about 5 minutes.

## Prerequisites

Before you start, please confirm the following:

<Steps>
  <Step title="Create an imini account">
    Visit [imini.ai](https://imini.ai) to register and verify your email.
  </Step>

  <Step title="Top up credits">
    All API calls are billed in credits. See [Pricing](/en/guide/pricing) for each model's consumption rules. Please top up at [Credits](https://imini.ai/credits) before making any calls.
  </Step>

  <Step title="Create an API Key">
    Go to the [**API Keys management page**](https://imini.ai/api-keys), create an API Key for server-side use, and store it securely.
  </Step>
</Steps>

## Base URL

All imini Open Platform endpoints share the same base URL:

```
https://openapi.imini.ai/imini/router
```

The relative paths in the examples below (such as `/v1/images/generate`) should be appended to this base URL.

## Authentication

Every request authenticates via an HTTP header using the Bearer Token standard:

```http theme={null}
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
```

<Warning>
  **API Key security**: Only use your API Key on the server side. Never commit it to a code repository, ship it in frontend code or mobile apps, or expose it in any other way. If you suspect a key has leaked, rotate it immediately on the [API Keys management page](https://imini.ai/api-keys).
</Warning>

## Asynchronous Task Model

All generation endpoints on imini (image and video) use an asynchronous task model. A complete generation flow is two steps:

```
┌──────────────────────────────────────────┐
│ 1. Submit the generation task            │
│    POST /v1/images/generate              │
│    → synchronously returns { task_id }   │
└────────────────┬─────────────────────────┘
                 │
                 ▼
┌──────────────────────────────────────────┐
│ 2. Poll the task status                  │
│    GET  /v1/images/tasks/{task_id}       │
│    → status: queued → processing         │
│             → succeeded (with images[].url) │
│             → failed (with error object) │
└──────────────────────────────────────────┘
```

<Note>
  The image task query endpoint is `/v1/images/tasks/{task_id}`; the video task query endpoint is `/v1/videos/tasks/{task_id}`. A polling interval of **2 seconds** is recommended. Image tasks typically complete within **10–30 seconds**.
</Note>

## Step 1: Submit the Generation Task

The example below uses the `google/nano-banana` model to generate a 1:1 image:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://openapi.imini.ai/imini/router/v1/images/generate \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "google/nano-banana",
      "prompt": "An orange cat napping under a cherry blossom tree, watercolor style",
      "aspect_ratio": "1:1"
    }'
  ```

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

  BASE_URL = "https://openapi.imini.ai/imini/router"
  API_KEY = "YOUR_API_KEY"

  response = requests.post(
      f"{BASE_URL}/v1/images/generate",
      headers={
          "Authorization": f"Bearer {API_KEY}",
          "Content-Type": "application/json",
      },
      json={
          "model": "google/nano-banana",
          "prompt": "An orange cat napping under a cherry blossom tree, watercolor style",
          "aspect_ratio": "1:1",
      },
      timeout=30,
  )
  response.raise_for_status()
  task_id = response.json()["task_id"]
  print(f"Submitted task: {task_id}")
  ```

  ```javascript Node.js theme={null}
  const BASE_URL = 'https://openapi.imini.ai/imini/router';
  const API_KEY = 'YOUR_API_KEY';

  const response = await fetch(`${BASE_URL}/v1/images/generate`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'google/nano-banana',
      prompt: 'An orange cat napping under a cherry blossom tree, watercolor style',
      aspect_ratio: '1:1',
    }),
  });

  if (!response.ok) {
    throw new Error(`Submit failed: ${response.status}`);
  }
  const { task_id } = await response.json();
  console.log(`Submitted task: ${task_id}`);
  ```
</CodeGroup>

**Successful response** (HTTP 200):

```json theme={null}
{
  "task_id": "task_2041350318103396352",
  "model": "google/nano-banana",
  "created_at": "2026-04-07T03:00:17.062Z",
  "request_id": "285f20ce-8158-401b-945c-7bc6a7ef6ead"
}
```

## Step 2: Poll the Task Result

Use the `task_id` returned above to poll until `status` becomes `succeeded` or `failed`:

<CodeGroup>
  ```bash cURL theme={null}
  curl https://openapi.imini.ai/imini/router/v1/images/tasks/TASK_ID \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

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

  def wait_for_result(task_id: str, interval: int = 2, timeout: int = 120):
      """Poll the task result, waiting up to `timeout` seconds."""
      deadline = time.time() + timeout
      while time.time() < deadline:
          result = requests.get(
              f"{BASE_URL}/v1/images/tasks/{task_id}",
              headers={"Authorization": f"Bearer {API_KEY}"},
              timeout=10,
          ).json()

          status = result["status"]
          if status == "succeeded":
              return result["images"]
          if status == "failed":
              raise RuntimeError(f"Task failed: {result['error']}")

          time.sleep(interval)

      raise TimeoutError(f"Task {task_id} timed out after {timeout}s")

  images = wait_for_result(task_id)
  print(images[0]["url"])
  ```

  ```javascript Node.js theme={null}
  async function waitForResult(taskId, { intervalMs = 2000, timeoutMs = 120_000 } = {}) {
    const deadline = Date.now() + timeoutMs;
    while (Date.now() < deadline) {
      const res = await fetch(`${BASE_URL}/v1/images/tasks/${taskId}`, {
        headers: { Authorization: `Bearer ${API_KEY}` },
      });
      const data = await res.json();

      if (data.status === 'succeeded') return data.images;
      if (data.status === 'failed') throw new Error(`Task failed: ${JSON.stringify(data.error)}`);

      await new Promise(r => setTimeout(r, intervalMs));
    }
    throw new Error(`Task ${taskId} timed out`);
  }

  const images = await waitForResult(task_id);
  console.log(images[0].url);
  ```
</CodeGroup>

**Task status values**:

| Status       | Meaning                                                 |
| ------------ | ------------------------------------------------------- |
| `queued`     | Task submitted, waiting to enter the processing queue   |
| `processing` | Model is generating                                     |
| `succeeded`  | Generation succeeded, result is in the `images[]` field |
| `failed`     | Generation failed, details in the `error` object        |

**Successful response example** (`status: succeeded`):

```json theme={null}
{
  "task_id": "task_2041350318103396352",
  "status": "succeeded",
  "model": "google/nano-banana",
  "created_at": "2026-04-07T03:00:17.062Z",
  "completed_at": "2026-04-07T03:00:29.418Z",
  "images": [
    {
      "url": "https://file.iminicdn.com/file/2026/04/07/xxxx.png",
      "width": 1024,
      "height": 1024
    }
  ],
  "error": null,
  "request_id": "285f20ce-8158-401b-945c-7bc6a7ef6ead"
}
```

## Error Handling

All error responses share a unified structure:

```json theme={null}
{
  "error": {
    "code": "INVALID_PARAMETER",
    "message": "aspect_ratio must be one of: 1:1, 2:3, ...",
    "status": 400,
    "request_id": "req_abc123"
  }
}
```

**Common HTTP status codes**:

| Status | Meaning                    | Typical cause                                                                   |
| ------ | -------------------------- | ------------------------------------------------------------------------------- |
| `400`  | Invalid request parameters | Missing required field, invalid enum value, or prompt flagged by content safety |
| `401`  | Authentication failed      | API Key missing, invalid, or revoked                                            |
| `402`  | Insufficient credits       | Account balance cannot cover this call                                          |
| `404`  | Resource not found         | The specified `task_id` does not exist or has expired                           |
| `429`  | Rate limit exceeded        | Exceeded your account's rate quota; back off and retry                          |
| `500`  | Internal platform error    | Platform-side issue; please retry later                                         |
| `502`  | Upstream model error       | Underlying model service unavailable; usually safe to retry immediately         |

<Tip>
  Every response includes a `request_id`. Please include it when submitting tickets or contacting support so we can investigate quickly.
</Tip>

## Production Integration Tips

Before integrating imini into production, review the following practices:

* **Set reasonable polling intervals**: We recommend a first poll at 2 seconds, then exponential backoff (2s / 3s / 5s) to reduce pressure on the query endpoint.
* **Configure sensible timeouts**: Use a 30-second timeout for submission calls. Set overall polling timeouts based on the model (e.g., 2 minutes for image, 10 minutes for video).
* **Error retry strategy**: For `429`, `500`, and `502`, retry 2–3 times with random jitter. Do not retry `400`, `401`, or `402`.
* **API Key rotation**: Store API Keys in a secrets manager (KMS / Secrets Manager), rotate them regularly, and use separate keys per business scenario for observability and isolation.
* **Idempotency and request tracing**: Record the submitted `task_id` and `request_id` on your side to reconcile against platform logs.
* **Content safety**: We recommend pre-screening user-supplied prompts and reference images on your side to reduce the likelihood of triggering `400` content-violation errors.

## Next Steps

<CardGroup cols={2}>
  <Card title="API Reference" icon="book" href="/en/api-reference/images/nano-banana">
    Full parameter definitions and an interactive Playground for each model
  </Card>

  <Card title="Pricing" icon="coins" href="/en/guide/pricing">
    Credit consumption rules by model, resolution, and scenario
  </Card>

  <Card title="Changelog" icon="bell" href="/en/changelog/index">
    Track new model launches, parameter changes, and service updates
  </Card>

  <Card title="Terms & Policies" icon="file-contract" href="/en/legal/terms">
    Please read the Terms of Service and Privacy Policy before onboarding
  </Card>
</CardGroup>
