A character is the media sibling of an identity: an identity is who an agent is being to the world (an inbox, a number); a character is who it renders as on screen.
POST /v1/characters does not wait: it answers 202 with the character in training, and you read it back until it is ready. An agent does the same with the create_character family of tools; a character made here is one a session can render as, and the other way round.
The character object
string
chr_….string
Always
character.string
How a person and an agent address it, up to 100 characters. Unique among the organization’s live characters, ignoring case.
string | null
Who the character is — looks, age, vibe, wardrobe — up to 1,024 characters. Read by the model when it renders as them.
string
training → ready | failed. ready is the only state a render can pin.string[]
The reference stills it was trained from, as you gave them: a
fil_ id or a public URL. Never the short-lived signed link the trainer was handed.string | null
Reserved for a trained preview. Always
null today: render a still with the character to see it.string | null
Why a
failed training failed; null otherwise.string
organization — your own, trained from your photos — or platform: a prebuilt character every organization can render as, ready with no training. A prebuilt character cannot be deleted.object | null
Who the character is, as up to five lines (
niche, bio, voice, wardrobe, hooks, each up to 500 characters), read by your agents when they write as them. null when none was given.string[]
The looks the character is usually drawn in, by name. A trained character given none gets Phone snap, Realistic and Everyday.
string[]
A prebuilt character’s sample stills, as paths on the dashboard. Empty for your own.
object
Arbitrary key/value pairs. A character you trained carries
consent here: attested, by (the member or API key that confirmed it, or the session whose approved call trained it), at and the statement that was confirmed.string
Creation timestamp.
string
When its status or fields last changed.
Create a character
POST /v1/characters → 202 Accepted — scope agents:write, Idempotency-Key required.
string
required
A short, unique name, such as
Ava. 1–100 characters. A name a live character already holds is validation_failed before anything is trained or billed.string
Who the character is. Up to 1,024 characters. Left out, it is a one-line description of how the person in the photos looks (apparent gender, age, hair), read from the photos when they are checked: every render as the character uses it to keep the person the same.
object
Who they are: any of
niche, bio, voice, wardrobe, hooks, each up to 500 characters.string[]
Up to 12 look names they are usually drawn in. An unknown look is
validation_failed. Omitted or empty, they are Phone snap, Realistic and Everyday.object
required
{ "attested": true } — you confirm: “I confirm the person in these photos is me, or has given me permission to create an AI likeness of them, and is not a public figure.” Anything else is validation_failed before anything is checked, trained or billed. Kept on the character as metadata.consent, with who confirmed it and when. An agent’s create_character always waits for a person to approve the call, whatever its tool policy says: approving it is that person’s confirmation of this statement.string[]
required
One to sixteen reference photos of the same person, each a stored file’s
fil_ id (an upload, or an image a render filed) or a public http(s) URL. More, varied angles train a stronger likeness. A fil_ this organization does not hold is not_found; one that is not an image, a private or loopback host, and a data: or file: URL are validation_failed. The first two photos are checked for a recognizable public figure before anything is billed; if they show one, the request is validation_failed on image_urls with the reason.Idempotency-Key answers the character the first request made — it is not trained or billed twice. Once that character is deleted, a replay of its key is 409 idempotency_conflict; send a new key to train another.
Retrieve a character
GET /v1/characters/{id} → 200 OK — scope agents:read. {id} is the chr_ id or the name; an exact id wins over a name. Poll it after a create: each read advances the status from the trainer, so training turns into ready or failed on the read that sees it. A training takes a few minutes.
List characters
GET /v1/characters → 200 OK, cursor-paginated, newest first — scope agents:read. { data: Character[], has_more, next_cursor }.
Your own characters come first, then the prebuilt ones.
string
training, ready or failed.string
organization for your own only, platform for the prebuilt ones only.number
Page size, 1–100.
string
The
next_cursor of the previous page.Update a character
PATCH /v1/characters/{id} changes who a character is, by chr_ id or name: name, description, persona and style_pack. A persona is merged line by line, so lines you leave out stay. The face can’t change: that’s a new training. A prebuilt character is 409 state_conflict, and a name another character holds is validation_failed.
cURL
Delete a character
DELETE /v1/characters/{id} → 200 OK — scope agents:write. {id} is the chr_ id or the name. A soft delete: the character can no longer be rendered as and its name is free for a new one, while every file it rendered keeps its source.character_id. A prebuilt character (scope: "platform") cannot be deleted: 409 state_conflict.
Response
Rendering as a character
Passcharacter — the chr_ id or name of a ready character — to POST /v1/media/images. The render is routed to a model that pins one, and the same face carries across every image. Add style to draw it in a look.
To keep a scene’s room, props and outfit across shots, pass character together with image_urls naming a still of that character: the render is an edit of that still in a new pose or framing, and it is a still of the character too, so it can be the first frame of the next video.
A character carries into video through the still it renders: generate an image as the character, then pass character and the still’s fil_ id as the image_urls first frame of POST /v1/media/videos. The first frame must be a still rendered as that character, or the request is validation_failed, and only a model that animates a still is used.
ai_generated: true on the post to add it. See AI-generated posts.
Billing
A training costs dollars, not cents, so unlike a render it is admitted first: the organization’s prepaid balance must cover one training, else402 insufficient_credits before anything is bought. It is then billed once, on the media tier, when the trainer accepts the photos — under the character the request’s idempotency key names, so a replay charges nothing. A request refused before training (a taken name, no consent, a public figure, an unreadable photo) is not billed. A training that later ends failed is refunded — credited back to the organization on the read that sees it fail. Reads, lists and deletes are free. See Pricing.
Errors
In a session
create_character, get_character, list_characters and delete_character — the same lifecycle as agent tools.