Input files

Anything placed in a project’s input/ folder is an input file, however it got there: an API upload, the AWS CLI, or an SDK. The processing service takes every file it finds, including files in subfolders. In a project that reads a feed, the input files are the feed items’ media, downloaded by the project itself and named from each item (4f1c2b9a7d3e.8a2b4c6d.mp4); everything on this page applies to them as to uploaded files. GET /projects/{id}/files lists them in name order, each with what it will produce:
meta counts every file by state. The same counts are kept on the project as files (Projects), refreshed by this call, by every change made through the API and once a minute otherwise, so a list of projects can be polled instead of each project’s files. meta counts every file by state. ?status=failed (or several states, comma-separated) keeps only those files in data, and GET /projects/{id}/files/{name} answers one file.
string
The file’s path under input/. A file in a subfolder is season 2/episode 01.mp4.
"pending" | "processing" | "done" | "failed"
See States.
object[]
Every output the project’s config produces for this file, one per item of every destination: its path under output/, whether it is available yet, and its size once it is. The files of an output feed are under feeds/<language>/ (feeds/es/4f1c2b9a7d3e.8a2b4c6d.mp4).
string | null
Set when status is failed.
string | null
Set when status is failed: why, when it is something you can fix. no_audio (the file has no audio track), not_media (not media, or truncated), voice_not_found (the config names a voice the engine does not have), interrupted (processing was stopped before it finished; retry), or internal (ours). See When a file failed.
boolean
true when the input was replaced after it was processed, by copying a new file over it with the AWS CLI. The file reads pending, its outputs are still the old content’s, and nothing happens until you retry it.
object[] | null
What a done file was billed for (Billing): one entry for its captions in the transcription language, then a translation for each target language and a dubbing for each dubbed one. Each entry has its kind, its language, and durationMs, the file’s length that it is billed by. The file’s billed minutes are the sum of the entries’ durations.A retried file keeps the entries its content was first billed for, because a retry bills nothing new; replaced content is billed again and has its own entries. usage is null while the file is not done, and for up to a minute after it finishes, until it is recorded. durationMs is null while processing has not reported the file’s length; the entry is billed once it has.
string | null
An identifier of the processing run. Quote it when you contact support about a file.

States

A file whose input was replaced after it was processed is pending with stale: true until you retry it (Replace). A file stays pending while its project is stopped. A project that stopped itself after its last file starts again within a minute of a new file, however it was uploaded. Completing an API upload also starts one stopped with POST …/stop; neither happens while the project’s startOnNewFiles is off. Retrying a file starts a stopped project that ran before either way. Both answer the project’s state in projectStatus; a project created with autoStart: false that never ran, or one in error, is left as it is. See Starting again on a new file. The processing service processes several files at a time, and takes the next file from the folder as soon as one finishes, so a file uploaded while others are being processed starts as soon as there is room for it. A file that is being processed when its project stops (a stop, a change of config or buildVersion, a restart) is left pending and processed again from the start when the project next runs.

Subfolders

Subfolders of input/ are kept in output/: with a nameTemplate of ${name}.es.${ext}, input/season 2/episode 01.mp4 writes output/season 2/episode 01.es.mp4. In a URL, a file’s name is one path segment, so encode its slashes along with everything else: season%202%2Fepisode%2001.mp4. Every page that takes a {name} points here. Generated clients do this for you (Generate a client); by hand:

Output names must not collide

Outputs are named from the input without its extension, so trailer.mov and trailer.mkv would both write trailer.es.mp4, and the second would overwrite the first. An API upload refuses such a name with 422 (errors.name). A file copied in with the AWS CLI is not checked, so give inputs distinct base names. A name must not contain ${: output names are made by putting the input’s name into ${name}, and a ${ left over fails the file. An API upload refuses such a name.

Retry

202
The file is processed again from the start the next time the service scans the folder, with the project’s current config. Retrying works on done files too, for example after changing the config. A retried file is not billed again unless its content changed. A project that ran and has stopped since is started again. projectStatus says what the project is doing now: stopped if it never ran (start it once every file is uploaded), error if its last start failed.

Replace

Upload a file under the same name to replace a done one:
  • Through the API, set overwrite: true on the upload (without it, a same-name upload answers 409). The new file is processed from scratch. While the project is running, a file that is neither done nor failed may be mid-run, and replacing it answers 409 (file_processing).
  • With the AWS CLI, copy the new file over the old one, then retry it. Until the retry, the file reads pending with stale: true, and is not processed again.
New content is billed as a new file.
Replace a failed file under a new name, and delete the failed one. For now the processing service keeps its own copy of a failed input, found by the file’s name, and processes that copy again when the name comes back: overwrite: true, copying over it, or deleting it and uploading it again would all fail the same way on the old bytes.

Download

The download calls answer a presigned S3 URL, valid for up to an hour. expiresAt is when it stops working, which can be sooner than an hour; fetch a new one after that, rather than storing it:
Fetch it with any HTTP client, without the Authorization header. A browser saves the file under its own name instead of playing it. With an upload role, aws s3 sync <outputPath> ./results fetches everything at once.

Delete

DELETE /projects/{id}/files/{name} deletes an input file and its processing records. Its outputs are kept; they stay listed by GET …/outputs. While the project is running, a file that is neither done nor failed may be in the middle of its run, which would finish and record the deleted file as done. Such a delete answers 409 (file_processing): wait for the file, or stop the project, then delete it.

Metadata

GET /projects/{id}/files/{name}/meta returns what the processing service recorded about the file’s latest run, filled in as it goes: hash and startedAt when it starts, durationMs once the media is read, dubbingMs after transcription, translation and dubbing, finishedAt when the outputs are written.
It answers 404 (file_meta_not_found) until the run starts. A run before 2026-10-09 may carry other fields.