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

# Asset generation

> Kick off an AI 3D-generation job, poll it to completion, and read back its cached file and provenance — and understand why a bare server returns 'API key not configured' until you add a provider key.

Euca turns a text prompt into 3D content through `euca-asset`: you `POST /asset/generate` with a prompt and
a provider, get a `task_id`, and poll `/asset/status/{id}` until it's `complete` with a file on disk. Results
are **cached on disk by a provider+prompt hash** (identical prompts reuse the bake, keeping runs
deterministic) and carry a JSON provenance sidecar. The generated *appearance* is decoupled from the world's
[ground truth](/concepts/determinism) — an AI mesh changes how an entity looks, never its exact state, which
is what keeps Euca usable as a world-model [answer key](/evaluation/overview). The mental model to hold:
**generation calls an external provider API, so it needs a key and network** — without one, the job fails
immediately, and this page shows that real failure alongside the working shape.

## Kick off a job and poll it

First check which providers your server can actually use. `/asset/providers` returns exactly the **four
3D-model providers** the handler tracks, each with an `available` flag set by whether a key is configured:

```bash theme={null}
curl -s http://localhost:3917/asset/providers
# Bare server (no keys configured):
# {"providers":[{"available":false,"name":"tripo"},{"available":false,"name":"meshy"},
#               {"available":false,"name":"rodin"},{"available":false,"name":"hunyuan"}]}
```

Now start a job. `provider` defaults to `tripo`; `quality` is `low` / `medium` (default) / `high`:

```bash theme={null}
curl -s -X POST http://localhost:3917/asset/generate \
  -H 'Content-Type: application/json' \
  -d '{"prompt":"a mossy stone golem","provider":"tripo","quality":"high"}'
# Bare server (no key): {"error":"API key not configured","ok":false}
```

That `API key not configured` is the **real response from a server with no provider key** — the service
constructs the provider, fails its key check, and never queues a task. With a key present, the same call
returns a `task_id` to poll: `{"task_id":"gen_1","status":"pending"}`. You then poll until it's done:

```bash theme={null}
curl -s http://localhost:3917/asset/status/gen_1
# With a real, running task: {"task_id":"gen_1","status":"pending","progress":0.4}
#                       ...:  {"task_id":"gen_1","status":"complete","file_path":"assets/generated/gen_1.glb"}
```

`/asset/generated` lists every task the service knows about:

```bash theme={null}
curl -s http://localhost:3917/asset/generated
# Bare server (nothing was queued): []
```

Asking for the status of a task that doesn't exist returns a plain error — useful when you typo a `task_id`:

```bash theme={null}
curl -s http://localhost:3917/asset/status/gen_1
# {"error":"Invalid request: unknown task: gen_1","ok":false}
```

## Behavior and gotchas

The things you only find out by running it:

* **No keys → no jobs.** On a bare server, `/asset/generate` returns `{"error":"API key not
  configured","ok":false}` and `/asset/providers` shows all four as `"available":false`. Set the matching
  env var (`TRIPO_API_KEY`, `MESHY_API_KEY`, `RODIN_API_KEY`, `HUNYUAN_API_KEY`) on the host, and that
  provider flips to `available:true`. Some providers also need a paid plan.
* **`/asset/providers` lists four, not eight.** The endpoint reports only the 3D-*model* providers
  (`tripo`, `meshy`, `rodin`, `hunyuan`). The wider `euca-asset` taxonomy also covers heightmaps, skyboxes,
  PBR textures, and full scenes through other providers — but those aren't what this endpoint enumerates.
* **Generation is async — generate then poll.** `/asset/generate` returns a `task_id` immediately;
  `/asset/status/{id}` is what reports `progress`, the final `file_path`, or an `error`. An unknown id
  returns `unknown task: {id}`.
* **Caching is by provider+prompt hash.** Before calling a provider, the service hashes provider+prompt and
  checks `assets/generated/`; a hit returns the existing bake immediately, so identical prompts are
  deterministic and free.
* **Provenance ships with every asset** — a JSON sidecar records provider, prompt, quality, and timestamp.
* **Provider I/O runs off the simulation thread.** Handlers use `spawn_blocking` because the provider
  clients are blocking, so generation never stalls a tick.

## Endpoints

| Method | Path                      | Description                                                                    |
| ------ | ------------------------- | ------------------------------------------------------------------------------ |
| `POST` | `/asset/generate`         | Start a generation task (`prompt`, `provider`, `quality`); returns a `task_id` |
| `GET`  | `/asset/status/{task_id}` | Poll a task — `progress`, `file_path`, or `error`                              |
| `GET`  | `/asset/generated`        | List all known tasks with prompt and status                                    |
| `GET`  | `/asset/providers`        | The four 3D-model providers and whether each has a key                         |

## Status

* **Shipped** — the four-provider 3D-model pipeline (plus heightmap/skybox/texture/scene providers in the
  crate), task lifecycle, prompt-hash caching, provenance sidecars, and offline baking.
* **Requires** — a provider API key and network access; no key ships by default, and some providers need a
  paid plan. Generated appearance never touches ground truth.

<Card title="Asset endpoints" icon="cube" href="/api-reference/introduction" horizontal>
  Generate, status, list, and providers endpoints, with request and response schemas.
</Card>
