---
title: Quickstart
description: Run your first image generation with the Clipia API in four steps, from creating a key to fetching the result, with cURL, TypeScript and Python examples.
icon: Rocket
---

To generate your first image with the Clipia API, follow four steps: create an API key, submit a job with `POST /v1/models/{model}`, wait for it to finish (webhook or status polling), and fetch the result. The base URL is `https://api.clipia.ai`. Every generation is asynchronous: the request queues a job and returns its ID right away.

<Steps>
<Step>
### Create an API key

Open the [Developer Console](/en/developer), go to the **API keys** tab and click **Create key**. The full key is shown **once**, so copy it straight away. All examples in these docs read the key from the `CLIPIA_KEY` environment variable.

```bash
export CLIPIA_KEY=clipia_live_xxxxxxxxxxxxxxxxxxxxxxxx
```

<Callout type="warn" title="The key is a server-side secret">
Never embed the key in a browser, mobile app or public repository. Use it only from your own server.
</Callout>

<Callout type="info" title="Active subscription required">
A live `clipia_live_` key can generate while the account has an active subscription; otherwise the request returns `402 subscription_required`. To build and debug without paying, create a `clipia_test_` key instead — see [Sandbox](/en/docs/getting-started/sandbox).
</Callout>
</Step>

<Step>
### Submit a generation

Send `POST /v1/models/{model}` with an `input` body. Get the model slug from `GET /v1/models` or the [model catalog](/en/docs/api-reference/models). The `Idempotency-Key` header makes a retry after a network failure safe: no second job is created.

<Tabs items={['cURL', 'TypeScript', 'Python']}>
<Tab value="cURL">

```bash
curl -X POST https://api.clipia.ai/v1/models/nano-banana-2 \
  -H "Authorization: Bearer $CLIPIA_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 8f3a1c7e-2b41-4d2a-9c0e-1200304cf45b" \
  -d '{
    "input": { "prompt": "a sunset over mountains, cinematic" },
    "webhook_url": "https://your-server.com/clipia/webhook"
  }'
```

</Tab>
<Tab value="TypeScript">

```ts
import { createClient } from "clipia-ai";

const clipia = createClient({ apiKey: process.env.CLIPIA_KEY! });

const job = await clipia.queue.submit("nano-banana-2", {
  input: { prompt: "a sunset over mountains, cinematic" },
  webhookUrl: "https://your-server.com/clipia/webhook",
});

console.log(job.request_id, job.status, job.cost);
```

</Tab>
<Tab value="Python">

```python
import os
from clipia import Clipia

clipia = Clipia(api_key=os.environ["CLIPIA_KEY"])

job = clipia.submit(
    "nano-banana-2",
    {"prompt": "a sunset over mountains, cinematic"},
    webhook_url="https://your-server.com/clipia/webhook",
)

print(job.request_id, job.status, job.cost)
```

</Tab>
</Tabs>

Both SDKs add an `Idempotency-Key` to every submit automatically. The response returns a `request_id` and polling URLs:

```json
{
  "request_id": "764cabcf-b745-4b3e-ae38-1200304cf45b",
  "status": "IN_QUEUE",
  "queue_position": 0,
  "status_url":   "https://api.clipia.ai/v1/requests/764cabcf-.../status",
  "response_url": "https://api.clipia.ai/v1/requests/764cabcf-...",
  "cost": 12
}
```

`cost` is the number of **credits** reserved for the job. They are charged on success and refunded in full if the generation fails. To see the price before submitting, use [cost estimation](/en/docs/api-reference/estimate).
</Step>

<Step>
### Wait for completion

There are two ways to learn that a generation is ready.

**Webhook (recommended).** If you pass a `webhook_url` on submit, Clipia sends a `POST` to your server when the job finishes. Every delivery is signed with HMAC-SHA256 — see [Webhooks](/en/docs/api-reference/webhooks).

**Status polling.** Query the `status_url` every 1–2 seconds until the status is terminal:

<Tabs items={['cURL', 'TypeScript', 'Python']}>
<Tab value="cURL">

```bash
curl https://api.clipia.ai/v1/requests/764cabcf-.../status \
  -H "Authorization: Bearer $CLIPIA_KEY"
```

</Tab>
<Tab value="TypeScript">

```ts
// subscribe() submits the job and polls until it finishes
const result = await clipia.subscribe("nano-banana-2", {
  input: { prompt: "a sunset over mountains, cinematic" },
  onQueueUpdate: (s) => console.log(s.status, s.progress),
});

console.log(result.status); // "COMPLETED"
```

</Tab>
<Tab value="Python">

```python
# subscribe() submits the job and polls until it finishes
result = clipia.subscribe(
    "nano-banana-2",
    {"prompt": "a sunset over mountains, cinematic"},
    on_queue_update=lambda s: print(s.status, s.progress),
)

print(result.status)  # "COMPLETED"
```

</Tab>
</Tabs>

```json
{ "request_id": "764cabcf-...", "status": "IN_PROGRESS", "queue_position": 0, "progress": 45 }
```

| Status | Meaning |
|--------|---------|
| `IN_QUEUE` | the job is queued |
| `IN_PROGRESS` | running (`progress` from 0 to 100) |
| `COMPLETED` | done, fetch the result |
| `FAILED` | failed, credits refunded |
| `CANCELED` | canceled outside the API (terminal status) |
</Step>

<Step>
### Fetch the result

Once the status is `COMPLETED`, request the result from `response_url`:

```bash
curl https://api.clipia.ai/v1/requests/764cabcf-... \
  -H "Authorization: Bearer $CLIPIA_KEY"
```

```json
{
  "request_id": "764cabcf-...",
  "status": "COMPLETED",
  "model": "nano-banana-2",
  "output": {
    "images": [
      {
        "url": "https://media.clipia.ai/....webp",
        "original_url": "https://media.clipia.ai/....png"
      }
    ]
  },
  "cost": 12,
  "created_at": "2026-10-09T12:00:00Z",
  "completed_at": "2026-10-09T12:00:18Z"
}
```

`url` is an optimized copy for display; `original_url` is the source file. For video, `output` contains `video: { url, original_url, thumbnail_url }`; for audio, `audio: { url }`. See [Result](/en/docs/api-reference/result) for details.
</Step>
</Steps>

<Callout type="info" title="Next">
Debug your integration without spending credits using a [test key](/en/docs/getting-started/sandbox). Before going live, read the [best practices](/en/docs/guides/best-practices).
</Callout>
