NodaroAccount
Nodaro Docs
DocumentationNode ReferenceModelsTemplatesAI Agents (MCP)DevelopersSelf-hostingResearchCompare
REST API

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

MethodPathWhat it does
POST/v1/characters/:id/trainStart a training. Reserves 1,650 credits.
GET/v1/characters/:id/trainingGet the training status.
DELETE/v1/characters/:id/loraCancel 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:

  1. The approved portrait.
  2. The reference photos.
  3. The expressions, the poses, the head angles and the body angles.
  4. 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
}
FieldWhat it holds
statusuntrained, queued, training, succeeded, failed or cancelled. untrained means never trained, the model was removed, or a training could not be started.
trainingIdThe current or last training, or null.
errorWhy the training failed, or null.
trainedAtWhen the last successful training finished, or null.
versionThe last successful training's model version, or null.
triggerWordThe word that calls up the character in the trained model, or null.
imageCountHow 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/lora cancels a training in progress and refunds its credits, deletes the trained model, and clears the character's training fields. The status then reads untrained. 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

ActionCredits
A training1,650, refunded when the training fails or is cancelled.
A re-training1,650 every time.
An image from the trained model22 per image, instead of the selected model's price.

See Credits for balances and transactions.

Errors

StatusCodeMeaning
400insufficient_training_imagesThe 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": [...] }.
401unauthorizedThe token is missing, invalid or revoked.
402insufficient_creditsThe account cannot cover the 1,650 credits. required and balance are in the answer.
403insufficient_scopeAn OAuth app token without assets:write.
404not_foundNo such character belongs to you, the character is archived, or the instance is not Nodaro Cloud.
409already_training_or_not_foundA training is already queued or running for this character, or the character is not yours or is archived.
422job_blockedThe deployment's job policy refused the training.
429—More than 3 training starts in a minute from this token.
500claim_failedThe training could not be claimed. Nothing started: retry.
502training_dispatch_failedThe training could not be started. The credits are refunded, and the status reads untrained.
503public_url_not_configured, price_not_configuredTraining is not configured on this instance.
503dedup_race_winner_unresolvableA 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.

Last updated on

On this page