---
title: "Update an avatar"
method: PATCH
path: "/v1/avatars/{avatarId}"
tags: ["Avatars"]
---

# Update an avatar

`PATCH /v1/avatars/{avatarId}`

## Request

- Base URL: `https://realtimeavatar.ai/api`
- URL: `https://realtimeavatar.ai/api/v1/avatars/{avatarId}`
- Auth: HTTP bearer

Requires an API key with the `avatars:write` scope.

## Path parameters

- `avatarId` string, required

## Request body

- UpdateAvatarRequest
  - `displayName` string
  - `defaultVoiceId` string, nullable
  - `llm` object, nullable
    - `provider` 'local' | 'gemini' | 'openai', required
    - `model` string, nullable
  - `llmProvider` 'local' | 'gemini' | 'openai'
  - `llmModel` string, nullable
  - `settings` object
  - `metadata` object
  - `persona` object
    - `name` string
    - `personality` string
    - `background` string
    - `replyStyle` string
  - `artDirection` string
  - `stylePreset` 'cinematic-founder' | 'editorial-companion' | 'warm-anime' | 'luxury-realism' | 'soft-3d' | 'noir-avatar'
  - `portraitUrl` string, uri: Dashboard-only. `updateAvatar` needs a request/env context to pull the image into tenant storage, and the public route does not supply one, so sending this here is always `400 Portrait updates are not available on this route`. To change the portrait over this API, register the image with `POST /v1/assets` or `POST /v1/assets/remote` and PATCH the returned id as `sourceAssetId`, which is the swap lane and does work.
  - `sourceAssetId` string
  - `anchorTimeMs` integer
  - `sourceReview` object
    - `reason` string, required

## Response `200`

Updated

- Avatar
  - `id` string, required
  - `tenantId` string, required
  - `displayName` string, required
  - `sourceKind` 'image' | 'video', required
  - `modelId` 'realtime-avatar-live-v1' | 'realtime-avatar-video-v1', required
  - `sourceAssetId` string, nullable, required
  - `status` 'draft' | 'preprocessing' | 'ready' | 'failed' | 'disabled' | 'deleted', required
  - `error` string, nullable, required
  - `idleVideoStatus` 'none' | 'queued' | 'generating' | 'ready' | 'failed', required
  - `defaultVoiceId` string, nullable, required
  - `llm` object, nullable, required
    - `provider` 'local' | 'gemini' | 'openai', required
    - `model` string, nullable
  - `createdAt` string, required
  - `updatedAt` string, required

## Other responses

- `401`: Missing, malformed, revoked, or expired key.
- `403`: The key lacks the scope for this operation, or the tenant is not active.
- `default`: Error. Route-dependent: 400 (a field this route cannot honour — see `portraitUrl` on `UpdateAvatarRequest`), 402 (insufficient credits or spend limit), 404 (no such avatar, voice, or key for this tenant — the message often reads "does not belong to this tenant", which is a missing id and not a permission failure), 408 (the request was cancelled), 409 (the resource is not in a state that accepts this write — a stale `expectedRevision`, a render already in flight, or a mint that asked for a clip library still building), 411 (`POST /v1/assets/remote` only — the origin serving `remoteUrl` sent no `content-length`, so the platform will not stream it), 422 (strict schema rejection, or a motion description the safety screen refused), 429 (rate limited), 502 (upstream render failed), 503 (a dependency this route needs is unavailable — retryable, and nothing was written), 504 (the upstream request budget expired), 500 (unhandled). Switch on `code` where present, else `status`.

---

[API](https://skmtc.dev/realtimeavatar/apis/realtime-avatar-api.md) · [All operations](https://skmtc.dev/realtimeavatar/apis/realtime-avatar-api/llms.txt) · [OpenAPI document](https://skmtc.dev/realtimeavatar/apis/realtime-avatar-api/revisions/e9e3e998e673?raw)
