# Generate Image

> Generate an image from a text prompt. Synchronous by default; returns 202 and delivers by webhook when given a callback URL.

Image generation is synchronous by default: the API waits for the image and returns its URL directly. Typical latency is a few seconds up to about 30s depending on the model and size.

Supplying a delivery target (`callback_url` or `webhook`) switches the call to the asynchronous contract instead — it returns `202` immediately and POSTs the finished image to you. See [Async Image Generation](/docs/developer-tools/async-image-generation) for the full guide.

## `POST /v1/images/generate`

Generate an image from a text prompt. Returns a URL to the image hosted on the PicX CDN.

**Auth:** API Key

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `prompt` | `string` | Yes | Text description of the image. Required. Maximum 4000 characters. |
| `model` | `string` | No | Model id. Defaults to gemini-3.1-flash-image-preview. See GET /v1/models. |
| `size` | `string` | No | Image quality: 1K, 2K, or 4K. Optional; the API uses 1K when omitted. |
| `aspect_ratio` | `string` | No | Aspect ratio in W:H form, e.g. 16:9, 1:1, or 9:16. |
| `callback_url` | `string` | No | Public HTTPS URL to POST the result to. **Supplying this returns 202 instead of 200.** Maximum 2048 characters; private and loopback addresses are rejected. |
| `webhook` | `object` | No | Delivery target as `{"id": "…"}` (a webhook registered in the console) or `{"url": "…"}` (one-off), with an optional `events` array. Also returns 202. |
| `idempotency_key` | `string` | No | Body-level twin of the `Idempotency-Key` header. The header wins if both are sent. |

| Header | Type | Required | Description |
| --- | --- | --- | --- |
| `Idempotency-Key` | `string` | No | Deduplicate retried requests. If a request with the same key was already completed, the original response is returned without re-billing credits. 8–128 URL-safe characters. |

**Response — 200, synchronous (no delivery target)**

```json
{
  "id": "img_abc123def456",
  "url": "https://cdn.picxstudio.com/generated/abc123.png",
  "model": "gemini-3.1-flash-image-preview",
  "size": "2K",
  "aspect_ratio": "16:9",
  "credits_used": 53,
  "created_at": "2026-06-17T20:00:00Z"
}
```

**Response — 202, asynchronous (`callback_url` or `webhook` supplied)**

```json
{
  "id": "d3bfa107-6475-4f5b-ad32-c65c3e1b0377",
  "status": "pending",
  "type": "image",
  "model": "gemini-3.1-flash-image-preview",
  "poll_url": "/v1/generations/d3bfa107-6475-4f5b-ad32-c65c3e1b0377",
  "events_url": "/v1/generations/d3bfa107-6475-4f5b-ad32-c65c3e1b0377/events",
  "webhook": {
    "mode": "legacy_callback",
    "id": null,
    "url": "https://your-server.com/hooks/picx",
    "events": ["generation.completed", "generation.failed"]
  }
}
```

## Generate an image

**JavaScript SDK**

```bash
npm install picx-ai
```

```js
import { PicX } from "picx-ai";

const picx = new PicX(process.env.PICX_API_KEY);

const asset = await picx.images.generate({
  prompt: "a cute cat on a windowsill, soft morning light",
  model: "gemini-3.1-flash-image-preview",
  size: "2K",
  aspect_ratio: "16:9",
});

console.log(asset.url);          // hosted CDN URL
console.log(asset.credits_used); // credits billed for this call
```

**Python SDK**

```bash
pip install picx-ai
```

```python
import os
from picx import PicX

picx = PicX(os.environ["PICX_API_KEY"])

asset = picx.images.generate(
    prompt="a cute cat on a windowsill, soft morning light",
    model="gemini-3.1-flash-image-preview",
    size="2K",
    aspect_ratio="16:9",
)

print(asset.url)           # hosted CDN URL
print(asset.credits_used)  # credits billed for this call
```

**curl**

```bash
curl -X POST https://api.picxstudio.com/v1/images/generate \
  -H "Authorization: Bearer pxsk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"a cute cat on a windowsill, soft morning light","model":"gemini-3.1-flash-image-preview","size":"2K","aspect_ratio":"16:9"}'
```

## Generate without waiting

Add `callback_url` and the call returns as soon as the job is queued. The SDKs return a job handle instead of an image.

```js
const job = await picx.images.generate({
  prompt: "a cute cat on a windowsill",
  callback_url: "https://your-server.com/hooks/picx",
});

console.log(job.id);     // persist this to correlate the delivery
console.log(job.status); // "pending"
```

```python
job = picx.images.generate(
    "a cute cat on a windowsill",
    callback_url="https://your-server.com/hooks/picx",
)

print(job.id, job.status)
```

Requires `picx-ai` 0.3.0 or later. Full details — payload shape, signature verification, retries, and the polling fallback — are in [Async Image Generation](/docs/developer-tools/async-image-generation).

## Error handling

```js
import { PicX, ValidationError, RateLimitError } from "picx-ai";

const picx = new PicX(process.env.PICX_API_KEY);

try {
  const asset = await picx.images.generate({ prompt: "a sunset" });
  console.log(asset.url);
} catch (err) {
  if (err instanceof ValidationError) {
    console.error("Bad params:", err.message);
  } else if (err instanceof RateLimitError) {
    console.error(`Rate limited, retry in ${err.retryAfter}s`);
  } else {
    throw err;
  }
}
```

> [!NOTE]
> Prompt tips: be specific about subject, style, lighting, and composition. Quality cues like "photorealistic", "cinematic", or "4k" help.

> [!WARNING]
> If generation fails after credits are deducted, the credits are refunded automatically and the API returns a 500 with error details.

## FAQ

### Is image generation synchronous or do I have to poll a job?

Synchronous. The API waits for the image and returns its hosted URL directly in the response — typically a few seconds, up to about 30s depending on the model and size. There's no job to poll for this endpoint.

### What does the API return — a URL or the raw image bytes?

A URL, hosted on the PicX CDN (`cdn.picxstudio.com`). The image itself isn't returned inline in the response body.

### How do I avoid double-billing if a request times out and I retry it?

Send an `Idempotency-Key` header. If a request with the same key already completed, the original response is returned and credits aren't billed again.

### What happens to my credits if generation fails?

They're refunded automatically, and the API returns a 500 with error details — you're never charged for a failed generation.

### Which image models are available, and which is used by default?

`gemini-3.1-flash-image-preview` is the default when `model` is omitted. See the [list of models](/docs/api-reference/list-models) for the full set and their credit costs.
