---
name: layer-train-custom-style
description: Train a custom style (LoRA) on Layer from a studio's own artwork, then generate new assets in that style. Use when asked to make a model match an existing art direction, teach Layer a character, object, scene, or visual effect, or turn a folder of reference images into a reusable style.
---

# Train a custom style on Layer

A **reference set** is a named group of files plus a training category. Training one produces a
LoRA that later generations apply by id, so a studio's art direction becomes a parameter rather
than a prompt-engineering exercise.

## 1. Upload the artwork

For each reference image, `POST /v2/workspaces/{workspace_id}/files/upload-url` with
`content_type` and `file_size_bytes`, `POST` to the returned `upload_url` with
`x-goog-resumable: start` to get a session URI, then `PUT` the bytes there. Keep each `file_id`.
PNG, JPEG, and WebP are accepted, up to 64 MB each.

## 2. Create the reference set

`POST /v2/workspaces/{workspace_id}/reference-sets`:

```json
{
  "name": "Ashfall — hand-painted props",
  "category": "object",
  "file_ids": ["…", "…"],
  "description": "Prop concept art from the Ashfall style bible",
  "cover_file_ids": ["…"]
}
```

`category` picks what the training is meant to learn, and it matters more than the name:

| Category | Learns |
| --- | --- |
| `general` | Overall aesthetic |
| `character` | A person or creature |
| `object` | A specific item |
| `scene` | An environment |
| `effect` | A visual effect |

## 3. Estimate, then start

`POST /v2/workspaces/{workspace_id}/training-runs/estimate` prices the run for free and returns
`has_sufficient_creative_units`. Check it, then:

```json
POST /v2/workspaces/{workspace_id}/training-runs
{ "reference_set_id": "…" }
```

`base_model_id` is optional — omit it to use the reference set's configured model or the
workspace default. `training_framework` (`fal` or `ai-toolkit`) is an override; omit it for the
server default.

## 4. Poll to completion

`GET /v2/workspaces/{workspace_id}/training-runs/{training_run_id}` on the returned
`poll_interval_seconds`. `state` is `in_progress`, `terminal_success`, or `terminal_failure`;
`progress` and `eta_at` tell you how far along it is. There are no webhooks — poll.

Cancel with `POST /v2/workspaces/{workspace_id}/training-runs/{training_run_id}/cancel`.
Fetch the result with `GET /v2/workspaces/{workspace_id}/training-runs/{training_run_id}/model`.
List past runs with `GET /v2/workspaces/{workspace_id}/training-runs`.

## 5. Generate in the trained style

Pass the reference set to any generation:

```json
POST /v2/workspaces/{workspace_id}/inferences
{
  "prompt": "a weathered signpost at a crossroads",
  "reference_sets": [{ "set_id": "…", "weight": 1 }]
}
```

`weight` (0–2, default 1) scales the LoRA adapter. It is ignored for sets applied as reference
images or as prompt text rather than as an adapter. Watch `reference_sets_degraded` and
`reference_sets_warning` on the response: they say when a set could not be applied as intended.

## Over MCP

The creative server covers the whole flow: `upload_file`, `create_reference_set`,
`list_reference_sets`, `get_reference_set`, `estimate_training_price`, `start_training`,
`get_training_status`, `list_training_runs`, `get_trained_model`, `cancel_training_run`.

## Reference

- REST reference: <https://layer.ai/docs/v2/rest-api>
- Creative Unit costs: <https://layer.ai/pricing.json>
