Agents API
Generate avatar agents, poll their status, retrieve and update them, then make them speak or inject knowledge into live sessions.
The agent lifecycle
From “I have a face and voice” to “live talking avatar”:
Generate → Poll until ready → Resolve by code → Live session → Speak
This page covers the full REST lifecycle. For the in-process SDK flow, see the Python SDK and agent lifecycle concepts.
Validate your key
POST /v1/validate — verify your API secret before making other calls. Costs no
credits.
curl -X POST https://api.bithuman.ai/v1/validate \
-H "api-secret: $BITHUMAN_API_SECRET"
{ "valid": true }
Generate an agent
POST /v1/agent/generate — create a new avatar agent. Generation is
asynchronous and billed per model — expression-2 costs 2000 credits,
the Essence 2 family (essence-2, essence-2-max) 500, the v1 families
(essence-1, expression-1) 250, and auto bills the routed model’s rate
(machine-readable schedule: GET /v1/pricing).
The call returns immediately with an agent_id and processing status.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
prompt | string | no | random | System prompt / personality for the agent. |
image | string | no | — | Image URL or base64 data for appearance. A supplied image is treated as a reference and always regenerated via Seedream 5 edit to standardize it (never used raw); omit it and a portrait is generated from the prompt with Seedream 5 pro. |
audio | string | no | — | Audio URL or base64 data for voice cloning. |
aspect_ratio | string | no | 16:9 | Aspect ratio for the generated identity image and driver video — 16:9 landscape (default), 9:16 portrait, 1:1 square. Images are generated at 1080p. |
transparency | boolean | no | false | When true, the identity image is generated on a solid green-screen background for chroma-key / transparent embedding — the character itself never uses green. |
framing | string | no | portrait | portrait (default) frames head-and-shoulders; full_body shows the whole figure including the feet (kiosk / standing-avatar layouts). |
agent_id | string | no | auto | Custom agent identifier. |
duration | number | no | — | Deprecated — omit it. The internally generated identity video is standardizing on 10 seconds; the parameter is ignored as that rollout completes. |
model | string | no | expression | Avatar model family — expression (default) or essence — combined with version to pick the engine: expression+v1 = Expression 1 (the default), essence+v1 = Essence 1, essence+v2 = essence-2 (the combined Essence 2 creation), expression+v2 = expression-2. You may also pass a full engine name directly (essence-1, essence-2, essence-2-max, expression-1, expression-2) or auto (classify-and-route) — those pass through unchanged and version is ignored, so existing integrations keep working. An omitted model defaults to expression at v1 (Expression 1, 250 credits) — a v1 engine at the ungated 250-credit rate; a caller is never silently upgraded onto a v2 engine or a higher price. Invalid values return 400 VALIDATION_ERROR (no credits charged); the retired essence-2-light name returns a targeted hint pointing at essence-2, and the pre-rename essence-2-quality is still accepted as a deprecated alias for essence-2-max during the migration. See models and Essence 2 & Expression 2. |
version | string | no | v1 | Engine generation for the chosen model family — v1 (default) selects the first-generation engine (Essence 1 / Expression 1, 250 credits); v2 selects the second-generation engine (Essence 2, 500 credits, or Expression 2, 2000 credits). Ignored when model is a full engine name or auto. |
Agent creation is image-only. Provide a portrait
image(or let the prompt generate one) — bitHuman generates a 10-second identity video internally (Seedance 1.5 pro, 25 fps), authored to loop seamlessly (its first and last frames match). Video input is not part of the creation contract for any model and is being removed platform-wide: do not sendvideo— as the rollout completes, a request carrying it is rejected with400 VIDEO_INPUT_NOT_SUPPORTEDbefore anything is billed.
Model-specific inputs and creation times
The model you pick changes what creation needs and how long it runs. All
models share the same pipeline prefix — persona, voice, and image are prepared
first (each generated from your prompt when not supplied) — then the
model-specific identity step runs:
model | Identity input | Identity step | Typical creation time |
|---|---|---|---|
essence-1 | image (or generated from prompt); an identity video is generated internally if needed | Builds the portable .imx avatar | 2–5 minutes |
expression-1 (default) | image (or generated from prompt) | None (animates the portrait at runtime) | ~1–2 minutes |
essence-2 | image (or generated from prompt) — a 10-second identity video is generated from it internally (the video step) | Combined: distills the standard Essence 2 identity bundle on a cloud GPU; Max derives from the same identity video | 25–40 minutes typical; occasionally longer (allowed up to several hours) |
essence-2-max | Included with every essence-2 creation — its identity derives from the same internally generated identity video | Instant prep of a compact identity bundle (seconds, warm) | Available once the combined creation is ready |
expression-2 | image (or generated from prompt) | Trains a per-identity model on an H100-class GPU | ~45 minutes (30–60; allowed up to 90) |
auto | image or prompt (classified automatically) | As the routed model — essence-2 or expression-2 | As the routed model |
Set your polling timeout per model — a 5-minute client timeout is fine for
essence-1 but will falsely “fail” every expression-2 and essence-2
creation. Full model behavior (serving tiers, idle, pricing) is in each
model’s guide.
essence-2 — the combined creation
model: "essence-2" creates both Essence 2 models from one creation: a
single 500-credit charge runs the standard Essence 2
distillation, and Essence 2 Max becomes
available at no extra charge from the same internally generated identity
video (its identity prepares on demand from that video). Sessions
launched as essence-2 serve
the standard chain by default; launch with ?model=essence-2-max on
the session/embed URL (or the model field on the
embed token) when you want the premium model (the
pre-rename essence-2-quality slug still works too). Once ready,
the agent’s supported_models lists the two families under their internal
names — essence-2-light (the standard Essence 2) and essence-2-quality
(Essence 2 Max) — until the platform-side flip.
auto — let the platform pick the model
model: "auto" runs an LLM subject classifier over your creation input —
the image if you provided one, else the prompt — and routes it:
- a photorealistic person →
essence-2(the combined creation above); - a cartoon, animal, creature, or robot →
expression-2(the generative engine, which handles any subject and works best for stylized characters).
auto never rejects on subject — it routes instead — and charges the routed
model’s rate (500 credits for essence-2, 2000 for expression-2). It is
the default selection in the dashboard’s
create flow, but API callers must pass it explicitly: an omitted model
defaults to expression-1 (v1, 250 credits) for backward compatibility.
The Essence 2 subject gate (422)
An explicit Essence 2 creation (essence-2, essence-2-max)
requires a photorealistic human subject — the Essence
identity pipelines train on real human faces. The same classifier runs on
your input before anything is billed and before any agent row is created;
a non-human or stylized subject is rejected with
422 MODEL_SUBJECT_MISMATCH:
{
"error": {
"code": "MODEL_SUBJECT_MISMATCH",
"message": "essence-2 requires a photorealistic human subject; this image looks like a cartoon — use expression-2",
"httpStatus": 422
},
"status": "error",
"status_code": 422
}
(With a prompt-only input the message reads “this description sounds like
a …”.) Use expression-2 for those subjects, or model: "auto" to route
automatically. A classifier outage never blocks creation — the gate fails
open.
import requests
resp = requests.post(
"https://api.bithuman.ai/v1/agent/generate",
headers={"Content-Type": "application/json", "api-secret": "YOUR_API_SECRET"},
json={
"prompt": "You are a professional video content creator.",
"image": "https://example.com/avatar.jpg",
"model": "expression-2",
},
)
print(resp.json())
{
"success": true,
"message": "Agent generation started",
"agent_id": "A80HVD8577",
"status": "processing"
}
Note The generation endpoint is
POST /v1/agent/generate. (Older docs referenced/v1/agent-generation— that path is incorrect.)
Poll status
GET /v1/agent/status/{agent_id} — returns the current state of a generation
request. Poll every 5 seconds.
| Status | Description |
|---|---|
processing | Initial state — generation queued. |
generating | Active generation in progress (sub-steps running). |
completed | An intermediate sub-step finished. Not terminal — it can appear early (even around ~5% progress), so do not stop polling on it. |
success | Success — the .imx model is available for use. |
ready | Success — the .imx model is available for use (equivalent to success). |
failed | Failure — check error_message. |
Treat success / ready and failed as terminal. processing, generating,
and completed are intermediate, so keep polling (don’t stop on completed —
it can appear long before the model is done). Drive your loop off progress
reaching 1.0 together with a terminal status. Typical wall-clock is two to
five minutes for essence-1 — the second-generation models train real
per-identity models and take longer (see
model-specific inputs and creation times).
While a run is in flight, current_step reports the pipeline stage:
current_step | Progress | What’s happening |
|---|---|---|
payment | ~2% | Credits reserved (the model’s creation cost — 250, 500, or 2000). |
persona | 5–15% | Persona / system prompt prepared. |
voice_image | ~20% | Voice and portrait generated (in parallel). |
video | ~45% | The 10-second identity video is generated internally (essence-1 and essence-2) — authored to loop seamlessly. |
awaiting_face_marking | ~35% | Waiting on manual face marking (rare essence-1 path). |
lip_sync | 70–99% | The model-specific identity step — .imx build (essence-1), identity prep (essence-2-max), bundle distillation (essence-2), or per-identity training (expression-2). The longest step for the v2 models. |
done | 100% | Terminal — the agent is ready. |
{
"success": true,
"data": {
"agent_id": "A80HVD8577",
"status": "ready",
"progress": 1.0,
"progress_msg": "Complete",
"current_step": "done",
"error_message": null,
"system_prompt": "You are a professional video content creator.",
"image_url": "https://...",
"video_url": "https://...",
"model_url": "https://...",
"supported_models": ["essence-2-quality", "expression-2"],
"name": "agent name"
}
}
| Progress field | Type | Description |
|---|---|---|
progress | float (0.0–1.0) | Generation progress as a fraction. 1.0 is complete. |
progress_msg | string | Human-readable progress description. |
current_step | string | Current generation step (see the table above). |
supported_models | string[] | The canonical model families this agent can be launched as right now. Trained families (expression-2, essence-2-light — the internal family name for the standard essence-2) appear once their per-identity model exists; essence-2-quality (the internal family name for essence-2-max, kept until the platform-side flip) appears when the agent has a stored identity video (generated internally by Essence creations; its identity prepares on demand from that video); essence-1 appears when its .imx exists. Tier slugs inherit their family, and the combined essence-2 creation shows up as its two tier families. Also returned on GET /v1/agent/{code}, GET /v1/agents items, and the embed-token response. |
Generate and poll
import os, time, requests
BASE = "https://api.bithuman.ai"
SECRET = os.environ["BITHUMAN_API_SECRET"]
headers = {"Content-Type": "application/json", "api-secret": SECRET}
resp = requests.post(f"{BASE}/v1/agent/generate", headers=headers,
json={"prompt": "You are a friendly AI assistant."})
agent_id = resp.json()["agent_id"]
while True:
data = requests.get(f"{BASE}/v1/agent/status/{agent_id}",
headers={"api-secret": SECRET}).json()["data"]
# `success` and `ready` both mean done; `completed` is NOT terminal.
if data["status"] in ("ready", "success"):
print("Ready:", data["model_url"])
break
if data["status"] == "failed":
raise SystemExit(f"Failed: {data['error_message']}")
time.sleep(5)
Creation failure modes
Two kinds of failure exist — rejected before start (HTTP error, nothing
charged) and failed during generation (status: "failed", credits
automatically refunded):
| Failure | Surface | Notes |
|---|---|---|
Invalid model value | 400 VALIDATION_ERROR — Invalid model '<x>'; must be one of: auto, essence, essence-1, essence-2, essence-2-max, essence-2-quality, expression, expression-1, expression-2 | Rejected before dispatch; no credits charged. Retired names get a targeted hint instead of the bare list — e.g. essence-2-light → “‘essence-2-light’ was consolidated into ‘essence-2’ (2026-07-05)…”. |
| Malformed body | 400 VALIDATION_ERROR — Request body must be valid JSON / …a JSON object | Rejected before dispatch. |
video in the request body | 400 VIDEO_INPUT_NOT_SUPPORTED — Agent creation is image-only. Provide a portrait image; bitHuman generates a 10-second idle/driver video internally so it loops seamlessly (first frame == last frame). … | The image-only contract is rolling out platform-wide — never send video; requests carrying it are rejected before dispatch (nothing charged) as the rollout completes. Send image instead — the identity video is always generated internally, for every model. |
| A second-generation family paused for your account (rare) | 503 MODEL_NOT_YET_AVAILABLE — <model> isn't available for generation yet. Specify 'essence-1' or 'expression-1' to generate now. | Essence 2 / Expression 2 are GA (since July 10, 2026) — creation is open for all accounts, so this isn’t returned in normal operation. It remains the safety response if a v2 family is ever re-paused; nothing is charged and the v1 families always work. |
| Non-human subject on an explicit Essence 2 creation | 422 MODEL_SUBJECT_MISMATCH — essence-2 requires a photorealistic human subject; this image looks like a <verdict> — use expression-2 | Rejected before billing and before any agent row exists — see the subject gate. auto routes instead of rejecting. |
| Not enough credits | 402 INSUFFICIENT_BALANCE (also surfaces as status: "failed" with a payment error_message if the reserve fails mid-pipeline) | Creation costs the model’s rate — 250 (v1), 500 (Essence 2), or 2000 (expression-2). |
| A pipeline step fails | status: "failed" + error_message naming the step (voice, image, video, or the model step) | Terminal for that agent_id; the creation credits are refunded automatically. Create again after fixing the input. |
essence-2-max on an agent without a stored identity video | 409 MODEL_NOT_GENERATED at launch | Max prepares its identity from the agent’s internally generated identity video — create with (or add) the combined essence-2, which generates it. See Essence 2 Max. |
v2 creation “stuck” at lip_sync | Not a failure | That’s the training/prep step — the longest part for expression-2 / essence-2. Keep polling; see creation times. |
More session-time issues (connect latency, tier pinning, idle behavior): Session behavior & troubleshooting.
Get an agent
GET /v1/agent/{code} — retrieve full details for an agent by its code.
import requests
code = "A80HVD8577"
data = requests.get(
f"https://api.bithuman.ai/v1/agent/{code}",
headers={"api-secret": "YOUR_API_SECRET"},
).json()
agent = data["data"]
print(agent["name"], agent["status"])
{
"success": true,
"data": {
"agent_id": "A80HVD8577",
"status": "ready",
"system_prompt": "You are a friendly AI assistant",
"image_url": "https://storage.bithuman.ai/A80HVD8577/image_20260115_103000_000001.jpg",
"video_url": "https://storage.bithuman.ai/A80HVD8577/video_20260115_103200_000002.mp4",
"model_url": "https://storage.bithuman.ai/A80HVD8577/my_agent_20260115_103500_000003.imx",
"name": "My Agent"
}
}
List your agents
GET /v1/agents — list the agents owned by your API secret, newest first.
Paginated with limit (default 20, max 100) and offset; filter by generation
state with status.
import requests
resp = requests.get(
"https://api.bithuman.ai/v1/agents",
headers={"api-secret": "YOUR_API_SECRET"},
params={"limit": 20, "offset": 0, "status": "ready"},
).json()
for a in resp["data"]:
print(a["code"], a["status"])
print(resp["pagination"]) # {limit, offset, total, has_more}
Page through with offset until pagination.has_more is false.
Delete an agent
DELETE /v1/agent/{code} — permanently delete an agent you own. Stored assets
are cleaned up best-effort; usage history is retained for billing. Deleting a
missing or non-owned agent returns 404.
import requests
requests.delete(
"https://api.bithuman.ai/v1/agent/A80HVD8577",
headers={"api-secret": "YOUR_API_SECRET"},
).json()
# {"success": true, "agent_code": "A80HVD8577", "deleted": true}
Update an agent’s prompt
POST /v1/agent/{code} — update the system prompt of an existing agent without
regenerating it. The agent must already exist. For a new face or voice, generate
a new agent.
import requests
code = "A80HVD8577"
resp = requests.post(
f"https://api.bithuman.ai/v1/agent/{code}",
headers={"Content-Type": "application/json", "api-secret": "YOUR_API_SECRET"},
json={"system_prompt": "You are a professional sales assistant."},
)
print(resp.json())
{ "agent_code": "A80HVD8577", "updated": true }
Add a model to an existing agent
POST /v1/agent/{code}/models — add an avatar model to an agent you already
created, without re-creating it or regenerating its persona/voice/image. The
agent must be in the ready state (else
409 AGENT_NOT_READY).
Body: {"model": "<name>"} — one of essence-1, essence-2,
expression-1, expression-2 (anything else returns 400 VALIDATION_ERROR
listing the options; the Essence 2 tiers are not individually addable —
essence-2 is the one combined add).
model | What happens | Prerequisites | Credits | Time |
|---|---|---|---|---|
expression-1 | Instant enablement — the v1 foundation model drives the agent’s existing image + voice at runtime; nothing is trained | stored image and voice (else 422) | 0 | immediate (this response) |
expression-2 | Trains the per-identity Expression 2 model from the stored image | stored image (else 422) | 2000 | ~10–45 min |
essence-2 | The combined add: trains the standard Essence 2 from the agent’s stored identity video (generated internally at creation); Max lights up from the same video at no extra charge | stored identity video (else 422 MODEL_PREREQUISITE_MISSING) + photorealistic-human subject on the stored image (else 422 MODEL_SUBJECT_MISMATCH) | 500 | 45 min–3 h |
essence-1 | Builds the v1 .imx — reuses the stored identity video, or generates one internally from the stored image | stored identity video or image (else 422) | 250 | ~10–20 min |
import requests
resp = requests.post(
"https://api.bithuman.ai/v1/agent/A66GYD8664/models",
headers={"Content-Type": "application/json", "api-secret": "YOUR_API_SECRET"},
json={"model": "expression-2"},
)
print(resp.json())
An async add (everything except expression-1) responds immediately:
{
"success": true,
"agent_id": "A66GYD8664",
"model": "expression-2",
"status": "processing",
"credits": 2000,
"supported_models": ["essence-1", "essence-2-quality"],
"message": "expression-2 model add started (typically 10-45 minutes). 2000 credits are charged (refunded automatically if the add fails). Poll GET /v1/agent/status/A66GYD8664 until supported_models includes expression-2."
}
Poll GET /v1/agent/status/{code} until supported_models
contains the new family (essence-2 adds both internal family names,
essence-2-light and essence-2-quality). The agent keeps serving as-is while the add runs —
status stays ready for the v2 adds. An instant add (expression-1,
or a model the agent already has) returns status: "ready" with
credits: 0 in the same response — re-POSTing the same model never
double-charges, and a failed add refunds automatically.
Failure shapes: 400 VALIDATION_ERROR · 404 NOT_FOUND (unknown or
not-owned agent) · 409 AGENT_NOT_READY ·
422 MODEL_PREREQUISITE_MISSING / 422 MODEL_SUBJECT_MISMATCH ·
503 MODEL_NOT_YET_AVAILABLE (only if a v2 family
is paused — not returned in normal operation since the July 10, 2026 GA; nothing charged).
Download an agent’s model
GET /v1/agent/{code}/model/download — download the generated model artifact
for an agent you own. The family defaults to the agent’s own model; override
with ?model=<family> (public names, deprecated aliases and runtime tier
slugs fold onto their family — essence-2 and the essence-2-{gpu,ane,cpu}
force slugs fold onto essence-2-light, and essence-2-max folds onto
essence-2-quality, the families’ internal names). What you get per family:
| Family | Artifact | Notes |
|---|---|---|
essence-1 | <code>.imx | The portable IMX container — runs locally in the CLI and the Python SDK. |
essence-2-light | <code>.lebundle.imx | The standard Essence 2 artifact — unified IMX container, ~350–550 MB. Licensed weights — a local runtime must complete the license activation flow; today the model serves via bitHuman cloud. |
essence-2-quality | <code>.pkl | The Essence 2 Max artifact — IMX container; renders on bitHuman’s GPU cloud (not a local-playback artifact). |
expression-2 | <code>.avatar | CoreML zip (~20–90 MB per identity) — the Apple/CoreML build of the trained model (served on bitHuman’s cloud today; local .avatar playback is in development). |
expression-1 | — | Not downloadable: no per-identity artifact exists (the v1 foundation model renders server-side from the agent’s image) → 400 MODEL_NOT_DOWNLOADABLE. |
The default response is a 302 redirect to the artifact (public URL for
essence-1, 1-hour signed URL for the private families), so a plain
curl works:
curl -LOJ -H "api-secret: $BITHUMAN_API_SECRET" \
"https://api.bithuman.ai/v1/agent/A17ZTB0222/model/download?model=expression-2"
# → A17ZTB0222.avatar
Pass ?redirect=false to get the URL as JSON instead (for UIs that want to
fetch or label first):
{
"success": true,
"data": {
"code": "A17ZTB0222",
"model": "expression-2",
"filename": "A17ZTB0222.avatar",
"url": "https://…signed…",
"expires_in": 3600
}
}
(expires_in is null for the public essence-1 URL.)
Errors (full reference):
| Status | Code | When |
|---|---|---|
400 | VALIDATION_ERROR | Unknown model value — the message lists the downloadable families. |
400 | MODEL_NOT_DOWNLOADABLE | The family has no per-identity artifact (expression-1). Not retryable. |
404 | NOT_FOUND | Agent unknown or not owned by this account. |
404 | MODEL_ARTIFACT_NOT_READY | The family is supported but its artifact hasn’t been published to the download store yet — the message says when to retry. Poll on this code. |
409 | MODEL_NOT_GENERATED | The requested family isn’t in the agent’s supported_models (same gate as embed/session launch). |
429 | RATE_LIMITED | Read-bucket rate limit. |
Tip The bitHuman CLI wraps this endpoint:
bithuman pull A17ZTB0222downloads the artifact, recognizes its model family, and prints what to do next — anessence-1.imxruns locally withbithuman run.
Make an agent speak
POST /v1/agent/{agent_code}/speak — trigger the agent to speak a message to
users in an active session.
| Parameter | Type | Required | Description |
|---|---|---|---|
message | string | yes | Text the agent will speak. |
room_id | string | no | Target a specific room. If omitted, delivers to all active rooms. |
curl -X POST https://api.bithuman.ai/v1/agent/A12345678/speak \
-H "Content-Type: application/json" \
-H "api-secret: $BITHUMAN_API_SECRET" \
-d '{
"message": "We have a 20% discount available today.",
"room_id": "customer_session_1"
}'
{
"agent_code": "A12345678",
"context_type": "speak",
"delivered_to_rooms": 1
}
Inject knowledge
POST /v1/agent/{agent_code}/add-context — add background knowledge the agent
uses to inform future responses. Set type to speak to trigger speech
instead.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
context | string | yes | — | Knowledge to inject (or message to speak). |
type | string | no | add_context | add_context injects knowledge silently; speak triggers a verbal response. |
room_id | string | no | — | Target a specific room. If omitted, delivers to all active rooms. |
import requests
requests.post(
"https://api.bithuman.ai/v1/agent/A12345678/add-context",
headers={"Content-Type": "application/json", "api-secret": "YOUR_API_SECRET"},
json={
"context": "Customer has VIP status. Preferred name: Alex. Account since 2021.",
"type": "add_context",
"room_id": "vip_session_42",
},
)
Note
/speakand/add-contexttarget agents created on the bitHuman platform that have an active session — not local SDK agents. Without a live room you’ll get404 NOT_FOUND. Start a session via the embed flow or a LiveKit worker first.
Error codes
| HTTP | Code | When |
|---|---|---|
401 | UNAUTHORIZED | Invalid or missing api-secret. |
402 | INSUFFICIENT_BALANCE | Not enough credits (generation costs 250 for the v1 models, 500 for Essence 2, 2000 for expression-2). |
404 | NOT_FOUND | No agent with the given code (message: "Agent not found for code: <code>"). |
404 | NOT_FOUND | Agent has no active session to /speak or /add-context (message: "No active rooms found for agent <code>"). |
400 | VALIDATION_ERROR | Invalid request body (e.g. bad type value, or an invalid / retired model name — the error message lists the accepted values). |
400 | VIDEO_INPUT_NOT_SUPPORTED | Agent creation with a video input. Creation is image-only — provide a portrait image; the 10-second identity video is generated internally so it loops seamlessly (first frame == last frame). Rejection is rolling out platform-wide (nothing charged) — never send video. |
503 | MODEL_NOT_YET_AVAILABLE | A second-generation family paused for your account. Essence 2 / Expression 2 are GA (since July 10, 2026) and open for all accounts, so creation and model add don’t return this in normal operation — it’s the safety response if a v2 family is ever re-paused. Nothing charged; the v1 families always work. |
409 | MODEL_NOT_GENERATED | A launch surface (embed-token model, talking video, model download) requested a family the agent can’t be launched as — it’s missing from supported_models. Trained families: "agent <code>'s <model> model hasn't been generated yet"; essence-2-max is gated on the stored identity video it prepares from (generated internally by Essence creations — the message keeps the internal essence-2-quality family name until the platform-side flip). Add the model or create the agent with it. |
409 | AGENT_NOT_READY | POST /v1/agent/{code}/models on an agent that is still generating or failed — models can only be added to a ready agent. |
422 | MODEL_SUBJECT_MISMATCH | An explicit Essence 2 creation or add whose input isn’t a photorealistic human subject — see the subject gate. Nothing is billed. |
422 | MODEL_PREREQUISITE_MISSING | Model add on an agent missing a stored asset the model needs (a stored identity video for essence-2 — generated internally by Essence creations, never uploaded; image for expression-2; image + voice for expression-1). |
400 | MODEL_NOT_DOWNLOADABLE | Model download for a family with no per-identity artifact (expression-1). |
404 | MODEL_ARTIFACT_NOT_READY | Model download for a supported family whose artifact hasn’t been published yet — retryable; the message says when. |
See the full error reference and the interactive API reference.