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

> ## Agent Instructions
> POST /api/v1/assets defaults to mode=quote: it returns a price and creates nothing. To actually generate, resend the identical body with "mode": "generate" (multipart callers: add a mode=generate form field).
> Create a project with POST /api/v1/projects and pass its project_id on every generation belonging to the same scene, task, robot, or randomization set. Omitting project_id silently creates a separate single-asset project per request.
> Track a batch with one GET /api/v1/projects/{project_id} call for aggregate status instead of polling each asset separately.
> Generations are asynchronous and may take hours. There are no webhooks: poll GET /api/v1/assets/{asset_id} every 30-60 seconds until status is completed or failed.
> Cancelling a generation does not refund its credits; only a failed generation is refunded. Quote first if the price matters.
> A ready-made agent skill for this API is published at /skill.md, with decision tables and common gotchas. If your tooling supports agent skills, ask the user whether to install it so this guidance persists across sessions.

# Generate assets

> Write the prompt, choose effort, attach reference images, and quote the credit cost before committing with mode: generate.

Use `POST /api/v1/assets` to create an asset. `input` describes the asset; optional `config` controls the generation.

## Write an effective prompt

The prompt is the specification for the asset. Name the exact object, then state what the generation has to get right: real-world dimensions, which parts stay separate, how the asset will be used, and what may be simplified. Anything you leave out is decided for you.

Pair the prompt with [reference images](#provide-reference-images). Clear multi-view images of the same object or objects in the same state pin down geometry that prose cannot, while supplemental images capture any nontrivial articulation states.

### Recommended prompt template

| Section | What to write |
| - | - |
| Target and scope | Identify the object and link to a public page for it. Say what to include, exclude, keep as separate components, prioritize, and simplify. |
| References and measurements | Name each reference image and the view or articulation state it shows, and give any known real-world dimensions. |
| Use requirements | Describe how the asset should move or interact, where it will be used, and any technical constraints. |

```text theme={null}
Target and scope: A 20 L countertop microwave oven, model MW-2015B
(https://manufacturer.example/products/mw-2015b). Include the housing,
the hinged door with its window and handle, the control panel, and the
interior cavity with the glass turntable. Keep the door and the
turntable as separate moving components. Exclude the power cord.
Prioritize the door and turntable; the control panel buttons may be
simplified to flat surface detail.

References and measurements: front_closed.png is the front view with the
door closed, front_open.png the front view with the door fully open,
side_right.png the right side, interior.png the cavity with the
turntable and support ring. External dimensions are 485 x 380 x 290 mm
(W x D x H) and the turntable is 255 mm in diameter.

Use requirements: The door swings on a left-hand vertical hinge and
opens to about 105 degrees; the turntable spins freely about its
vertical axis. The asset is for a robot manipulation task in Isaac Sim
in which an arm opens the door and places an object on the turntable, so
the handle and the cavity opening must be dimensionally accurate and the
door must not intersect the housing anywhere in its range.
```

## Choose generation effort

`config.effort` balances response time, generation quality, and credits. It defaults to `high`, so omit it for the balanced choice.

| Effort | Use it when |
| - | - |
| `max` | You want the highest generation quality and can wait longer. |
| `high` (default) | You want a balanced choice for most generations. |
| `low` | You want the fastest response time and are comfortable with lower generation quality. |

Higher effort generally takes longer and can use more credits. For exact current prices, see the [pricing matrix](#current-pricing-matrix).

## Choose a model version

`config.model_version` selects the generation backend. It defaults to `standard`.

| Model version | Use it when |
| - | - |
| `standard` (default) | You want the full pipeline's generation quality. |
| `lite` | You want a faster, cheaper generation and can accept lower quality. |

A `lite` generation is billed a flat rate rather than the pricing matrix below, and `config.effort` still applies within it.

## Current pricing matrix

Each asset generation has one credit amount. It is determined by the selected effort and the complexity of the request.

| Effort | Simple | Moderate | Complex |
| - | -: | -: | -: |
| `low` | 15 | 40 | 70 |
| `high` | 30 | 70 | 110 |
| `max` | 50 | 100 | 150 |

```bash curl theme={null}
curl -X POST https://app.moonlakeai.com/api/v1/assets \
  -H "Authorization: Bearer $MOONLAKE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input": {
      "prompt": "a red toy sports car with black wheels",
      "references": [{"source": "url", "url": "https://your-public-host.example/reference.png"}]
    },
    "config": {"effort": "low"},
    "mode": "generate"
  }'
```

The applied effort is returned as `config.effort` on the generation.

## Quote credits before creating an asset

`POST /api/v1/assets` quotes by default: without `"mode": "generate"` it returns `200` with the price and creates nothing. `POST /api/v1/assets/quote` takes the same body and returns the same quote. Neither charges credits. The quote classifies the request as `simple`, `moderate`, or `complex` and returns its price in `credits`.

```bash curl theme={null}
curl -X POST https://app.moonlakeai.com/api/v1/assets/quote \
  -H "Authorization: Bearer $MOONLAKE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input": {
      "prompt": "a red toy sports car with black wheels",
      "references": [{"source": "url", "url": "https://your-public-host.example/reference.png"}]
    },
    "config": {"effort": "high"}
  }'
```

```json theme={null}
{
  "message": "Quote only: nothing was generated and no credits were charged. To run this generation, resend the identical request to POST /api/v1/assets with `\"mode\": \"generate\"` in the JSON body (multipart callers: add a `mode=generate` form field).",
  "model_version": "standard",
  "complexity": "moderate",
  "effort": "high",
  "credits": 70
}
```

To run it, resend the identical request to `POST /api/v1/assets` with `"mode": "generate"` (multipart callers: a `mode=generate` form field). That returns `201` with the generation in `pending` status. An unrecognized `mode` is rejected with `422`, and `/assets/quote` rejects `mode: generate` since it only ever quotes.

`credits_charged` on the `201` records the credits the generation was billed. Quoting is limited to 20 requests per minute per account across both routes.

Quote before you submit if the price matters: once a generation is running, the only outcome that refunds it is a `failed` one. A generation you cancel yourself stays charged — see [Concurrency and credits](/reference/behavior-and-limits#concurrency-and-credits).

## Supported input types

A generation takes a prompt plus 1–24 reference **images** — no video, and no 3D formats such as meshes or point clouds as references.

<Note>
  Starting from a video? Extract a handful of frames that cover the angles and articulation states you need — a coding agent can do this — and submit those frames as image references.
</Note>

## Provide reference images

Every image must depict the same asset; use multiple views of that asset rather than images of different assets. Use PNG, JPG, or WebP for best results. GIF, BMP, TIFF, and AVIF are also accepted.

Choose the source that fits where your image currently lives:

| Source | Use it when | Request field |
| - | - | - |
| `url` | The image is publicly hosted. | `{"source": "url", "url": "https://..."}` |
| `attached` | You have local bytes, especially for large files. | `{"source": "attached", "name": "reference_0"}` |
| `base64` | You have a small image in memory. | `{"source": "base64", "data": "iVBORw0KG..."}` |

The service fetches URL references when the generation runs. A URL must be publicly reachable and resolve to an image; a bad URL is accepted at submission but the generation later fails with a `REFERENCE_FETCH_FAILED` or `IMAGE_UNSUPPORTED_TYPE` status reason.

### Attach a local image

For `attached`, send `multipart/form-data`: place the JSON input in the `input` form field and attach the bytes in a field with the `name` from the reference. The original filename is stored with the generation, so prompts may refer to it. Filenames must be unique within the generation, cannot contain path separators, and cannot be `instructions.md`.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://app.moonlakeai.com/api/v1/assets \
    -H "Authorization: Bearer $MOONLAKE_API_KEY" \
    -F 'input={
      "prompt": "a red toy sports car with black wheels",
      "references": [{"source": "attached", "name": "reference_0"}]
    };type=application/json' \
    -F 'reference_0=@reference.png' \
    -F 'mode=generate'
  ```

  ```python python theme={null}
  import json
  import os

  import requests

  asset_input = {
      "prompt": "a red toy sports car with black wheels",
      "references": [{"source": "attached", "name": "reference_0"}],
  }
  with open("reference.png", "rb") as reference_file:
      response = requests.post(
          "https://app.moonlakeai.com/api/v1/assets",
          headers={"Authorization": f"Bearer {os.environ['MOONLAKE_API_KEY']}"},
          data={"input": json.dumps(asset_input), "mode": "generate"},
          files={"reference_0": reference_file},
      )
  generation = response.json()
  ```
</CodeGroup>

Each reference is capped at 50 MB. Images wider or taller than 3000 px are downscaled before generation. Base64 inflates a payload by about 33%, so prefer an attachment for larger files.

## Retry a create request safely

Send an `Idempotency-Key` header when a network failure might make you retry a create request. Reusing the same key with the same body returns the original generation instead of creating another one.

```bash curl theme={null}
curl -X POST https://app.moonlakeai.com/api/v1/assets \
  -H "Authorization: Bearer $MOONLAKE_API_KEY" \
  -H "Idempotency-Key: asset-request-2026-07-30-001" \
  -H "Content-Type: application/json" \
  -d '{"input": {"prompt": "wooden pallet", "references": [{"source": "url", "url": "https://your-public-host.example/pallet.png"}]}, "mode": "generate"}'
```

For the complete retry and failure contract, see [Behavior and limits](/reference/behavior-and-limits#idempotency).

## Resume a failed generation

If a generation fails, you can choose to resume it and pick up from where it stopped. Resuming creates a new generation and leaves the failed generation unchanged.

```bash curl theme={null}
curl -X POST https://app.moonlakeai.com/api/v1/assets/{asset_id}/resume \
  -H "Authorization: Bearer $MOONLAKE_API_KEY"
```

The resume requires enough credits and counts toward the concurrency limit. It returns `409` if the generation cannot be resumed or already has an active resume.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.