# Character training

> Train a high-fidelity model on a character over REST, poll the training, remove the model, and learn when Generate Image uses the trained model.

Source: https://nodaro.ai/docs/developers/api/character-training

**Character training** creates a dedicated model of one character from its images, for the closest likeness in [Generate Image](https://nodaro.ai/docs/nodes/image/generate-image). You start a training with one call, poll it until it finishes, and remove the model when you no longer need it. After training, Generate Image uses the trained model automatically whenever a prompt mentions that character.

Character training runs on Nodaro Cloud only; on self-hosted installs the routes do not exist and answer `404`. On a self-hosted install, keep a character consistent with its approved portrait and reference images, as described in [Characters](https://nodaro.ai/docs/developers/api/characters). The routes take a bearer token and act only on your own characters. See [Authentication](https://nodaro.ai/docs/developers/api/authentication).

## Endpoints

| Method | Path | What it does |
| --- | --- | --- |
| `POST` | `/v1/characters/:id/train` | Start a training. Reserves 1,500 credits. |
| `GET` | `/v1/characters/:id/training` | Get the training status. |
| `DELETE` | `/v1/characters/:id/lora` | Cancel a training in progress, or remove the trained model. |

## Before you train

The character needs at least **4 different images**. Nodaro collects them from the character, in this order, removes duplicates, and trains on up to 20:

1. The approved portrait.
2. The reference photos.
3. The expressions, the poses, the head angles and the body angles.
4. The lighting variants.

Character sheets do not count, because their views repeat the angles. When a character has fewer than 4 images, generate a few angles and expressions first with `POST /v1/generate-character-asset`; see [Characters](https://nodaro.ai/docs/developers/api/characters#generate-an-expression-angle-pose-or-lighting-variant).

## Start a training

`POST /v1/characters/:id/train` reserves 1,500 credits and starts the training. It answers `202` with the training's job id, its id and the character's trigger word. You never need to type the trigger word: Nodaro adds it to prompts for you.

**curl**

```bash
curl -X POST https://app.nodaro.ai/v1/characters/3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94/train \
  -H "Authorization: Bearer $NODARO_API_KEY"
```

**TypeScript SDK**

```ts

const client = createClient({
baseUrl: 'https://app.nodaro.ai',
auth: new StaticTokenAuth(process.env.NODARO_API_KEY!),
})

// The SDK has no training methods yet; its generic request method calls the route.
const training = await client.request('POST', `/v1/characters/${characterId}/train`)
```

```json
{
"jobId": "7a9c1e3b-5d2f-4b8a-9c6e-1f3d5b7a9c2e",
"trainingId": "q4m8x2k6p1",
"triggerWord": "TOK_kira_a1b2c3"
}
```

A double click is safe: while a training is queued or running, another start answers `409 already_training_or_not_found` and reserves nothing. Each token may start 3 trainings per minute.

## Follow the training

`GET /v1/characters/:id/training` returns the training's state. A training takes about 15 minutes. Poll every few seconds; the editor polls every 8 seconds.

**curl**

```bash
curl https://app.nodaro.ai/v1/characters/3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94/training \
  -H "Authorization: Bearer $NODARO_API_KEY"
```

**TypeScript SDK**

```ts
type Training = { status: string; error: string | null; triggerWord: string | null }

const path = `/v1/characters/${characterId}/training`
let state = await client.request<Training>('GET', path)
while (state.status === 'queued' || state.status === 'training') {
await new Promise((resolve) => setTimeout(resolve, 8000))
state = await client.request<Training>('GET', path)
}
```

```json
{
"status": "succeeded",
"trainingId": "q4m8x2k6p1",
"error": null,
"trainedAt": "2026-09-20T11:42:08Z",
"version": "b81f4c0e9d27",
"triggerWord": "TOK_kira_a1b2c3",
"imageCount": 12
}
```

| Field | What it holds |
| --- | --- |
| `status` | `untrained`, `queued`, `training`, `succeeded`, `failed` or `cancelled`. |
| `trainingId` | The current or last training, or `null`. |
| `error` | Why the training failed, or `null`. |
| `trainedAt` | When the model finished training, or `null`. |
| `version` | The trained model's version, or `null`. |
| `triggerWord` | The word that calls up the character in the trained model, or `null`. |
| `imageCount` | How many images the model was trained on, or `null`. |

## Generate images with the trained model

Once the status is `succeeded`, run [Generate Image](https://nodaro.ai/docs/nodes/image/generate-image) with a prompt that mentions exactly one trained character with `@`, and with that character wired into the node. Nodaro then uses the trained model instead of the selected model and the reference images:

- **Automatic.** The trigger word is put at the start of the prompt for you, and your `@` mentions are removed from the text.
- **20 credits per image.** The trained model's price replaces the selected model's price.
- **One trained character at a time.** When the prompt mentions two or more trained characters, Generate Image falls back to the selected model with reference images.
- **Generate Image only.** Other nodes, such as [Modify Image](https://nodaro.ai/docs/nodes/image/modify-image) and the video nodes, keep using the character's reference images.

See [Run a single node](https://nodaro.ai/docs/developers/api/nodes) for the Generate Image request, and [Character training](https://nodaro.ai/docs/guides/character-training) for the same feature in the editor.

## Re-train or remove the model

- **Re-train.** Start a training again at any time after one has succeeded, failed or been cancelled. It costs 1,500 credits every time and replaces the previous model.
- **Remove.** `DELETE /v1/characters/:id/lora` cancels a training in progress and refunds its credits, deletes the trained model, and clears the character's training fields. It returns `{ ok: true }`. Generations go back to reference images.
- **Archive the character.** Archiving the character also cancels a training in progress, refunds its credits and deletes the trained model.

```bash
curl -X DELETE https://app.nodaro.ai/v1/characters/3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94/lora \
  -H "Authorization: Bearer $NODARO_API_KEY"
```

## Credits

| Action | Credits |
| --- | --- |
| A training | 1,500, refunded when the training fails or is cancelled. |
| A re-training | 1,500 every time. |
| An image from the trained model | 20 per image, instead of the selected model's price. |

See [Credits](https://nodaro.ai/docs/developers/api/credits) for balances and transactions.

## Errors

| Status | Code | Meaning |
| --- | --- | --- |
| `400` | `insufficient_training_images` | The character has fewer than 4 different images. Add angles or expressions and try again. |
| `401` | `unauthorized` | The token is missing, invalid or revoked. |
| `402` | `insufficient_credits` | The account cannot cover the 1,500 credits. |
| `404` | `not_found` | No such character belongs to you, or the instance is not Nodaro Cloud. |
| `409` | `already_training_or_not_found` | A training is already queued or running for this character, or the character is not yours. |
| `429` | — | More than 3 training starts in a minute from this token. |
| `502` | `training_dispatch_failed` | The training service refused the request. The credits are refunded. |
| `503` | `public_url_not_configured`, `webhook_not_configured` | Training is not configured on this instance. |

## Frequently asked questions

### How many photos does character training need?

At least 4 different images of the character, across its approved portrait, reference photos, expressions, poses, angles and lighting variants. Nodaro trains on up to 20 of them. Character sheets do not count.

### How much does character training cost?

A training costs 1,500 credits, and so does every re-training. The credits are refunded when a training fails or is cancelled. Each image generated with the trained model then costs 20 credits.

### How long does a training take?

About 15 minutes. Poll GET /v1/characters/:id/training every few seconds until the status is succeeded, failed or cancelled.

### When does Generate Image use the trained model?

When the prompt mentions exactly one trained character with @ and that character is wired into the Generate Image node. With two or more trained characters, the node uses the selected model with reference images instead.

### Can I train a character on a self-hosted install?

No. Character training runs on Nodaro Cloud only, and the routes do not exist on self-hosted installs. There, keep a character consistent with its approved portrait and reference images.
