Library
Assets
The library of everything your organisation has generated or uploaded — list and search it, upload files, organise them into folders, delete them.
Every file the API makes for you — an image, a clip, a skybox, stored speech, a transcript — lands in your organisation’s asset library, and so does every file you upload. Each one is an asset with an ast_… id: the id you pass as a reference image, a video frame, or audio to transcribe.
curl "https://api.lumavox.ai/v1/assets?media_type=image&limit=20" \ -H "Authorization: Bearer $API_KEY"{ "data": [ { "id": "ast_a1B2c3D4e5F6g7H8", "name": "A weathered brass diving helmet", "kind": "output", "media_type": "image", "content_type": "image/jpeg", "size_bytes": 412377, "duration_seconds": null, "width": 1328, "height": 752, "peaks": null, "folder_id": null, "capability": "image", "origin": "api", "thumbnail_url": "https://…", "status": "ready", "error": null, "created_at": "2026-10-24T09:14:21.904Z" } ], "next_cursor": "eyJrIjoiYXNzZXRzOmNyZWF0ZWRfYXQi…"}Scopes
Section titled “Scopes”| Scope | Allows |
|---|---|
assets |
Listing and reading assets and folders, and uploading files. |
assets:write |
Renaming, moving and deleting assets, and creating, changing and deleting folders. |
They are separate on purpose: a key that reads your generations back cannot empty the library. See Authentication.
List and search
Section titled “List and search”GET /v1/assets returns the library newest first, a page at a time.
| Query | What it does |
|---|---|
limit |
Page size, 1–200. Default 50. |
cursor |
The next_cursor from the previous page. |
kind |
input (you uploaded it) or output (a service made it). |
media_type |
image, video, audio or data. |
capability |
The capability that produced it, such as image, video or tts. Uploads have none. |
request_id |
req_… — everything one API call produced. |
search |
Matches anywhere in the name, case-insensitively, up to 120 characters. Taken literally — % and _ are ordinary characters. |
sort |
created_at (default), name, size_bytes or duration_seconds. |
order |
desc (default) or asc. |
The answer is a page: keep passing next_cursor back as cursor, with the same sort, until it comes back null (Conventions). A cursor belongs to the sort it was made with: one from another sort, or one that cannot be read, is a 422 — never the first page again.
Each item carries a thumbnail_url — a short-lived link to a 512-pixel square preview — for images, video and skyboxes. Audio has none; it has peaks instead, a waveform of magnitudes from 0 to 100 for drawing (an empty list for silence, null when never measured). duration_seconds is how long audio or video runs, null for a still.
Read one asset
Section titled “Read one asset”GET /v1/assets/{asset_id} returns everything in the listing plus links to the file itself.
curl https://api.lumavox.ai/v1/assets/ast_a1B2c3D4e5F6g7H8 \ -H "Authorization: Bearer $API_KEY"{ "id": "ast_a1B2c3D4e5F6g7H8", "name": "A weathered brass diving helmet", "kind": "output", "media_type": "image", "content_type": "image/jpeg", "size_bytes": 412377, "duration_seconds": null, "width": 1328, "height": 752, "peaks": null, "folder_id": null, "capability": "image", "origin": "api", "thumbnail_url": "https://…", "status": "ready", "error": null, "created_at": "2026-10-24T09:14:21.904Z", "request_id": "req_k3J9mQ2vX7pL4nRt", "end_user_id": null, "meta": null, "url": "https://…", "url_expires_at": "2026-10-24T09:45:12.000Z", "preview_url": null, "variants": [ { "name": "50", "width": 664, "height": 376, "size_bytes": 118204, "url": "https://…" }, { "name": "25", "width": 332, "height": 188, "size_bytes": 34110, "url": "https://…" }, { "name": "12.5", "width": 166, "height": 94, "size_bytes": 9873, "url": "https://…" } ]}| Field | What it is |
|---|---|
url |
A time-limited link to the file; null when file storage is unavailable. |
url_expires_at |
When url, preview_url and the variants’ links stop working — fifteen minutes after the response. null when there is no url. |
preview_url |
A displayable copy when url is not one. Set for skyboxes, whose url is a Radiance .hdr; null otherwise. |
variants |
Smaller copies of an image — 50, 25 and 12.5 per cent of the original, largest first — each with its own url. Empty for anything that has none. |
request_id |
The req_… of the call that produced it. |
end_user_id |
The end user it was made for, if any. |
meta |
Anything else recorded about it. |
Links are made fresh on every response and never stored. Read the asset again for a new one whenever an old link has expired; the asset itself stays until you delete it.
An id that does not exist and an id that belongs to another organisation are the same 404.
Upload a file
Section titled “Upload a file”Uploads go in three steps, and the bytes never pass through the API: you ask for an upload URL, PUT the file straight to storage, then confirm.
1. Ask where to upload — name the type you are about to send:
curl https://api.lumavox.ai/v1/assets/upload-url \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "content_type": "image/png" }'{ "asset_id": "ast_a1B2c3D4e5F6g7H8", "url": "https://…", "expires_at": "2026-10-24T09:45:00.000Z"}Nothing is created yet. The URL accepts the upload until expires_at, fifteen minutes after you asked; ask for another if it runs out.
2. Upload the bytes to that URL with a PUT, unmodified, with exactly the Content-Type you named — it is signed into the URL — and no Authorization header:
curl -X PUT "$UPLOAD_URL" \ -H "Content-Type: image/png" \ --data-binary @photo.png3. Confirm once the PUT has succeeded:
curl https://api.lumavox.ai/v1/assets/uploaded \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "asset_id": "ast_a1B2c3D4e5F6g7H8", "content_type": "image/png", "filename": "photo.png", "folder_id": "fld_a1B2c3D4e5F6g7H8" }'The answer is a 202 with the asset, status: "pending". The stored file’s type and size are checked, then it is converted in the background. Poll GET /v1/assets/{asset_id} until status is ready — or failed, with the reason in error. A pending asset cannot yet be used as a reference or a frame.
name and folder_id are optional on the confirm. Without a name, the asset is named after filename without its extension.
What you can upload
Section titled “What you can upload”| Kind | Types | Largest |
|---|---|---|
| Images | image/jpeg, image/png, image/webp, image/gif, image/heic, image/heif, image/tiff, image/bmp, image/avif |
limits.uploads.image_bytes |
| Audio | audio/mpeg, audio/mp3, audio/mp4, audio/x-m4a, audio/aac, audio/wav, audio/x-wav, audio/wave, audio/vnd.wave, audio/webm, audio/ogg, audio/opus, audio/flac, audio/x-flac |
limits.uploads.audio_bytes |
The largest file of each kind is the platform’s, listed on Limits with what it is now.
Audio uploads are what transcription reads. An upload that is empty, over the limit, or stored as a different type from the one confirmed is deleted and refused with a 422.
Your organisation can hold a limited number of uploaded files (limits.org.asset_uploads on Limits). At the limit, asking for an upload URL — or confirming one — is a 409 that names the number; delete some uploads to make room.
Upload errors
Section titled “Upload errors”| Status | When |
|---|---|
| 404 | (Confirm) folder_id is not one of your folders. |
| 409 | The PUT has not landed yet, the upload was already confirmed, or your organisation is at its upload limit. |
| 422 | A type that is not accepted, or a stored file that is empty, too large, or not the type confirmed. issues names content_type or asset_id. |
| 503 | File storage is unavailable. |
Rename and move
Section titled “Rename and move”PATCH /v1/assets/{asset_id} needs assets:write. Send name (1–200 characters), folder_id, or both:
curl -X PATCH https://api.lumavox.ai/v1/assets/ast_a1B2c3D4e5F6g7H8 \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Helmet, final", "folder_id": null }'folder_id has three states: leave it out to keep the asset where it is, send null to move it to the root, or send an fld_… id to move it there.
To move many at once, POST /v1/assets/move with up to 500 ids and a folder_id (or null for the root). It answers {"affected": n} — ids that are not yours are skipped and simply not counted.
Delete
Section titled “Delete”DELETE /v1/assets/{asset_id} needs assets:write. The asset leaves the library at once, and its stored bytes — every copy and the thumbnail — are removed shortly after. It answers 204, with no body.
To delete many, POST /v1/assets/delete with up to 500 ids:
curl https://api.lumavox.ai/v1/assets/delete \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "asset_ids": ["ast_a1B2c3D4e5F6g7H8", "ast_Z9y8X7w6V5u4T3s2"] }'It answers {"affected": n}: how many were deleted. Ids that are not yours, or already deleted, are skipped.
Folders
Section titled “Folders”Folders organise the library into a tree. Image, video, skybox, stored-audio and template requests take a folder_id to file their result straight into one.
| Call | Scope | What it does |
|---|---|---|
GET /v1/asset-folders |
assets |
One level of the tree, alphabetically: the top level, or the children of parent_id. Each folder has asset_count and folder_count. |
GET /v1/asset-folders/{folder_id} |
assets |
One folder, with its ancestors from the top down — a breadcrumb trail. |
POST /v1/asset-folders |
assets:write |
Create a folder: name (1–120 characters) and an optional parent_id. Answers 201. |
PATCH /v1/asset-folders/{folder_id} |
assets:write |
Rename it, or move it: parent_id left out keeps it, null moves it to the top level. |
DELETE /v1/asset-folders/{folder_id} |
assets:write |
Remove the folder. Its contents move up to its parent — nothing else is deleted. Answers how many moved: {"moved_assets": 12, "moved_folders": 1}. |
curl https://api.lumavox.ai/v1/asset-folders \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Campaign — spring" }'{ "id": "fld_a1B2c3D4e5F6g7H8", "name": "Campaign — spring", "parent_id": null, "created_at": "2026-10-24T09:50:00.000Z", "asset_count": null, "folder_count": null}asset_count and folder_count are counted only when you read folders; a create or an edit answers them null.
The rules of the tree:
- Two folders side by side cannot share a name (409).
- Folders nest at most 40 deep, and one level holds at most 500 folders — so a level’s listing is always one page, with
next_cursornull. - A folder cannot be moved inside itself.
See also
Section titled “See also”- Generations — the requests behind the outputs.
- Images and Video — using assets as references and frames.
- The assets reference — every field.