Zum Inhalt
Lumean API

Files, links and storage

Why result.files[] can't be downloaded, where the subtitles are, and how to tell a live path from a dead one.

Übersetzung in Arbeit

Diese Seite ist noch nicht in Ihre Sprache übersetzt — die Fassung unten ist auf English. Text und Codebeispiele sind dieselben.

A finished order returns its result in result.files[]. These are paths inside storage, not URLs: a GET on such a string returns nothing. Downloading always takes two steps: exchange the path for a temporary link, then download from the link.

POST /storage/url takes the full path, exactly as it appears in the order, and returns data.url — a signed temporary link. It's the only public API operation that requires the orders.download scope: with a key that has orders.read + orders.write, the order is visible but the file won't download — 403 with no reason at all.

FieldRuleDefaultPurpose
pathrequired, string—A string from result.files[] or result.service_files[]
downloadbooleanfalsetrue — the link is marked as an attachment: the file is saved under the order name (Order.name) instead of opening in a tab
number_baseinteger 0 or 11The number that chunk numbering in the file name starts from
number_paddinginteger 1..43Chunk number width, padded with leading zeros (3 → “007”)

The link lives for a limited time (per the spec, about an hour) and is downloaded with a plain GET without the X-API-KEY header: the signature is already inside the URL. Don't store it in a database or hand it out for long — request it right before downloading. If it has expired, repeat POST /storage/url for the same path; the file itself isn't affected.

Two file containers, not one

Subtitles and alignment are not in files[]. An order has two independent flat arrays of path strings:

FieldWhat's inside
result.files[]The main result. For TTS after merging — exactly one element (the final track); for music — one file per each of the n_variants
result.service_files[].srt / .vtt / .lrc subtitles, alignment, result.json with word-level timings

Stolperfalle

service_files are generated only by TTS services, and the field is present only when the set is non-empty: for sfx and music it doesn't exist at all — not null and not [], but a missing key, so you have to check whether the key is present. And it exists only at the order level: GET /orders/{order}/items/{item} returns only the chunk's own result_file. Anyone looking for subtitles in files[] or in a chunk will never find them.

An element has no separate type field — the type is told apart by the extension and by the /service/ segment in the string itself. raw_chunk and metadata paths aren't visible to an API key consumer; an attempt to exchange such a path gives 403.

Recipe: download everything there is

The whole pipeline:

Die Pipeline der öffentlichen APIAcht Schritte vom Schlüssel bis zum Link auf die fertige Datei: Schlüssel, Rechte, Stimme, Vorlage, Auftrag, Abschnitte, Dateien, Link.1. SchlüsselX-API-KEY2. Rechteorders.write3. StimmeGET /voices4. VorlagePOST /templates5. AuftragPOST /orders6. AbschnitteGET /orders/{order}7. Dateienresult.files[]8. LinkPOST /storage/url
# 1. The order: the paths are in result, and the status must be terminal
curl -s "$BASE/orders/$ORDER_ID" -H "X-API-KEY: $KEY"

# 2. Every path from files[] AND from service_files[] is exchanged for a link
curl -s -X POST "$BASE/storage/url" -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
  -d '{ "path": "storage/501/orders/<ORDER_UUID>/output/final/result.mp3", "download": true }'
# → { "success": true, "data": { "url": "https://s3.lumean.app/…?X-Amz-Signature=…" } }

# 3. Download from data.url with a plain GET, without X-API-KEY
curl -sL -o result.mp3 "$URL"

You can also collect files from a partially_completed order: the successful chunks are already finished. A failed order (failed, compensated) has result equal to null — there's nothing to download, and there are no error details on the public surface either.

Retention: two levels and two deadlines

Order files are deleted by retention — by default 7 days after the transition to a terminal status (completed, result_delivered, failed, compensated, cancelled). There are two storage levels, and the per-chunk tracks disappear earlier than the finished result:

FieldMeaning
files_expire_at / retention.files.expires_atWhen all of the order's files will disappear. null — the order isn't terminal yet or the files have already been deleted
files_expired / retention.files.expiredtrue — the files are gone, and a link can't be obtained
retention.chunks.expires_at / .expiredThe deadline for the per-chunk tracks: while they're alive, pause editing, reassembly and chunk regeneration are available
retention.chunks.expires_earlytrue — the chunks will disappear before the result (the order has been merged into a separate file)
retention.chunks.reasonchunks_purged (no chunks, the result is in place), storage_expired (nothing left), null (everything is available)

Vorsicht

The main trap: after retention expires, GET /orders/{order} still shows the old paths in result.files[]. The presence of a path proves nothing — check files_expired (or retention.files.expired), and ultimately the result of the link exchange. A dead path differs from a live one only by the 404 code from POST /storage/url.

404storage_expiredstorage_expired — files deleted by retention
Was passiert ist
`POST /storage/url` for a path from `result.files[]` returns 404 `{"success": false, "message": "File not found."}`. Under the same name, the code also appears as a field in the chunk preview response — next to the `chunks_purged` value, which means only the fragments were deleted and the result is still there.
Was jetzt zu tun ist
The main trap: after retention expires, `GET /orders/{order}` STILL shows the old paths in `result.files[]`. The user-facing response has no separate expiry flag — a "dead" path can be told apart from a live one only by the 404 when you request a link. The files cannot be restored: they no longer exist. The right habit is to download the result as soon as the order is `completed`, without delay; subtitles are stored separately, in `result.service_files[]`, and are deleted along with everything else.
Code-Seite öffnen

Deleted files can't be restored: the order record stays in the database, but the files themselves no longer exist. The only way to get the result again is POST /orders/{order}/retry, which creates a new order with the same parameters and is billed again.

Richtig

Download the result right at completed — both files[] and service_files[] — and before downloading an old order, check files_expired.

Falsch

Store paths or issued links as permanent addresses: a link goes stale within an hour, a path within a week, and both remain in the response after they're dead.

Diese Seite einer KI geben

.md öffnenllm.md

Aktualisiert 04.09.2026 · Spezifikation 0.0.1