# Personagens

> Crie, atualize, arquive e restaure personagens via REST, gere candidatos a retrato, expressões, ângulos e clipes de movimento e aprove o retrato-âncora.

Source: https://nodaro.ai/pt-BR/docs/developers/api/characters

A **API de personagens** automatiza tudo o que o Estúdio de personagens faz. Você cria um personagem, gera candidatos a retrato, aprova um deles como retrato-âncora e adiciona expressões, ângulos, poses, variações de iluminação e clipes de movimento. Os nós de imagem e de vídeo então reaproveitam o personagem, para que a mesma pessoa tenha a mesma aparência em todas as tomadas.

As rotas funcionam em todas as edições. Elas aceitam um token Bearer: um token de API pessoal (`ndr_…`), um token de app OAuth (`ndr_app_…`) ou o token da sua sessão na Community Edition. Toda rota se limita a quem chama: você só vê e altera os seus próprios personagens. Veja [Autenticação](https://nodaro.ai/docs/developers/api/authentication).

## Endpoints
| Método | Caminho | O que faz |
| --- | --- | --- |
| `GET` | `/v1/characters` | Lista os seus personagens, uma página por vez. |
| `GET` | `/v1/characters/:id` | Retorna um personagem com os jobs dele em andamento. |
| `POST` | `/v1/characters` | Cria um personagem, ou atualiza um quando o corpo tem um `id`. |
| `POST` | `/v1/characters/:id/duplicate` | Copia um personagem para um novo, com o sufixo `(copy)` no nome. |
| `DELETE` | `/v1/characters/:id` | Arquiva um personagem. Ele pode ser restaurado. |
| `POST` | `/v1/characters/:id/restore` | Restaura um personagem arquivado. |
| `GET` | `/v1/characters/:id/usage` | Conta e lista os workflows que usam o personagem. |
| `POST` | `/v1/generate-character` | Gera de 1 a 10 candidatos a retrato. |
| `POST` | `/v1/generate-character-asset` | Gera uma expressão, pose, ângulo ou variação de iluminação. |
| `POST` | `/v1/generate-character-motion` | Anima o personagem em um clipe de movimento. |
| `POST` | `/v1/characters/:id/approve-portrait` | Aprova um candidato como retrato e escreve a descrição do personagem. |
| `POST` | `/v1/characters/:id/llm-caption` | Escreve a descrição de novo a partir do retrato atual. |

Treinar um modelo dedicado com um personagem é um recurso do Nodaro Cloud com rotas próprias. Veja [Treinamento de personagem](https://nodaro.ai/docs/developers/api/character-training).

## O que um personagem contém
Um personagem é uma identidade salva. Os campos abaixo voltam de `GET /v1/characters/:id` em camelCase.

| Campo | O que contém |
| --- | --- |
| `id`, `name` | O identificador e o nome de exibição. Os nomes são únicos por conta, sem diferenciar maiúsculas de minúsculas. |
| `description`, `gender`, `style`, `baseOutfit` | Notas de identidade que moldam todas as imagens geradas do personagem. |
| `seedPrompt` | Um prompt curto que enquadra o retrato, com até 4.000 caracteres. |
| `sourceImageUrl` | O retrato-âncora. É definido quando você aprova um candidato. |
| `canonicalDescription` | Uma descrição visual de cerca de 80 a 120 palavras, escrita pelo Nodaro quando o retrato é aprovado. Os prompts que fazem referência ao personagem a incluem. |
| `expressions`, `poses`, `angles`, `bodyAngles`, `lightingVariations`, `motions` | Os grupos de mídias. Cada entrada é `{ name, url }`. |
| `referencePhotos` | Até 20 fotos reais, cada uma marcada com o enquadramento. |
| `realLifeRefsByVariant`, `referenceVideosByVariant` | Fotos ou clipes de referência extras para uma variação, por exemplo a expressão `smile`. |
| `person`, `wardrobe` | Escolhas estruturadas de aparência e de figurino, definidas na página Seletores do Estúdio de personagens. |
| `voice`, `personality` | A voz e a personalidade do personagem. |
| `identityLock` | Com que rigor as mídias geradas mantêm o rosto: `off`, `soft` ou `strict`. O padrão é `off`. |
| `deletedAt` | Definido quando o personagem é arquivado. |

### Os grupos de mídias
Cada grupo guarda variações do retrato-âncora. Você pode dar qualquer nome a uma variação; estes são os nomes predefinidos.

| Grupo | O que mostra | Variações predefinidas |
| --- | --- | --- |
| `expressions` | Cabeça e ombros, com outra emoção | neutral, smile, angry, surprised, sad, talking, laughing, disgusted, fearful, smirk, crying |
| `angles` | Cabeça e ombros de outro ângulo de câmera | front, 3/4 left, left profile, right profile, 3/4 right |
| `bodyAngles` | Corpo inteiro de outro ângulo, com os braços relaxados | front, 3/4 left, left profile, right profile, 3/4 right, back |
| `poses` | Corpo inteiro em outra postura | standing, walking, sitting, running, crouching, pointing, fighting stance, jumping, turning |
| `lightingVariations` | A mesma pose sob outra luz | daylight, night, dramatic |
| `motions` | Clipes de vídeo do personagem em movimento | Qualquer rótulo, por exemplo walking ou head turn |

## Listar personagens
`GET /v1/characters` retorna uma página dos seus personagens, dos mais recentes para os mais antigos. Continue pedindo páginas até `nextCursor` ser `null`: uma única resposta nunca traz “todos os personagens” de uma conta que passa do tamanho da página.

| Parâmetro de consulta | O que faz |
| --- | --- |
| `limit` | Linhas por página. O padrão é 100 e o máximo é 500. |
| `cursor` | O `nextCursor` da página anterior. |
| `projectId` | Só os personagens de um projeto. |
| `archived` | `true` lista os personagens arquivados em vez dos ativos. |

**curl**

```bash
CURSOR=""
while :; do
PAGE=$(curl -s "https://app.nodaro.ai/v1/characters?limit=100${CURSOR:+&cursor=$CURSOR}" \
    -H "Authorization: Bearer $NODARO_API_KEY")
echo "$PAGE" | jq -r '.characters[] | "\(.id) \(.name)"'
CURSOR=$(echo "$PAGE" | jq -r '.nextCursor // empty')
[ -z "$CURSOR" ] && break
done
```

**TypeScript SDK**

```ts

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

const all = []
let cursor: string | undefined
do {
const page = await client.characters.list({ limit: 100, cursor })
all.push(...page.characters)
cursor = page.nextCursor ?? undefined
} while (cursor)
```

**CLI**

```bash
nodaro characters list --limit 100 --json
nodaro characters list --archived
```

```json
{
"characters": [
{
"id": "3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94",
"name": "Kira",
"description": "young protagonist with auburn hair",
"sourceImageUrl": "https://cdn.nodaro.ai/characters/kira-portrait.png",
"expressions": [{ "name": "smile", "url": "https://cdn.nodaro.ai/characters/kira-smile.png" }]
}
],
"nextCursor": "eyJjcmVhdGVkQXQiOiIyMDI2LTA5LTIwVDEwOjAwOjAxWiJ9"
}
```

O cursor é opaco. Envie de volta apenas um `nextCursor` que o servidor deu a você, e nunca guarde um cursor de uma versão para outra. Um cursor malformado gera `400 validation_error`, não uma volta silenciosa para a primeira página. Os personagens criados enquanto você pagina não são incluídos; comece de novo sem cursor para vê-los.

## Criar ou atualizar um personagem
`POST /v1/characters` cria um personagem quando o corpo não tem `id` e atualiza o personagem quando tem. Uma criação precisa de `nodeId` e `name`. `nodeId` vincula o personagem a um nó do canvas; use qualquer rótulo, como `"scripted"`, quando criar o personagem por código.

Em uma atualização, só os campos que você envia são gravados. Os campos omitidos mantêm os valores, então um salvamento nunca sobrescreve grupos de mídias que um job em execução está preenchendo. Envie um grupo de mídias só quando quiser substituí-lo.

**curl**

```bash
curl -X POST https://app.nodaro.ai/v1/characters \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
"nodeId": "scripted",
"name": "Kira",
"description": "young protagonist with auburn hair",
"style": "realistic",
"seedPrompt": "kira portrait, warm natural lighting"
}'
```

**TypeScript SDK**

```ts
const { id } = await client.characters.create({
nodeId: 'scripted',
name: 'Kira',
description: 'young protagonist with auburn hair',
style: 'realistic',
seedPrompt: 'kira portrait, warm natural lighting',
})

await client.characters.update(id, { gender: 'female', identityLock: 'soft' })
```

**CLI**

```bash
nodaro characters create --name "Kira" \
  --description "young protagonist with auburn hair" \
  --style realistic --seed-prompt "kira portrait, warm natural lighting"

nodaro characters update <id> --gender female
```

```json
{ "id": "3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94", "name": "Kira" }
```

<TypeTable
type={{
id: { type: 'string (uuid)', description: 'O personagem a atualizar. Omita para criar um personagem.' },
nodeId: { type: 'string', description: 'Obrigatório na criação. O nó do canvas ao qual o personagem pertence, ou qualquer rótulo quando não há nenhum.' },
name: { type: 'string', description: 'Obrigatório na criação. De 1 a 200 caracteres. Um nome já usado por outro personagem ativo retorna 409 name_taken.' },
description: { type: 'string', description: 'Notas de identidade, com até 2.000 caracteres.' },
gender: { type: 'string', description: 'Até 50 caracteres.' },
style: { type: 'string', description: 'O estilo visual, por exemplo realistic, anime, 3d-pixar ou illustration.' },
baseOutfit: { type: 'string', description: 'O figurino padrão, com até 1.000 caracteres.' },
seedPrompt: { type: 'string', description: 'Um prompt curto que enquadra o retrato, com até 4.000 caracteres. Um valor mais longo retorna 400.' },
identityLock: { type: "'off' | 'soft' | 'strict'", description: 'Com que rigor as mídias geradas mantêm o rosto.', default: 'off' },
referencePhotos: { type: 'array', description: 'Até 20 fotos { url, kind }. kind é frontFace, sideLeft, sideRight, threeQuarterLeft, threeQuarterRight, frontBody ou other. Cada kind, exceto other, pode aparecer uma vez.' },
realLifeRefsByVariant: { type: 'object', description: 'URLs de fotos de referência por variação, por exemplo { "smile": [url] }. Até 20 chaves e 5 URLs por chave. As chaves perdem os espaços das pontas e são convertidas para minúsculas.' },
referenceVideosByVariant: { type: 'object', description: 'URLs de clipes de referência por rótulo, com os mesmos limites. Leia esses valores de volta para preencher referenceVideoUrls no Gerar vídeo.' },
person: { type: 'object', description: "Escolhas estruturadas de aparência (cabelo, olhos, porte físico, idade e mais). São adicionadas aos prompts do retrato e das mídias do próprio personagem." },
wardrobe: { type: 'object', description: 'Escolhas estruturadas de figurino (parte de cima, parte de baixo, calçados, paleta, época e mais). São adicionadas aos mesmos prompts.' },
voice: { type: 'object | null', description: 'A voz: { voiceId, voiceName, traits, voiceType?, ttsProvider? }. Envie null para limpar.' },
personality: { type: 'object | null', description: '{ mood, speechStyle, movementStyle, behavioralNotes }.' },
canonicalDescription: { type: 'string', description: 'Substitui a descrição escrita, com até 4.000 caracteres.' },
projectId: { type: 'string (uuid)', description: 'O projeto em que o personagem fica guardado.' },
}}
/>

`person` e `wardrobe` moldam só as gerações do retrato e das mídias do próprio personagem. Eles usam os mesmos catálogos do seletor [**Pessoa** (Person)](https://nodaro.ai/docs/nodes/creative-controls/person). Veja [Catálogos de seletores](https://nodaro.ai/docs/developers/picker-catalogs).

Quando um workflow é executado, a `voice` do personagem preenche qualquer nó [**Texto para fala** (Text to Speech)](https://nodaro.ai/docs/nodes/audio/text-to-speech) conectado depois do personagem: a voz, o tipo de voz e o modelo recomendado. Um valor definido no próprio nó Texto para fala tem prioridade.

## Gerar candidatos a retrato
`POST /v1/generate-character` inicia um job por candidato e retorna os IDs deles na hora. Consulte cada job periodicamente com a [API de jobs](https://nodaro.ai/docs/developers/api/jobs) até ele estar `completed`.

Com `attachToCharacterId`, o primeiro candidato a terminar vira o retrato do personagem. Para um único candidato, isso é tudo de que você precisa. Para vários candidatos, aprove o que preferir; a aprovação substitui o retrato.

**curl**

```bash
curl -X POST https://app.nodaro.ai/v1/generate-character \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
"name": "Kira",
"seedPrompt": "kira portrait, warm natural lighting",
"count": 4,
"attachToCharacterId": "3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94"
}'
```

**TypeScript SDK**

```ts
const { jobIds } = await client.characters.generate({
name: 'Kira',
seedPrompt: 'kira portrait, warm natural lighting',
count: 4,
attachToCharacterId: id,
})
```

**CLI**

```bash
nodaro characters generate <id> --count 4 \
  --seed-prompt "kira portrait, warm natural lighting" --watch
```

```json
{
"jobId": "a1c4e8f2-5b3d-4e6a-8f7c-2d9b1e0a3c5f",
"jobIds": [
"a1c4e8f2-5b3d-4e6a-8f7c-2d9b1e0a3c5f",
"b7d2f9a1-6c4e-4a8b-9d3f-3e0c2f1b4d6a",
"c3e5a7b9-8d1f-4c2e-a6b8-4f1d3a2c5e7b",
"d9f1b3c5-2e4a-4d6f-b8c1-5a2e4b3d6f8c"
]
}
```

<TypeTable
type={{
name: { type: 'string', description: 'O nome do personagem, de 1 a 200 caracteres.', required: true },
seedPrompt: { type: 'string', description: 'O prompt do retrato. Envie seedPrompt, description ou referencePhotos, ou anexe a um personagem que tenha uma descrição.' },
description: { type: 'string', description: 'Notas de identidade, com até 2.000 caracteres.' },
referencePhotos: { type: 'array', description: 'Até 20 fotos { url, kind } para montar o retrato.' },
gender: { type: 'string', description: 'Até 50 caracteres.' },
style: { type: 'string', description: 'O estilo visual.' },
baseOutfit: { type: 'string', description: 'Até 1.000 caracteres.' },
count: { type: 'integer', description: 'Candidatos a gerar, de 1 a 10.', default: '1' },
provider: { type: 'string', description: 'O ID do modelo de imagem. Omita para usar o modelo padrão.' },
quality: { type: "'basic' | 'medium' | 'high'", description: 'Um nível de qualidade, nos modelos que têm um. Muda o preço.' },
resolution: { type: 'string', description: '1K, 2K, 4K, 0.5 MP, 1 MP, 2 MP ou 4 MP, nos modelos que oferecem essa opção. Muda o preço.' },
aspectRatio: { type: "'1:1' | '3:4' | '16:9' | '9:16'", description: 'O quadro do retrato.', default: '3:4' },
sourceImageUrl: { type: 'string', description: 'Uma imagem para usar como ponto de partida.' },
attachToCharacterId: { type: 'string (uuid)', description: 'O personagem que recebe o resultado como retrato.' },
}}
/>

`quality` e `resolution` definem o preço do job exatamente como no [**Gerar imagem** (Generate Image)](https://nodaro.ai/docs/nodes/image/generate-image): uma execução em 4K ou de alta qualidade custa mais que o mesmo modelo no nível básico. Um valor que o modelo não aceita é trocado pelo mais próximo que ele aceita, nunca recusado, e os créditos seguem o valor trocado. Essas rotas não retornam uma lista `adjustments`; leia o valor que foi executado no `input_data` do job, em `GET /v1/jobs/:id`.

## Gerar uma variação de expressão, ângulo, pose ou iluminação
`POST /v1/generate-character-asset` gera uma variação do retrato-âncora e retorna `{ jobId }`. Para adicionar o resultado ao personagem, envie os três campos de anexo: `attachToCharacterId`, `attachToColumn` e `attachName`. Quando o job termina, o worker acrescenta `{ name: attachName, url }` a esse grupo.

**curl**

```bash
curl -X POST https://app.nodaro.ai/v1/generate-character-asset \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
"name": "Kira",
"assetType": "expressions",
"variant": "smile",
"attachToCharacterId": "3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94",
"attachToColumn": "expressions",
"attachName": "smile"
}'
```

**TypeScript SDK**

```ts
await client.characters.generateAsset({
name: 'Kira',
assetType: 'bodyAngles',
variant: 'front',
attachToCharacterId: id,
attachToColumn: 'body_angles',
attachName: 'front',
})
```

**CLI**

```bash
nodaro characters generate-asset <id> --asset-type expressions --variant smile --watch
```

| Campo | O que faz |
| --- | --- |
| `name` | Obrigatório. O nome do personagem. |
| `assetType` | Obrigatório. `expressions`, `poses`, `lighting`, `headAngles`, `angles` (igual a `headAngles`), `bodyAngles` ou `custom`. |
| `variant` | Obrigatório. A variação a gerar, de 1 a 100 caracteres, por exemplo `smile` ou `3/4 left`. |
| `description` | Uma descrição de uma frase desta variação, com até 1.000 caracteres. Quando você anexa a um personagem e omite este campo, o Nodaro rascunha uma a partir da descrição canônica do personagem. |
| `sourceImageUrl` | A imagem a variar, normalmente o retrato aprovado. |
| `provider`, `quality`, `resolution` | O modelo de imagem e o nível de saída dele, com preço igual ao do Gerar imagem. |
| `aspectRatio` | `1:1`, `3:4`, `16:9` ou `9:16`. O padrão depende do tipo: `1:1` para expressões, `9:16` para poses e ângulos do corpo e `3:4` para os demais. |
| `attachToCharacterId`, `attachToColumn`, `attachName` | Para onde vai o resultado. `attachToColumn` é `expressions`, `poses`, `angles`, `body_angles` ou `lighting_variations`. Uma variação `custom` precisa indicar a coluna. |

Quando você anexa a variação a um personagem, as fotos reais salvas na chave da variação em `realLifeRefsByVariant` são enviadas com a requisição automaticamente.

## Animar o personagem
`POST /v1/generate-character-motion` transforma uma imagem fixa do personagem em um clipe de vídeo e retorna `{ jobId }`. Com `attachToCharacterId` e `attachName`, o clipe é acrescentado ao grupo `motions` quando termina.

Quando você anexa a um personagem, o Nodaro escolhe o quadro inicial nesta ordem:

1. O `sourceImageUrl` que você envia, que sempre tem prioridade.
2. A entrada `front` de `bodyAngles`. Um quadro de corpo inteiro fica muito melhor animado do que um retrato de cabeça e ombros.
3. Qualquer outra entrada de `bodyAngles`, da mais recente para a mais antiga.
4. O retrato-âncora.

Para obter os melhores clipes, gere um ângulo do corpo `front` antes do primeiro movimento.

**curl**

```bash
curl -X POST https://app.nodaro.ai/v1/generate-character-motion \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
"name": "Kira",
"motionPrompt": "slow head turn left, soft smile",
"provider": "kling",
"attachToCharacterId": "3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94",
"attachName": "head turn"
}'
```

**TypeScript SDK**

```ts
await client.characters.generateMotion({
name: 'Kira',
motionPrompt: 'slow head turn left, soft smile',
provider: 'kling',
attachToCharacterId: id,
attachName: 'head turn',
})
```

**CLI**

```bash
nodaro characters generate-motion <id> \
  --motion-prompt "slow head turn left, soft smile" --attach-name "head turn" --watch
```

| Campo | O que faz |
| --- | --- |
| `name` | Obrigatório. O nome do personagem. |
| `motionPrompt` | Obrigatório. O que se move e como, de 1 a 2.000 caracteres. |
| `provider` | O modelo de vídeo: `kling` (o padrão), `kling-turbo`, `kling-3.0`, `wan-i2v` ou `wan-2.7-i2v`. |
| `sourceImageUrl` | O quadro inicial. Obrigatório quando você não anexa a um personagem. |
| `description`, `motionDescription` | Uma descrição visual (até 1.000 caracteres) e uma descrição do movimento (até 500). O Nodaro rascunha as duas quando você anexa e as omite. |
| `aspectRatio` | `1:1`, `3:4`, `16:9` ou `9:16`. O padrão é `9:16`, um clipe vertical de corpo inteiro. |
| `attachToCharacterId`, `attachName` | O personagem e o nome do clipe em `motions`. |

Estes modelos podem animar um personagem. O preço é o preço de imagem para vídeo do modelo:

| Model | Maker | Modes | Credits | Details |
| --- | --- | --- | --- | --- |
| [Kling 2.6](https://nodaro.ai/docs/models/video/kling-2-6) | Kuaishou | Image to video, Text to video | a partir de 152 | Kling 2.6 I2V — strong motion realism. 5s/10s, optional native audio. |
| [Kling 2.5 Turbo Pro](https://nodaro.ai/docs/models/video/kling-2-5-turbo-pro) | Kuaishou | Image to video, Text to video | a partir de 121 | Faster Kling — good quality at lower cost. Supports end frame. |
| [Kling 3.0](https://nodaro.ai/docs/models/video/kling-3-0) | Kuaishou | Image to video, Text to video | a partir de 297 | Premium Kling 3.0 — variable 3-15s duration, native audio, 720P/1080P. |
| [Wan 2.6 I2V](https://nodaro.ai/docs/models/video/wan-2-6-i2v) | Alibaba | Image to video | a partir de 193 | Wan 2.6 image-to-video — 5/10/15s at 720p/1080p. |
| [Wan 2.7 I2V](https://nodaro.ai/docs/models/video/wan-2-7-i2v) | Alibaba | Image to video | 207 | Wan 2.7 image-to-video — 2–15s at 720p/1080p, supports start+end frame. |

## Aprovar um retrato
`POST /v1/characters/:id/approve-portrait` define um candidato concluído como o retrato-âncora. Na mesma chamada, o Nodaro analisa o retrato e escreve `canonicalDescription`, o texto que os prompts seguintes usam para descrever o personagem. Sem essa descrição, um personagem varia muito mais de uma cena para outra.

O candidato precisa ser um job `completed` que pertence a você. Se a escrita da descrição falhar, o retrato continua definido e `canonicalDescription` fica `null`; chame `POST /v1/characters/:id/llm-caption` para tentar de novo. As duas rotas podem ser repetidas com segurança. Aprovar é gratuito. Cada chamada de llm-caption custa 8 créditos, e uma chamada com falha (`502`) é reembolsada.

**curl**

```bash
curl -X POST https://app.nodaro.ai/v1/characters/3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94/approve-portrait \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "candidateJobId": "b7d2f9a1-6c4e-4a8b-9d3f-3e0c2f1b4d6a" }'
```

**TypeScript SDK**

```ts
const { portraitUrl, canonicalDescription } =
await client.characters.approvePortrait(id, jobIds[1])

if (canonicalDescription === null) {
await client.characters.recaption(id)
}
```

**CLI**

```bash
nodaro characters approve-portrait <id> --job <jobId>
nodaro characters recaption <id>
```

```json
{
"portraitUrl": "https://cdn.nodaro.ai/characters/kira-portrait-2.png",
"canonicalDescription": "Kira is a woman in her mid-twenties with shoulder-length auburn hair, green eyes and light freckles..."
}
```

`llm-caption` retorna `{ canonicalDescription }`. A rota responde `400 no_portrait` quando o personagem ainda não tem retrato e `502` quando não foi possível escrever a descrição.

## Arquivar, restaurar e copiar um personagem
- **Arquivar.** `DELETE /v1/characters/:id` arquiva o personagem e retorna `{ success: true, archived: true }`. O personagem sai da lista padrão, mas `GET /v1/characters/:id` continua retornando o personagem, então os workflows que o usam continuam funcionando. No Nodaro Cloud, arquivar também cancela um treinamento em andamento, reembolsa os créditos dele e remove o modelo treinado.
- **Restaurar.** `POST /v1/characters/:id/restore` retorna `{ id, name }`. Quando um personagem ativo já tem o mesmo nome, o Nodaro adiciona o sufixo `(restored)` e retorna o novo nome.
- **Excluir para sempre.** Nenhuma rota da API exclui um personagem permanentemente. Use a visualização de arquivados na biblioteca do editor.
- **Copiar.** `POST /v1/characters/:id/duplicate` retorna `{ id, name }` de um novo personagem com o sufixo `(copy)`. A cópia compartilha as URLs das mídias do original até você gerá-las de novo.
- **Uso.** `GET /v1/characters/:id/usage` retorna `{ workflowCount, workflows: [{ id, name }] }`. Verifique o uso antes de arquivar um personagem.

| Ação | curl | TypeScript SDK | CLI |
| --- | --- | --- | --- |
| Arquivar | `DELETE /v1/characters/:id` | `client.characters.delete(id)` | `nodaro characters delete <id>` |
| Restaurar | `POST /v1/characters/:id/restore` | `client.characters.restore(id)` | `nodaro characters restore <id>` |
| Copiar | `POST /v1/characters/:id/duplicate` | `client.characters.duplicate(id)` | `nodaro characters duplicate <id>` |
| Uso | `GET /v1/characters/:id/usage` | `client.characters.usage(id)` | `nodaro characters usage <id>` |

## Um fluxo completo: criar, gerar, aprovar e adicionar variações
### Criar o personagem
`POST /v1/characters` com `nodeId`, `name` e um `seedPrompt`. Guarde o `id` retornado.

### Gerar candidatos a retrato
`POST /v1/generate-character` com `count: 4` e `attachToCharacterId`. Consulte periodicamente cada job pelo ID até ele estar `completed` ou `failed`.

### Aprovar o seu favorito
`POST /v1/characters/:id/approve-portrait` com o ID do job desse candidato. O retrato e a descrição canônica são definidos.

### Adicionar variações e movimento
Gere um ângulo do corpo `front` e, depois, expressões e poses com `POST /v1/generate-character-asset`, e clipes com `POST /v1/generate-character-motion`.

## Usar o personagem em outras gerações
Depois que as mídias existirem, envie as URLs delas como imagens de referência para o [Gerar imagem](https://nodaro.ai/docs/nodes/image/generate-image) ou o [**Gerar vídeo** (Generate Video)](https://nodaro.ai/docs/nodes/video/generate-video). Por exemplo, leia a entrada `smile` de `expressions` e envie a URL dela como referência com o seu prompt. URLs explícitas são a opção mais simples no código, porque não dependem de como um workflow está conectado. Veja [Executar um único nó](https://nodaro.ai/docs/developers/api/nodes) para os campos da requisição.

Em um workflow, conecte o nó [**Personagem** (Character Asset)](https://nodaro.ai/docs/nodes/assets/character) ao nó de imagem ou de vídeo, ou mencione o personagem no prompt com `@`, por exemplo `@kira:1:smile`. [Papéis de referência](https://nodaro.ai/docs/guides/reference-roles) explica a sintaxe das menções, e [Personagens consistentes](https://nodaro.ai/docs/guides/consistent-characters), o método completo.

## Uso pelo MCP
Os assistentes de IA usam as mesmas rotas por meio destas ferramentas. Arquivar e restaurar não estão disponíveis pelo MCP, de propósito.

| Ferramenta | O que faz |
| --- | --- |
| `list_characters`, `get_character` | Encontra um personagem e lê as URLs das mídias dele. |
| `create_character`, `update_character` | Cria um personagem ou muda os campos de identidade dele. |
| `generate_character` | Gera um retrato (`kind: "main"`) ou uma variação (`kind: "asset"`). |
| `generate_character_motion` | Anima o personagem em um clipe. |
| `approve_portrait`, `recaption_character` | Aprova um retrato ou escreve a descrição dele de novo. |

Veja a [Referência das ferramentas MCP](https://nodaro.ai/docs/mcp/tools).

## Créditos
No Nodaro Cloud, a geração de personagens usa os mesmos preços em créditos dos nós correspondentes.

| Rota | Preço |
| --- | --- |
| `POST /v1/generate-character` | O preço do modelo de imagem vezes `count`, reservado para todos os candidatos antes de o primeiro job começar. |
| `POST /v1/generate-character-asset` | O preço do modelo de imagem, por variação. |
| `POST /v1/generate-character-motion` | O preço de imagem para vídeo do modelo de vídeo, por clipe. |
| `approve-portrait` | Gratuito. |
| `llm-caption` | 8 créditos por chamada. |

A página de cada modelo informa o preço exato. Veja [Créditos](https://nodaro.ai/docs/concepts/credits).

## Erros
Os erros usam o envelope padrão, `{ "error": { "code", "message" } }`. Veja [Erros](https://nodaro.ai/docs/developers/api/errors).

| Status | Código | Significado |
| --- | --- | --- |
| `400` | `validation_error` | Um campo está ausente ou é inválido, um cursor está malformado, ou uma requisição de geração não tem `seedPrompt`, `description` nem `referencePhotos`. |
| `400` | `no_portrait` | `llm-caption` foi chamado antes de o personagem ter um retrato. |
| `401` | `unauthorized` | O token está ausente, é inválido ou foi revogado. |
| `402` | `insufficient_credits` | Só no Nodaro Cloud. A conta não cobre a reserva. |
| `404` | `not_found` | Nenhum personagem ou job com esse ID pertence a você. |
| `409` | `name_taken` | Outro personagem ativo já tem esse nome. |
| `502` | — | Não foi possível escrever a descrição canônica. O retrato não muda. Tente de novo. |

## Frequently asked questions

### Como mantenho o mesmo personagem em todas as gerações pela API?

Crie o personagem, gere um retrato e aprove-o. O Nodaro então escreve uma descrição canônica do personagem. Envie as URLs das mídias do personagem como imagens de referência para o Gerar imagem ou o Gerar vídeo, ou conecte o personagem a um workflow.

### Quantos candidatos a retrato uma requisição pode gerar?

POST /v1/generate-character aceita um count de 1 a 10. Os créditos de todos os candidatos são reservados antes de o primeiro job começar, e uma falha no meio do lote desfaz a reserva inteira.

### DELETE /v1/characters/:id remove um personagem para sempre?

Não. A rota arquiva o personagem, e POST /v1/characters/:id/restore o traz de volta. Só a visualização de arquivados no editor pode excluir um personagem permanentemente.

### Por que canonicalDescription fica null depois que eu aprovo um retrato?

O retrato foi definido, mas a escrita da descrição falhou. Chame POST /v1/characters/:id/llm-caption para tentar de novo. A aprovação e a descrição dela são gratuitas. Cada chamada de llm-caption custa 8 créditos, e uma chamada com falha é reembolsada.

### Quais modelos podem animar um personagem?

Kling 2.6 (o padrão, ID de provedor kling), Kling 2.5 Turbo Pro, Kling 3.0, Wan 2.6 I2V e Wan 2.7 I2V. Cada clipe custa o preço da geração de imagem para vídeo desse modelo.
