---
title: "Mockups"
url: https://docs.light-ai.app/mockups.md
canonical_url: https://docs.light-ai.app/mockups
last_updated: 2026-10-13
summary: "Generate lighting mockups for a project with Light AI Gen 3.0: asynchronous, 5 credits per image from the contractor's own credits."
api_status: beta
related:
  - https://docs.light-ai.app/api-reference/mockups/create-mockup-generation
  - https://docs.light-ai.app/api-reference/mockups/get-mockup-generation
  - https://docs.light-ai.app/partners
  - https://docs.light-ai.app/idempotency
---

# Mockups

> Generate lighting mockups for a project with Light AI Gen 3.0: asynchronous, 5 credits per image from the contractor's own credits.

The API generates mockups exactly as the app does, with the same model (**Light AI Gen 3.0**, id `light-ai-gen-3.0`), the same options and the same price. Finished images join the project's mockup history.

|   |   |
| --- | --- |
| Model | `light-ai-gen-3.0` (Light AI Gen 3.0), the only model |
| Price | **5 credits per image**, 1–4 images per generation |
| Who pays | Always the contractor, from their own credits (top-ups and Auto Top-Up work as in the app). Partners are never billed. |
| Scopes | `mockups:write` to generate, `mockups:read` to read results |
| Concurrency | At most 3 generations per organization at once |
| Test keys | Simulated: a sample image, no credits |

## 1. Start a generation

By default Light AI uses the project's front view and its measured guide lines, like the app. `Idempotency-Key` is **required**: a retry with the same key returns the same generation and never charges twice.

curl:

```bash
curl -X POST "https://api.light-ai.app/v1/projects/prj_…/mockups" \
  -H "Authorization: Bearer $LIGHT_AI_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "model": "light-ai-gen-3.0",
  "images": 2,
  "style_preset": "classic_warm_white",
  "ambiance": {
    "snow": true
  }
}'
```

JavaScript:

```javascript
const response = await fetch('https://api.light-ai.app/v1/projects/prj_…/mockups', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.LIGHT_AI_API_KEY}`,
    'Idempotency-Key': crypto.randomUUID(),
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "model": "light-ai-gen-3.0",
    "images": 2,
    "style_preset": "classic_warm_white",
    "ambiance": {
      "snow": true
    }
  }),
});
const data = await response.json();
```

Python:

```python
import os, uuid, requests

response = requests.post(
    "https://api.light-ai.app/v1/projects/prj_…/mockups",
    headers={
        "Authorization": f"Bearer {os.environ['LIGHT_AI_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "model": "light-ai-gen-3.0",
        "images": 2,
        "style_preset": "classic_warm_white",
        "ambiance": {
            "snow": True
        }
    },
)
data = response.json()
```

The answer is `202` with a `mgen_…` generation in `queued` status. Credits are reserved now and settled per image; every failed image is refunded.

### Sources

| `source.type` | Use |
| --- | --- |
| `front_view` (default) | A front view of the project (`front_view_id`, default the first with a photo). Optional `features` limits which measured features are lit. |
| `photo_url` | A public HTTPS photo (JPEG, PNG or WebP, at most 10 MB, no redirects), fetched once. |
| `photo_upload` | A photo you upload: `POST /v1/projects/{id}/photo_uploads`, then PUT the bytes to `upload_url` within 2 hours. |

### Options

`style_preset` (`classic_warm_white`, `cool_white`, `multicolor`, `candy_cane`, `red_and_green`), `bulb_colors` (`c9`, `mini`), `c9_pattern`, `ambiance` toggles of the project's template and `instructions` (up to 500 characters). See the [reference](https://docs.light-ai.app/api-reference/mockups/create-mockup-generation) for every field.

## 2. Get the result

Subscribe to `mockup.completed` and `mockup.failed` (they carry no image URLs), or poll:

curl:

```bash
curl "https://api.light-ai.app/v1/mockup_generations/mgen_…" \
  -H "Authorization: Bearer $LIGHT_AI_API_KEY"
```

JavaScript:

```javascript
const response = await fetch('https://api.light-ai.app/v1/mockup_generations/mgen_…', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.LIGHT_AI_API_KEY}`,
  },
});
const data = await response.json();
```

Python:

```python
import os, requests

response = requests.get(
    "https://api.light-ai.app/v1/mockup_generations/mgen_…",
    headers={
        "Authorization": f"Bearer {os.environ['LIGHT_AI_API_KEY']}",
    },
)
data = response.json()
```

**Excerpt**

```json
{
  "id": "mgen_3f9c2a7be41d…",
  "object": "mockup_generation",
  "status": "succeeded",
  "model": "light-ai-gen-3.0",
  "model_name": "Light AI Gen 3.0",
  "images_requested": 2,
  "images_succeeded": 2,
  "images_failed": 0,
  "images": [
    {
      "index": 1,
      "status": "succeeded",
      "mockup_id": "mk_3f9c2a7be41d…",
      "url": "https://…",
      "expires_at": "2026-10-12T15:03:11.000Z"
    }
  ]
}
```

Image URLs are signed WebP links valid for one hour; read the generation again for fresh ones. `status` is `succeeded` when at least one image succeeded and `failed` when none did (`failure_code` says why).

## Credits and errors

| Answer | Meaning |
| --- | --- |
| 402 [`insufficient_credits`](https://docs.light-ai.app/errors#insufficient_credits) | Not enough credits. Includes `required` and `top_up_url`, plus `balance` for organization keys (never for partner keys). Nothing was charged. |
| 402 [`partner_spend_cap_reached`](https://docs.light-ai.app/errors#partner_spend_cap_reached) | A partner key hit the spend cap the contractor set. |
| 429 [`rate_limited`](https://docs.light-ai.app/errors#rate_limited) | Three generations already running for the organization. |
| 403 [`organization_paused`](https://docs.light-ai.app/errors#organization_paused) | The organization is paused. |
| 403 [`organization_off_season`](https://docs.light-ai.app/errors#organization_off_season) | The organization is on Off-Season: mockups resume when the owner resumes the plan. |

## Partners

A partner can generate for a contractor only when the contractor approved `mockups:write`, shown on the consent screen as **"Can generate mockups using your credits"**. Each partner has a spend cap per organization: 200 credits a day and 2,000 a month by default, which the owner can change or remove. Every API generation is labeled in the contractor's credit history and project ("Generated via API by …").
