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.
Available on Nodaro Cloud
Character training creates a dedicated model of one character from its images, for the closest likeness in 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. The routes take a bearer token and act only on your own characters. See Authentication.
The SDK wraps the routes as client.characters.train, trainingStatus and deleteLora. In the CLI, use nodaro characters train, training and delete-lora. An AI assistant connected over MCP starts a training with train_character and follows it on get_character. Removing a trained model is not an MCP tool.
With an OAuth app token, starting a training and removing a trained model need assets:write, the same scope as creating or deleting the character. Without it they answer 403 insufficient_scope before anything is reserved. The status read needs no scope. A session or a personal API token needs no scope.
Endpoints
| Method | Path | What it does |
|---|---|---|
POST | /v1/characters/:id/train | Start a training. Reserves 1,650 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. By default, Nodaro collects them from the character, in this order, removes duplicates, and trains on up to 20:
- The approved portrait.
- The reference photos.
- The expressions, the poses, the head angles and the body angles.
- The lighting variants.
To train on a subset, send { "selectedImageUrls": [...] } in the body: up to 200 URLs of the character's own images. The training then uses only those, and at least 4 must remain. An omitted or empty list means every eligible image.
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.
Start a training
POST /v1/characters/:id/train reserves 1,650 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 -X POST https://app.nodaro.ai/v1/characters/3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94/train \
-H "Authorization: Bearer $NODARO_API_KEY"
# Or train on a subset of the character's images
curl -X POST https://app.nodaro.ai/v1/characters/3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94/train \
-H "Authorization: Bearer $NODARO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"selectedImageUrls": ["https://cdn.nodaro.ai/characters/kira-portrait.png", "https://cdn.nodaro.ai/characters/kira-smile.png", "https://cdn.nodaro.ai/characters/kira-left.png", "https://cdn.nodaro.ai/characters/kira-right.png"]}'import { createClient, StaticTokenAuth } from '@nodaro/sdk'
const client = createClient({
baseUrl: 'https://app.nodaro.ai',
auth: new StaticTokenAuth(process.env.NODARO_API_KEY!),
})
const training = await client.characters.train(characterId)
// Or a subset: client.characters.train(characterId, { selectedImageUrls: [...] }){
"jobId": "7a9c1e3b-5d2f-4b8a-9c6e-1f3d5b7a9c2e",
"trainingId": "q4m8x2k6p1",
"triggerWord": "TOK_kira_a1b2c3"
}The training's job, jobId, ends completed, failed or cancelled with the training, so you can also follow it with GET /v1/jobs/:id/status.
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 10 seconds or so. The SDK has no wait helper.
curl https://app.nodaro.ai/v1/characters/3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94/training \
-H "Authorization: Bearer $NODARO_API_KEY"let training = await client.characters.trainingStatus(characterId)
while (training.status === 'queued' || training.status === 'training') {
await new Promise((resolve) => setTimeout(resolve, 10_000))
training = await client.characters.trainingStatus(characterId)
}
if (training.status !== 'succeeded') console.warn(training.status, training.error){
"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. untrained means never trained, the model was removed, or a training could not be started. |
trainingId | The current or last training, or null. |
error | Why the training failed, or null. |
trainedAt | When the last successful training finished, or null. |
version | The last successful training's model version, or null. |
triggerWord | The word that calls up the character in the trained model, or null. |
imageCount | How many images the latest training used, or null. |
Generation uses the trained model only while status is succeeded. trainedAt and version stay set through a re-training, a failed or cancelled one, or one that could not be started, but the model is not used in any of those states. A character that is not yours, or is archived, answers 404 not_found.
Generate images with the trained model
Once the status is succeeded, run 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. - 22 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 and the video nodes, keep using the character's reference images.
See Run a single node for the Generate Image request, and 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,650 credits every time and replaces the previous model.
- Remove.
DELETE /v1/characters/:id/loracancels a training in progress and refunds its credits, deletes the trained model, and clears the character's training fields. The status then readsuntrained. It returns{ ok: true }, and it cannot be undone. 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.
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,650, refunded when the training fails or is cancelled. |
| A re-training | 1,650 every time. |
| An image from the trained model | 22 per image, instead of the selected model's price. |
See Credits for balances and transactions.
Errors
| Status | Code | Meaning |
|---|---|---|
400 | insufficient_training_images | The character has fewer than 4 different images. The answer's count and message say how many it has. Add angles or expressions and try again. |
400 | — | A malformed id or selectedImageUrls. The body is { "message", "issues": [...] }. |
401 | unauthorized | The token is missing, invalid or revoked. |
402 | insufficient_credits | The account cannot cover the 1,650 credits. required and balance are in the answer. |
403 | insufficient_scope | An OAuth app token without assets:write. |
404 | not_found | No such character belongs to you, the character is archived, 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 or is archived. |
422 | job_blocked | The deployment's job policy refused the training. |
429 | — | More than 3 training starts in a minute from this token. |
500 | claim_failed | The training could not be claimed. Nothing started: retry. |
502 | training_dispatch_failed | The training could not be started. The credits are refunded, and the status reads untrained. |
503 | public_url_not_configured, price_not_configured | Training is not configured on this instance. |
503 | dedup_race_winner_unresolvable | A duplicate of the request was in flight and its outcome could not be read. This request reserved nothing: read the status before you retry. |
The refusals these routes write themselves use an older body shape: the code is a bare string, { "error": "<code>" }, sometimes with a top-level message. The scope, credit, rate-limit and job-policy refusals use the usual { "error": { "code", "message" } } envelope. The SDK reads both shapes into NodaroError.code and .message.
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,650 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 22 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.
Related
Character training
Characters
Generate Image
Consistent characters
Credits
Last updated on
Content rights
Before Nodaro imports a video link, the person confirms a content rights declaration. Read it, confirm it per link, or authorize keys and agents once.
3D scenes
Generate, edit and render editable 3D clay scenes over REST, quote and run 3D Render Pro, and read scene revisions, assets and deliveries.