Character endpoints
Every /v1/characters and /v1/scenes endpoint — save a character (a name, a description and a turnaround sheet) or a scene (a place and its picture), list, retrieve, update and delete them, download their pictures, and use them in music videos, character swaps and video shots.
A saved character is a person you want to use again: a name, a description (face, hair, build, the clothes they usually wear) and a turnaround sheet — the same person from the front, three-quarter, side and back, over close-ups of their face with six expressions, in one picture — plus, optionally, the photo it was made from and a voice. Pass its id as character_id to music videos and character swaps instead of sending the picture every time.
Saved characters are optional. Every video endpoint still takes the picture and the text inline, so a one-off call needs no saved character at all.
The endpoints live under https://lovelyrouter.com/v1/characters. Authenticate with your API key as Authorization: Bearer $LOVELY_API_KEY (Authentication). Characters are free to keep, private to your account, and kept until you delete them; an account can keep up to 100.
The character object#
Attributes
idstringUnique id, chr_ followed by 24 characters.
objectstringAlways character.
namestringWhat you call the character, up to 80 characters.
descriptionstringWho the person is, as you wrote it: face, hair, body and default outfit. Up to 4,000 characters; may be empty.
sheet_urlstringThe turnaround sheet. See Download the pictures. The v query value changes when you replace the sheet.
photo_urlstring | nullThe source photo, when you saved one.
voiceobject | nullThe character's voice in video shots: id (a saved voice), description (how it was designed, or null) and audio_url (the sample). null when the character has no voice. See Give a character a voice.
created_atintegerUnix seconds.
updated_atintegerUnix seconds of the last change.
{
"id": "chr_3b9e1f0c7a2d4e58b6c1a9f2",
"object": "character",
"name": "Mara",
"description": "A woman in her thirties with a long black braid, brown eyes, freckles and an athletic build; a green bomber jacket over a grey hoodie, black cargo trousers and white sneakers.",
"sheet_url": "https://lovelyrouter.com/v1/characters/chr_3b9e1f0c7a2d4e58b6c1a9f2/sheet?v=mh2x7k1c",
"photo_url": null,
"voice": {
"id": "voice_7d2a9c4e1b6f3a8d0c5e2b1f",
"description": "A low, calm alto, unhurried",
"audio_url": "https://lovelyrouter.com/v1/audio/voices/voice_7d2a9c4e1b6f3a8d0c5e2b1f/audio"
},
"created_at": 1792915200,
"updated_at": 1792915200
}Create a character#
/v1/charactersSaves a character and returns 201 with the character object. Send multipart (sheet and photo as files) or JSON (the same as http(s) or data: URLs). To save a sheet you generated with the images API, pass the image job's id as sheet_image_job instead of the file.
Body parameters
namestringRequiredUp to 80 characters.
descriptionstringFace, hair, body and default outfit, up to 4,000 characters. Music videos use it as the character brief when you don't send one.
sheetfile or stringRequiredThe turnaround sheet: PNG, JPEG or WebP up to 10 MB, as a file or an http(s) / data: URL (also sheet_url). Use sheet_image_job instead to take it from an image job.
sheet_image_jobstringAn image job id (img_…) of your account that has succeeded: its first image becomes the sheet. Send either this or sheet.
photofile or stringThe photo the sheet was made from, PNG, JPEG or WebP up to 10 MB (also photo_url, or photo_image_job). Kept for your records; videos use the sheet.
voice_idstringOne of your saved voices (voice_…) to give the character.
voicefile or stringA new voice sample instead: WAV, MP3, OGG/Opus, FLAC, M4A or WebM up to 10 MB, as a file or an http(s) / data: URL. It is saved as one of your voices, named after the character, and linked. Needs consent.
voice_transcriptstringWhat the sample says (up to 1,000 characters) — voices clone better with it.
consentbooleantrue confirms the sample is your voice or you have the speaker's permission to use it. Required with voice.
voice_descriptionstringHow the voice was designed, e.g. the description you gave qwen3-tts (up to 1,000 characters). Kept with the voice for your records.
curl https://lovelyrouter.com/v1/characters \
-H "Authorization: Bearer $LOVELY_API_KEY" \
-F name=Mara \
-F description="A woman in her thirties with a long black braid, brown eyes and freckles; a green bomber jacket" \
-F sheet=@mara-sheet.pngList characters#
/v1/charactersYour characters, newest first.
Query parameters
limitintegerDefault 201–100.
afterstringA character id: list the ones saved before it (the next page).
curl "https://lovelyrouter.com/v1/characters?limit=50" \
-H "Authorization: Bearer $LOVELY_API_KEY"{
"object": "list",
"data": [{ "id": "chr_3b9e1f0c7a2d4e58b6c1a9f2", "object": "character", "name": "Mara" }],
"first_id": "chr_3b9e1f0c7a2d4e58b6c1a9f2",
"last_id": "chr_3b9e1f0c7a2d4e58b6c1a9f2",
"has_more": false
}Retrieve a character#
/v1/characters/{id}Returns the character object; 404 for an id that isn't one of yours.
curl https://lovelyrouter.com/v1/characters/CHARACTER_ID \
-H "Authorization: Bearer $LOVELY_API_KEY"Update a character#
/v1/characters/{id}Changes the fields you send and returns the character object. Takes JSON or multipart, like Create. Videos already made keep the sheet they were made with.
Body parameters
namestringA new name.
descriptionstringA new description (an empty string clears it).
sheetfile or stringA new sheet, or sheet_image_job.
photofileA new photo (or photo_image_job); null removes it.
voice_idstring or nullLink one of your saved voices; null unlinks the voice (the saved voice itself stays).
voicefileA new sample (with voice_transcript and consent, as in Create); null unlinks.
voice_descriptionstring or nullHow the voice was designed. A newly linked voice takes the description you send with it, or none.
curl -X PATCH https://lovelyrouter.com/v1/characters/CHARACTER_ID \
-H "Authorization: Bearer $LOVELY_API_KEY" \
-H "content-type: application/json" \
-d '{"description": "A woman in her thirties with a long black braid, now in a red raincoat"}'Download the pictures#
/v1/characters/{id}/sheetThe sheet image with its own content type; GET /v1/characters/{id}/photo is the photo (404 when there is none). Only your key can read them.
curl https://lovelyrouter.com/v1/characters/CHARACTER_ID/sheet \
-H "Authorization: Bearer $LOVELY_API_KEY" -o sheet.pngDelete a character#
/v1/characters/{id}Deletes the character and its pictures. Videos already made with it are not affected.
curl -X DELETE https://lovelyrouter.com/v1/characters/CHARACTER_ID \
-H "Authorization: Bearer $LOVELY_API_KEY"{ "id": "chr_3b9e1f0c7a2d4e58b6c1a9f2", "object": "character.deleted", "deleted": true }Give a character a voice#
A character can have a voice: one of your saved voices. In a video shot a character with a voice speaks their lines in it — its timbre, pitch and manner, not its words.
- Upload one: send the sample as
voice(withvoice_transcriptandconsent: true) when you create or update the character. It is saved as a voice named after the character. - Design one: make a sample with
qwen3-ttsfrom a description and a line the character would say (instructions= the description,input= the line, novoice), save it withPOST /v1/audio/voices, then link it asvoice_id— with the description asvoice_description.
voice_id: null (or voice: null) unlinks the voice. Deleting a character keeps its voice; deleting the voice unlinks it from every character.
# Link a saved voice to a character.
curl -X PATCH https://lovelyrouter.com/v1/characters/CHARACTER_ID \
-H "Authorization: Bearer $LOVELY_API_KEY" \
-H "content-type: application/json" \
-d '{"voice_id": "voice_7d2a9c4e1b6f3a8d0c5e2b1f", "voice_description": "A low, calm alto, unhurried"}'Saved scenes#
/v1/scenesA saved scene is a place you want to use again in video shots: a name, a description of the place and its picture. Scenes work like characters, under https://lovelyrouter.com/v1/scenes, with the picture called image (a file, an http(s) / data: URL, or image_image_job) and no photo. Up to 100 per account, besides your characters; free.
The scene object: {id: "scn_…", object: "scene", name, description, image_url, created_at, updated_at}.
| Request | What it does |
|---|---|
POST /v1/scenes | name (required, up to 80 characters), description, image (required). Returns 201. |
GET /v1/scenes | Your scenes, newest first (?limit, ?after). |
GET /v1/scenes/{id} | One scene. |
PATCH /v1/scenes/{id} | name, description, image. |
GET /v1/scenes/{id}/image | The picture (your key only). |
DELETE /v1/scenes/{id} | Deletes the scene and its picture. |
curl https://lovelyrouter.com/v1/scenes \
-H "Authorization: Bearer $LOVELY_API_KEY" \
-F name="Night Café" \
-F description="A small café at night, rain on the windows, warm lamps" \
-F image=@cafe.jpgUse a character#
Pass character_id where you would send the picture. The inline fields keep working, so pick per call:
| Endpoint | One-off call (inline) | With a saved character |
|---|---|---|
POST /v1/videos/music | character (text) and/or character_image (file or URL) | character_id: its sheet is the reference picture, its description the character text unless you send one. Not with character_image, and only with mode: "image". |
POST /v1/videos | input_reference (file or URL) | character_id: its sheet is the reference picture. Send exactly one of the two. |
POST /v1/videos/shots | characters / scenes: {name, image} objects | characters / scenes: ids; the prompt tags them (@Mara), each tagged one is a reference picture. |
The music video object and the video object show the character_id they were made with (null for inline calls).
# A one-off music video: the picture sent with the call.
curl https://lovelyrouter.com/v1/videos/music \
-H "Authorization: Bearer $LOVELY_API_KEY" \
-F model=ltx-music-video -F song=@song.mp3 -F consent=true \
-F character="A woman with a long black braid" -F character_image=@mara.png
# The same with a saved character.
curl https://lovelyrouter.com/v1/videos/music \
-H "Authorization: Bearer $LOVELY_API_KEY" \
-F model=ltx-music-video -F song=@song.mp3 -F consent=true \
-F character_id=chr_3b9e1f0c7a2d4e58b6c1a9f2Errors#
Errors use the standard error body.
| Status | type | Why |
|---|---|---|
400 | invalid_request_error | A missing name or sheet, a field too long, a picture that isn't PNG, JPEG or WebP or is larger than 10 MB, an image job that isn't yours or hasn't succeeded, or 100 characters already saved. A voice_id that isn't one of your voices, a voice that isn't audio or is larger than 10 MB, or one sent without consent, or 100 voices already saved. |
401 | authentication_error | A missing or invalid API key. |
404 | not_found_error | An unknown or deleted character, or one of another account — also as character_id in a video request. |